mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-11-01 01:18:38 +08:00 
			
		
		
		
	RemoveEffect (#1063)
* Added FlameAnimationController class * Added MainAnimationController class * Update doc comments * formatting * rename MainAnimationController * Added tests for StandardAnimationController * Added more tests * comment * Added changelog note * Export StandardAnimationController * formatting * Use a default for 'curve' parameter * rename onsetDelay -> startDelay * Added Transofm2DEffect * Added EffectComponent * Added .transform getter * formatting * Rename EffectComponent -> Effect * Add documentation for the Effect class * minor * Added a test for Effect class * Adding tests for removeOnFinish * Adding tests for onStart and onFinish * Also check the effect after reset * Fix-up merge * formatting * added doc-comments * changelog note * Added test for transform2DEffect * Adjusted comments * Make PositionComponent._transform public * change changelog * Added SimpleEffectController * Added DestroyEffect * Changelog note * Rename DestroyEffect -> RemoveEffect * Added example for RemoveEffect * flutter format * Move description of the RemoveEffectExample game * move the description again * minor
This commit is contained in:
		| @ -18,4 +18,11 @@ class CircleComponent extends PositionComponent { | |||||||
|     super.render(canvas); |     super.render(canvas); | ||||||
|     canvas.drawCircle(Offset(radius, radius), radius, paint); |     canvas.drawCircle(Offset(radius, radius), radius, paint); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool containsPoint(Vector2 point) { | ||||||
|  |     final local = absoluteToLocal(point); | ||||||
|  |     final center = Vector2.all(radius); | ||||||
|  |     return local.distanceToSquared(center) <= radius * radius; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import 'combined_effect.dart'; | |||||||
| import 'infinite_effect.dart'; | import 'infinite_effect.dart'; | ||||||
| import 'move_effect.dart'; | import 'move_effect.dart'; | ||||||
| import 'opacity_effect.dart'; | import 'opacity_effect.dart'; | ||||||
|  | import 'remove_effect_example.dart'; | ||||||
| import 'rotate_effect.dart'; | import 'rotate_effect.dart'; | ||||||
| import 'scale_effect.dart'; | import 'scale_effect.dart'; | ||||||
| import 'sequence_effect.dart'; | import 'sequence_effect.dart'; | ||||||
| @ -67,5 +68,11 @@ void addEffectsStories(Dashbook dashbook) { | |||||||
|       'Color Effect', |       'Color Effect', | ||||||
|       (_) => GameWidget(game: ColorEffectGame()), |       (_) => GameWidget(game: ColorEffectGame()), | ||||||
|       codeLink: baseLink('effects/color_effect.dart'), |       codeLink: baseLink('effects/color_effect.dart'), | ||||||
|  |     ) | ||||||
|  |     ..add( | ||||||
|  |       'Remove Effect', | ||||||
|  |       (_) => GameWidget(game: RemoveEffectExample()), | ||||||
|  |       codeLink: baseLink('effects/remove_effect_example.dart'), | ||||||
|  |       info: RemoveEffectExample.description, | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								examples/lib/stories/effects/remove_effect_example.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								examples/lib/stories/effects/remove_effect_example.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | import 'dart:math'; | ||||||
|  |  | ||||||
|  | import 'package:flame/components.dart'; | ||||||
|  | import 'package:flame/game.dart'; | ||||||
|  | import 'package:flame/input.dart'; | ||||||
|  | import 'package:flame/src/effects2/remove_effect.dart'; // ignore: implementation_imports | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import '../../commons/circle_component.dart'; | ||||||
|  |  | ||||||
|  | class RemoveEffectExample extends FlameGame with HasTappableComponents { | ||||||
|  |   static const description = ''' | ||||||
|  |     Click on any circle to apply a RemoveEffect, which will make the circle | ||||||
|  |     disappear after a 0.5 second delay. | ||||||
|  |   '''; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void onMount() { | ||||||
|  |     super.onMount(); | ||||||
|  |     camera.viewport = FixedResolutionViewport(Vector2(400, 600)); | ||||||
|  |     final rng = Random(); | ||||||
|  |     for (var i = 0; i < 20; i++) { | ||||||
|  |       add(_RandomCircle(rng)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _RandomCircle extends CircleComponent with Tappable { | ||||||
|  |   _RandomCircle(Random rng) : super(radius: rng.nextDouble() * 30 + 10) { | ||||||
|  |     position.setValues( | ||||||
|  |       rng.nextDouble() * 320 + 40, | ||||||
|  |       rng.nextDouble() * 520 + 40, | ||||||
|  |     ); | ||||||
|  |     paint.color = Colors.primaries[rng.nextInt(Colors.primaries.length)]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool onTapDown(TapDownInfo info) { | ||||||
|  |     add(RemoveEffect(delay: 0.5)); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -4,6 +4,7 @@ | |||||||
|  - Added `StandardEffectController` class |  - Added `StandardEffectController` class | ||||||
|  - Refactored `Effect` class to use `EffectController`, added `Transform2DEffect` class |  - Refactored `Effect` class to use `EffectController`, added `Transform2DEffect` class | ||||||
|  - Clarified `TimerComponent` example |  - Clarified `TimerComponent` example | ||||||
|  |  - Added `RemoveEffect` and `SimpleEffectController` | ||||||
|  |  | ||||||
| ## [1.0.0-releasecandidate.16] | ## [1.0.0-releasecandidate.16] | ||||||
|  - `changePriority` no longer breaks game loop iteration |  - `changePriority` no longer breaks game loop iteration | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								packages/flame/lib/src/effects2/remove_effect.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								packages/flame/lib/src/effects2/remove_effect.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | import 'effect.dart'; | ||||||
|  | import 'simple_effect_controller.dart'; | ||||||
|  |  | ||||||
|  | /// This simple effect, when attached to a component, will cause that component | ||||||
|  | /// to be removed from the game tree after `delay` seconds. | ||||||
|  | class RemoveEffect extends Effect { | ||||||
|  |   RemoveEffect({double delay = 0.0}) | ||||||
|  |       : super(SimpleEffectController(delay: delay)); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void apply(double progress) { | ||||||
|  |     if (progress == 1) { | ||||||
|  |       parent?.removeFromParent(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | import 'effect_controller.dart'; | ||||||
|  | import 'standard_effect_controller.dart'; | ||||||
|  |  | ||||||
|  | /// Simplest possible [EffectController], which supports an effect progressing | ||||||
|  | /// linearly over [duration] seconds. | ||||||
|  | /// | ||||||
|  | /// The [duration] can be 0, in which case the effect will jump from 0 to 1 | ||||||
|  | /// instantaneously. | ||||||
|  | /// | ||||||
|  | /// The [delay] parameter allows to delay the start of the effect by the | ||||||
|  | /// specified number of seconds. | ||||||
|  | /// | ||||||
|  | /// See also: [StandardEffectController] | ||||||
|  | class SimpleEffectController extends EffectController { | ||||||
|  |   SimpleEffectController({ | ||||||
|  |     this.duration = 0.0, | ||||||
|  |     this.delay = 0.0, | ||||||
|  |   })  : assert(duration >= 0, 'duration cannot be negative: $duration'), | ||||||
|  |         assert(delay >= 0, 'delay cannot be negative: $delay'); | ||||||
|  |  | ||||||
|  |   final double duration; | ||||||
|  |   final double delay; | ||||||
|  |   double _timer = 0.0; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool get started => _timer >= delay; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool get completed => _timer >= delay + duration; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   bool get isInfinite => false; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   double get progress { | ||||||
|  |     // If duration == 0, then `completed == started`, and the middle case | ||||||
|  |     // (which divides by duration) cannot occur. | ||||||
|  |     return completed | ||||||
|  |         ? 1 | ||||||
|  |         : started | ||||||
|  |             ? (_timer - delay) / duration | ||||||
|  |             : 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void update(double dt) { | ||||||
|  |     _timer += dt; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void reset() { | ||||||
|  |     _timer = 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								packages/flame/test/effects2/remove_effect_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								packages/flame/test/effects2/remove_effect_test.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | import 'package:flame/components.dart'; | ||||||
|  | import 'package:flame/game.dart'; | ||||||
|  | import 'package:flame/src/effects2/remove_effect.dart'; | ||||||
|  | import 'package:flutter_test/flutter_test.dart'; | ||||||
|  |  | ||||||
|  | void main() { | ||||||
|  |   group('RemoveEffect', () { | ||||||
|  |     test('no delay', () { | ||||||
|  |       final game = FlameGame(); | ||||||
|  |       game.onGameResize(Vector2.all(1)); | ||||||
|  |       expect(game.children.length, 0); | ||||||
|  |       final obj = Component(); | ||||||
|  |       game.add(obj); | ||||||
|  |       game.update(0); | ||||||
|  |       expect(game.children.length, 1); | ||||||
|  |  | ||||||
|  |       // First `game.update()` invokes the destroy effect and schedules `obj` | ||||||
|  |       // for deletion; second `game.update()` processes the deletion queue and | ||||||
|  |       // actually removes the component | ||||||
|  |       obj.add(RemoveEffect()); | ||||||
|  |       game.update(0); | ||||||
|  |       game.update(0); | ||||||
|  |       expect(game.children.length, 0); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('delayed', () { | ||||||
|  |       final game = FlameGame(); | ||||||
|  |       game.onGameResize(Vector2.all(1)); | ||||||
|  |       expect(game.children.length, 0); | ||||||
|  |       final obj = Component(); | ||||||
|  |       game.add(obj); | ||||||
|  |       game.update(0); | ||||||
|  |       expect(game.children.length, 1); | ||||||
|  |  | ||||||
|  |       obj.add(RemoveEffect(delay: 1)); | ||||||
|  |       game.update(0.5); | ||||||
|  |       game.update(0); | ||||||
|  |       expect(game.children.length, 1); | ||||||
|  |  | ||||||
|  |       game.update(0.5); | ||||||
|  |       game.update(0); | ||||||
|  |       expect(game.children.length, 0); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
							
								
								
									
										129
									
								
								packages/flame/test/effects2/simple_effect_controller_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								packages/flame/test/effects2/simple_effect_controller_test.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,129 @@ | |||||||
|  | import 'package:flame/src/effects2/simple_effect_controller.dart'; | ||||||
|  | import 'package:flutter_test/flutter_test.dart'; | ||||||
|  |  | ||||||
|  | void main() { | ||||||
|  |   group('SimpleEffectController', () { | ||||||
|  |     test('default', () { | ||||||
|  |       final ec = SimpleEffectController(); | ||||||
|  |       expect(ec.duration, 0); | ||||||
|  |       expect(ec.delay, 0); | ||||||
|  |       expect(ec.isInfinite, false); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('simple with duration', () { | ||||||
|  |       final ec = SimpleEffectController(duration: 1); | ||||||
|  |       expect(ec.delay, 0); | ||||||
|  |       expect(ec.duration, 1); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.isInfinite, false); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.progress, 0.5); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |  | ||||||
|  |       ec.update(0.00001); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('simple with delay', () { | ||||||
|  |       final ec = SimpleEffectController(delay: 1); | ||||||
|  |       expect(ec.isInfinite, false); | ||||||
|  |       expect(ec.started, false); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |       expect(ec.delay, 1); | ||||||
|  |       expect(ec.duration, 0); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.started, false); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('duration + delay', () { | ||||||
|  |       final ec = SimpleEffectController(duration: 1, delay: 2); | ||||||
|  |       expect(ec.isInfinite, false); | ||||||
|  |       expect(ec.started, false); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.duration, 1); | ||||||
|  |       expect(ec.delay, 2); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.started, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.started, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(1); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, 0.5); | ||||||
|  |  | ||||||
|  |       ec.update(0.5); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('reset', () { | ||||||
|  |       final ec = SimpleEffectController(); | ||||||
|  |       ec.reset(); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     test('reset 2', () { | ||||||
|  |       final ec = SimpleEffectController(duration: 2, delay: 1); | ||||||
|  |       ec.update(3); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |  | ||||||
|  |       ec.reset(); | ||||||
|  |       expect(ec.started, false); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(1); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, 0); | ||||||
|  |  | ||||||
|  |       ec.update(1); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, false); | ||||||
|  |       expect(ec.progress, closeTo(0.5, 1e-15)); | ||||||
|  |  | ||||||
|  |       ec.update(1); | ||||||
|  |       expect(ec.started, true); | ||||||
|  |       expect(ec.completed, true); | ||||||
|  |       expect(ec.progress, 1); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Pasha Stetsenko
					Pasha Stetsenko