mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +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 './move_effect.dart';
|
||||||
export './scale_effect.dart';
|
export './scale_effect.dart';
|
||||||
export './rotate_effect.dart';
|
export './rotate_effect.dart';
|
||||||
|
export './sequence_effect.dart';
|
||||||
|
|
||||||
abstract class PositionComponentEffect {
|
abstract class PositionComponentEffect {
|
||||||
bool _isDisposed = false;
|
bool _isDisposed = false;
|
||||||
@ -15,19 +16,24 @@ abstract class PositionComponentEffect {
|
|||||||
bool isInfinite;
|
bool isInfinite;
|
||||||
double percentage;
|
double percentage;
|
||||||
double travelTime;
|
double travelTime;
|
||||||
double _curveTime = 0.0;
|
double currentTime = 0.0;
|
||||||
int _curveDirection = 1;
|
double driftTime = 0.0;
|
||||||
|
int curveDirection = 1;
|
||||||
|
|
||||||
PositionComponentEffect(this.isInfinite, this.isAlternating);
|
PositionComponentEffect(this.isInfinite, this.isAlternating);
|
||||||
|
|
||||||
void update(double dt) {
|
void update(double dt) {
|
||||||
_curveTime += dt * _curveDirection;
|
currentTime += dt * curveDirection;
|
||||||
if (isAlternating) {
|
if (hasFinished() && !isDisposed) {
|
||||||
_curveDirection = isMax() ? -1 : (isMin() ? 1 : _curveDirection);
|
driftTime = isAlternating ? currentTime.abs() : currentTime - travelTime;
|
||||||
} else if (isInfinite && isMax()) {
|
|
||||||
_curveTime = 0.0;
|
|
||||||
}
|
}
|
||||||
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;
|
void dispose() => _isDisposed = true;
|
||||||
@ -40,4 +46,11 @@ abstract class PositionComponentEffect {
|
|||||||
isDisposed;
|
isDisposed;
|
||||||
bool isMax() => percentage == null ? false : percentage == 1.0;
|
bool isMax() => percentage == null ? false : percentage == 1.0;
|
||||||
bool isMin() => percentage == null ? false : percentage == 0.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);
|
_yDirection = _direction(destination.y, component.y);
|
||||||
|
|
||||||
final totalDistance = sqrt(pow(_xDistance, 2) + pow(_yDistance, 2));
|
final totalDistance = sqrt(pow(_xDistance, 2) + pow(_yDistance, 2));
|
||||||
|
print(totalDistance);
|
||||||
|
print(speed);
|
||||||
travelTime = totalDistance / speed;
|
travelTime = totalDistance / speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class RotateEffect extends PositionComponentEffect {
|
|||||||
double _direction;
|
double _direction;
|
||||||
|
|
||||||
RotateEffect({
|
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
|
@required this.speed, // In radians per second
|
||||||
this.curve,
|
this.curve,
|
||||||
isInfinite = false,
|
isInfinite = false,
|
||||||
@ -26,7 +26,7 @@ class RotateEffect extends PositionComponentEffect {
|
|||||||
_originalAngle = component.angle;
|
_originalAngle = component.angle;
|
||||||
_peakAngle = _originalAngle + radians;
|
_peakAngle = _originalAngle + radians;
|
||||||
_direction = _peakAngle.sign;
|
_direction = _peakAngle.sign;
|
||||||
travelTime = (_peakAngle / speed).abs();
|
travelTime = (radians / speed).abs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@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