Sequence effect with example

This commit is contained in:
Lukas Klingsbo
2020-05-25 01:43:08 +02:00
parent b46cea5112
commit 65b0193cb6
10 changed files with 328 additions and 10 deletions

View 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

View 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

View File

@ -0,0 +1,3 @@
# Infinite effects
A Flame game showcasing how to create infinite alternating effects.

View 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);
}
}

View 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);
}
}

View 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

View File

@ -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;
}
} }

View File

@ -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;
} }

View File

@ -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

View 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());
}
}