mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 03:15:43 +08:00
Sequence effect with example
This commit is contained in:
70
doc/examples/effects/sequence_effect/.gitignore
vendored
Normal file
70
doc/examples/effects/sequence_effect/.gitignore
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Visual Studio Code related
|
||||
.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
|
||||
# Android related
|
||||
**/android/**/gradle-wrapper.jar
|
||||
**/android/.gradle
|
||||
**/android/captures/
|
||||
**/android/gradlew
|
||||
**/android/gradlew.bat
|
||||
**/android/local.properties
|
||||
**/android/**/GeneratedPluginRegistrant.java
|
||||
|
||||
# iOS/XCode related
|
||||
**/ios/**/*.mode1v3
|
||||
**/ios/**/*.mode2v3
|
||||
**/ios/**/*.moved-aside
|
||||
**/ios/**/*.pbxuser
|
||||
**/ios/**/*.perspectivev3
|
||||
**/ios/**/*sync/
|
||||
**/ios/**/.sconsign.dblite
|
||||
**/ios/**/.tags*
|
||||
**/ios/**/.vagrant/
|
||||
**/ios/**/DerivedData/
|
||||
**/ios/**/Icon?
|
||||
**/ios/**/Pods/
|
||||
**/ios/**/.symlinks/
|
||||
**/ios/**/profile
|
||||
**/ios/**/xcuserdata
|
||||
**/ios/.generated/
|
||||
**/ios/Flutter/App.framework
|
||||
**/ios/Flutter/Flutter.framework
|
||||
**/ios/Flutter/Generated.xcconfig
|
||||
**/ios/Flutter/app.flx
|
||||
**/ios/Flutter/app.zip
|
||||
**/ios/Flutter/flutter_assets/
|
||||
**/ios/ServiceDefinitions.json
|
||||
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!**/ios/**/default.mode1v3
|
||||
!**/ios/**/default.mode2v3
|
||||
!**/ios/**/default.pbxuser
|
||||
!**/ios/**/default.perspectivev3
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
10
doc/examples/effects/sequence_effect/.metadata
Normal file
10
doc/examples/effects/sequence_effect/.metadata
Normal file
@ -0,0 +1,10 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 7fc14a55af64462763d28abfb4e610086c6e0f39
|
||||
channel: dev
|
||||
|
||||
project_type: app
|
||||
3
doc/examples/effects/sequence_effect/README.md
Normal file
3
doc/examples/effects/sequence_effect/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Infinite effects
|
||||
|
||||
A Flame game showcasing how to create infinite alternating effects.
|
||||
78
doc/examples/effects/sequence_effect/lib/main.dart
Normal file
78
doc/examples/effects/sequence_effect/lib/main.dart
Normal file
@ -0,0 +1,78 @@
|
||||
import 'package:flame/effects/move_effect.dart';
|
||||
import 'package:flame/effects/scale_effect.dart';
|
||||
import 'package:flame/effects/rotate_effect.dart';
|
||||
import 'package:flame/effects/sequence_effect.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import './square.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Flame.util.fullScreen();
|
||||
runApp(MyGame().widget);
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame with TapDetector {
|
||||
Square greenSquare;
|
||||
Square redSquare;
|
||||
Square orangeSquare;
|
||||
|
||||
MyGame() {
|
||||
final green = Paint()..color = const Color(0xAA338833);
|
||||
greenSquare = Square(green, 100, 100);
|
||||
add(greenSquare);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapUp(TapUpDetails details) {
|
||||
final dx = details.localPosition.dx;
|
||||
final dy = details.localPosition.dy;
|
||||
|
||||
greenSquare.clearEffects();
|
||||
|
||||
final move1 = MoveEffect(
|
||||
destination: Position(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.bounceInOut,
|
||||
isInfinite: false,
|
||||
isAlternating: false,
|
||||
);
|
||||
|
||||
final move2 = MoveEffect(
|
||||
destination: Position(dx, dy + 150),
|
||||
speed: 150.0,
|
||||
curve: Curves.easeIn,
|
||||
isInfinite: false,
|
||||
isAlternating: true,
|
||||
);
|
||||
|
||||
final scale = ScaleEffect(
|
||||
size: Size(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.easeInCubic,
|
||||
isInfinite: false,
|
||||
isAlternating: false,
|
||||
);
|
||||
|
||||
final rotate = RotateEffect(
|
||||
radians: (dx + dy) % pi,
|
||||
speed: 2.0, // Radians per second
|
||||
curve: Curves.decelerate,
|
||||
isInfinite: false,
|
||||
isAlternating: false,
|
||||
);
|
||||
|
||||
final sequence = SequenceEffect(
|
||||
effects: [move1, scale, move2, rotate],
|
||||
//effects: [rotate],
|
||||
//effects: [scale],
|
||||
isInfinite: true, isAlternating: true);
|
||||
greenSquare.addEffect(sequence);
|
||||
}
|
||||
}
|
||||
24
doc/examples/effects/sequence_effect/lib/square.dart
Normal file
24
doc/examples/effects/sequence_effect/lib/square.dart
Normal file
@ -0,0 +1,24 @@
|
||||
import 'package:flame/anchor.dart';
|
||||
import 'package:flame/components/component.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
class Square extends PositionComponent {
|
||||
final Paint _paint;
|
||||
|
||||
Square(this._paint, double x, double y, {double angle = 0.0}) {
|
||||
width = 100;
|
||||
height = 100;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.angle = angle;
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
prepareCanvas(canvas);
|
||||
final rect = Rect.fromLTWH(0, 0, width, height);
|
||||
canvas.drawRect(rect, _paint);
|
||||
}
|
||||
}
|
||||
17
doc/examples/effects/sequence_effect/pubspec.yaml
Normal file
17
doc/examples/effects/sequence_effect/pubspec.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
name: infinite_effects
|
||||
description: Flame sample game showcasing infinite effects
|
||||
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flame:
|
||||
path: ../../../../
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
@ -4,6 +4,7 @@ import '../components/component.dart';
|
||||
export './move_effect.dart';
|
||||
export './scale_effect.dart';
|
||||
export './rotate_effect.dart';
|
||||
export './sequence_effect.dart';
|
||||
|
||||
abstract class PositionComponentEffect {
|
||||
bool _isDisposed = false;
|
||||
@ -15,19 +16,24 @@ abstract class PositionComponentEffect {
|
||||
bool isInfinite;
|
||||
double percentage;
|
||||
double travelTime;
|
||||
double _curveTime = 0.0;
|
||||
int _curveDirection = 1;
|
||||
double currentTime = 0.0;
|
||||
double driftTime = 0.0;
|
||||
int curveDirection = 1;
|
||||
|
||||
PositionComponentEffect(this.isInfinite, this.isAlternating);
|
||||
|
||||
void update(double dt) {
|
||||
_curveTime += dt * _curveDirection;
|
||||
if (isAlternating) {
|
||||
_curveDirection = isMax() ? -1 : (isMin() ? 1 : _curveDirection);
|
||||
} else if (isInfinite && isMax()) {
|
||||
_curveTime = 0.0;
|
||||
currentTime += dt * curveDirection;
|
||||
if (hasFinished() && !isDisposed) {
|
||||
driftTime = isAlternating ? currentTime.abs() : currentTime - travelTime;
|
||||
}
|
||||
percentage = min(1.0, max(0.0, _curveTime / travelTime));
|
||||
|
||||
if (isAlternating) {
|
||||
curveDirection = isMax() ? -1 : (isMin() ? 1 : curveDirection);
|
||||
} else if (isInfinite && isMax()) {
|
||||
currentTime = 0.0;
|
||||
}
|
||||
percentage = min(1.0, max(0.0, currentTime / travelTime));
|
||||
}
|
||||
|
||||
void dispose() => _isDisposed = true;
|
||||
@ -40,4 +46,11 @@ abstract class PositionComponentEffect {
|
||||
isDisposed;
|
||||
bool isMax() => percentage == null ? false : percentage == 1.0;
|
||||
bool isMin() => percentage == null ? false : percentage == 0.0;
|
||||
|
||||
void reset() {
|
||||
_isDisposed = false;
|
||||
percentage = null;
|
||||
currentTime = 0.0;
|
||||
curveDirection = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +44,8 @@ class MoveEffect extends PositionComponentEffect {
|
||||
_yDirection = _direction(destination.y, component.y);
|
||||
|
||||
final totalDistance = sqrt(pow(_xDistance, 2) + pow(_yDistance, 2));
|
||||
print(totalDistance);
|
||||
print(speed);
|
||||
travelTime = totalDistance / speed;
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ class RotateEffect extends PositionComponentEffect {
|
||||
double _direction;
|
||||
|
||||
RotateEffect({
|
||||
@required this.radians, // The angle to rotate to
|
||||
@required this.radians, // As many radians as you want to rotate
|
||||
@required this.speed, // In radians per second
|
||||
this.curve,
|
||||
isInfinite = false,
|
||||
@ -26,7 +26,7 @@ class RotateEffect extends PositionComponentEffect {
|
||||
_originalAngle = component.angle;
|
||||
_peakAngle = _originalAngle + radians;
|
||||
_direction = _peakAngle.sign;
|
||||
travelTime = (_peakAngle / speed).abs();
|
||||
travelTime = (radians / speed).abs();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
101
lib/effects/sequence_effect.dart
Normal file
101
lib/effects/sequence_effect.dart
Normal file
@ -0,0 +1,101 @@
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
import 'dart:math';
|
||||
|
||||
import './effects.dart';
|
||||
import '../position.dart';
|
||||
|
||||
class SequenceEffect extends PositionComponentEffect {
|
||||
final List<PositionComponentEffect> effects;
|
||||
int _currentIndex = 0;
|
||||
PositionComponentEffect _currentEffect;
|
||||
bool _currentWasAlternating;
|
||||
double _driftModifier = 0.0;
|
||||
|
||||
SequenceEffect({
|
||||
@required this.effects,
|
||||
isInfinite = false,
|
||||
isAlternating = false,
|
||||
}) : super(isInfinite, isAlternating);
|
||||
|
||||
@override
|
||||
set component(_comp) {
|
||||
super.component = _comp;
|
||||
final originalSize = _comp.toSize();
|
||||
final originalPosition = _comp.toPosition();
|
||||
Position currentSize = _comp.toSize();
|
||||
Position currentPosition = _comp.toPosition();
|
||||
effects.forEach((effect) {
|
||||
effect.reset();
|
||||
_comp.setBySize(currentSize);
|
||||
_comp.setByPosition(currentPosition);
|
||||
effect.component = _comp;
|
||||
if (effect is MoveEffect) {
|
||||
currentPosition = effect.destination;
|
||||
} else if (effect is ScaleEffect) {
|
||||
currentSize = Position.fromSize(effect.size);
|
||||
}
|
||||
});
|
||||
travelTime = effects.fold(0, (time, effect) => time + effect.travelTime *
|
||||
(effect.isAlternating ? 2 : 1));
|
||||
effects.forEach((element) {print("$element ${element.travelTime}");});
|
||||
component.setBySize(originalSize);
|
||||
component.setByPosition(originalPosition);
|
||||
_currentEffect = effects.first;
|
||||
_currentWasAlternating = _currentEffect.isAlternating;
|
||||
}
|
||||
|
||||
@override
|
||||
void update(double dt) {
|
||||
super.update(dt);
|
||||
if (hasFinished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_currentEffect.update(dt + _driftModifier);
|
||||
_driftModifier = 0.0;
|
||||
if (_currentEffect.hasFinished()) {
|
||||
_driftModifier = _currentEffect.driftTime;
|
||||
_currentEffect.isAlternating = _currentWasAlternating;
|
||||
_currentIndex++;
|
||||
final iterationSize = isAlternating ? effects.length * 2 : effects.length;
|
||||
if (isInfinite &&
|
||||
_currentIndex != 0 &&
|
||||
_currentIndex % iterationSize == 0) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
final orderedEffects =
|
||||
curveDirection.isNegative ? effects.reversed.toList() : effects;
|
||||
_currentEffect = orderedEffects[_currentIndex % effects.length];
|
||||
print("Index: ${_currentIndex % effects.length}");
|
||||
print(_currentIndex);
|
||||
print(curveDirection);
|
||||
print(_currentEffect);
|
||||
print(orderedEffects);
|
||||
_currentWasAlternating = _currentEffect.isAlternating;
|
||||
if (isAlternating &&
|
||||
!_currentEffect.isAlternating &&
|
||||
curveDirection.isNegative) {
|
||||
// Make the effect go in reverse
|
||||
_currentEffect.isAlternating = true;
|
||||
_currentEffect.percentage = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void reset() {
|
||||
super.reset();
|
||||
_currentIndex = 0;
|
||||
component = component;
|
||||
}
|
||||
|
||||
@override
|
||||
bool hasFinished() {
|
||||
return super.hasFinished() &&
|
||||
effects.every((effect) => effect.hasFinished());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user