Skip to content

Commit

Permalink
feat: Add RotateAroundEffect (#3499)
Browse files Browse the repository at this point in the history
Introduces the `RotateAroundEffect` which rotates your component around
a pivot point.
  • Loading branch information
spydon authored Feb 16, 2025
1 parent 20c08ad commit 0688f41
Show file tree
Hide file tree
Showing 23 changed files with 376 additions and 208 deletions.
24 changes: 24 additions & 0 deletions doc/flame/effects.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ There are multiple effects provided by Flame, and you can also
- [`MoveByEffect`](#movebyeffect)
- [`MoveToEffect`](#movetoeffect)
- [`MoveAlongPathEffect`](#movealongpatheffect)
- [`RotateAroundEffect`](#rotatearoundeffect)
- [`RotateEffect.by`](#rotateeffectby)
- [`RotateEffect.to`](#rotateeffectto)
- [`ScaleEffect.by`](#scaleeffectby)
Expand Down Expand Up @@ -177,6 +178,29 @@ itself in the direction the curve is facing at each point. With this flag the ef
the move- and the rotate- effect at the same time.


### `RotateAroundEffect`

Rotates the target clockwise by the specified angle relative to its current orientation around
the specified center. The angle is in radians. For example, the following effect will rotate the
target 90º (=[tau]/4 in radians) clockwise around (100, 100).

```{flutter-app}
:sources: ../flame/examples
:page: rotate_around_effect
:show: widget code infobox
:width: 180
:height: 160
```

```dart
final effect = RotateAroundEffect(
tau/4,
center: Vector2(100, 100),
EffectController(duration: 2),
);
```


### `RotateEffect.by`

Rotates the target clockwise by the specified angle relative to its current orientation. The angle
Expand Down
23 changes: 8 additions & 15 deletions doc/flame/examples/lib/anchor_by_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,20 @@ import 'package:flame/game.dart';

class AnchorByEffectGame extends FlameGame {
bool reset = false;

@override
Future<void> onLoad() async {
final flower = Flower(
size: 60,
position: canvasSize / 2,
onTap: (flower) {
if (reset = !reset) {
flower.add(
AnchorByEffect(
Vector2(0.5, 0.5),
EffectController(speed: 1),
),
);
} else {
flower.add(
AnchorByEffect(
Vector2(-0.5, -0.5),
EffectController(speed: 1),
),
);
}
flower.add(
AnchorByEffect(
reset ? Vector2(-0.5, -0.5) : Vector2(0.5, 0.5),
EffectController(speed: 1),
),
);
reset = !reset;
},
);
add(flower);
Expand Down
21 changes: 6 additions & 15 deletions doc/flame/examples/lib/anchor_to_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,12 @@ class AnchorToEffectGame extends FlameGame {
size: 60,
position: canvasSize / 2,
onTap: (flower) {
if (flower.anchor == Anchor.center) {
flower.add(
AnchorToEffect(
Anchor.bottomLeft,
EffectController(speed: 1),
),
);
} else {
flower.add(
AnchorToEffect(
Anchor.center,
EffectController(speed: 1),
),
);
}
flower.add(
AnchorToEffect(
flower.anchor == Anchor.center ? Anchor.bottomLeft : Anchor.center,
EffectController(speed: 1),
),
);
},
);
add(flower);
Expand Down
25 changes: 8 additions & 17 deletions doc/flame/examples/lib/color_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,14 @@ class ColorEffectExample extends FlameGame {
position: size / 2,
size: size / 4,
onTap: (ember) {
if (reset = !reset) {
ember.add(
ColorEffect(
const Color(0xFF00FF00),
EffectController(duration: 1.5),
opacityTo: 0.6,
),
);
} else {
ember.add(
ColorEffect(
const Color(0xFF1039DB),
EffectController(duration: 1.5),
opacityTo: 0.6,
),
);
}
ember.add(
ColorEffect(
reset ? const Color(0xFF1039DB) : const Color(0xFF00FF00),
EffectController(duration: 1.5),
opacityTo: 0.6,
),
);
reset = !reset;
},
)..anchor = Anchor.center;

Expand Down
2 changes: 2 additions & 0 deletions doc/flame/examples/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import 'package:doc_flame_examples/ray_cast.dart';
import 'package:doc_flame_examples/ray_trace.dart';
import 'package:doc_flame_examples/remove_effect.dart';
import 'package:doc_flame_examples/rive_example.dart';
import 'package:doc_flame_examples/rotate_around_effect.dart';
import 'package:doc_flame_examples/rotate_by_effect.dart';
import 'package:doc_flame_examples/rotate_to_effect.dart';
import 'package:doc_flame_examples/router.dart';
Expand Down Expand Up @@ -60,6 +61,7 @@ final routes = <String, Game Function()>{
'ray_trace': RayTraceExample.new,
'remove_effect': RemoveEffectGame.new,
'rive_example': RiveExampleGame.new,
'rotate_around_effect': RotateAroundEffectGame.new,
'rotate_by_effect': RotateByEffectGame.new,
'rotate_to_effect': RotateToEffectGame.new,
'router': RouterGame.new,
Expand Down
24 changes: 9 additions & 15 deletions doc/flame/examples/lib/move_along_path_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,15 @@ class MoveAlongPathEffectGame extends FlameGame {
size: 60,
position: canvasSize / 2,
onTap: (flower) {
if (reset = !reset) {
flower.add(
MoveAlongPathEffect(
Path()..quadraticBezierTo(100, 0, 50, -50),
EffectController(duration: 1.5),
),
);
} else {
flower.add(
MoveAlongPathEffect(
Path()..quadraticBezierTo(-100, 0, -50, 50),
EffectController(duration: 1.5),
),
);
}
flower.add(
MoveAlongPathEffect(
reset
? (Path()..quadraticBezierTo(-100, 0, -50, 50))
: (Path()..quadraticBezierTo(100, 0, 50, -50)),
EffectController(duration: 1.5),
),
);
reset = !reset;
},
);
add(flower);
Expand Down
22 changes: 7 additions & 15 deletions doc/flame/examples/lib/move_by_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,13 @@ class MoveByEffectGame extends FlameGame {
size: 60,
position: canvasSize / 2,
onTap: (flower) {
if (reset = !reset) {
flower.add(
MoveEffect.by(
Vector2(30, 30),
EffectController(duration: 1.0),
),
);
} else {
flower.add(
MoveEffect.by(
Vector2(-30, -30),
EffectController(duration: 1.0),
),
);
}
flower.add(
MoveEffect.by(
reset ? Vector2(-30, -30) : Vector2(30, 30),
EffectController(duration: 1.0),
),
);
reset = !reset;
},
);
add(flower);
Expand Down
23 changes: 8 additions & 15 deletions doc/flame/examples/lib/move_to_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,20 @@ import 'package:flame/game.dart';

class MoveToEffectGame extends FlameGame {
bool reset = false;

@override
Future<void> onLoad() async {
final flower = Flower(
size: 60,
position: canvasSize / 2,
onTap: (flower) {
if (reset = !reset) {
flower.add(
MoveEffect.to(
Vector2(30, 30),
EffectController(duration: 1.0),
),
);
} else {
flower.add(
MoveEffect.to(
size / 2,
EffectController(duration: 1.0),
),
);
}
flower.add(
MoveEffect.to(
reset ? size / 2 : Vector2(30, 30),
EffectController(duration: 1.0),
),
);
reset = !reset;
},
);
add(flower);
Expand Down
23 changes: 8 additions & 15 deletions doc/flame/examples/lib/opacity_by_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,20 @@ import 'package:flame/game.dart';

class OpacityByEffectGame extends FlameGame {
bool reset = false;

@override
Future<void> onLoad() async {
final ember = EmberPlayer(
position: size / 2,
size: size / 4,
onTap: (ember) {
if (reset = !reset) {
ember.add(
OpacityEffect.by(
0.9,
EffectController(duration: 0.75),
),
);
} else {
ember.add(
OpacityEffect.by(
-0.9,
EffectController(duration: 0.75),
),
);
}
ember.add(
OpacityEffect.by(
reset ? 0.9 : -0.9,
EffectController(duration: 0.75),
),
);
reset = !reset;
},
)..anchor = Anchor.center;

Expand Down
7 changes: 4 additions & 3 deletions doc/flame/examples/lib/opacity_effect_with_target.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,20 @@ class OpacityEffectWithTargetGame extends FlameGame {
void _onTap(Flower flower) {
if (reset = !reset) {
flower.add(
OpacityEffect.to(
0.2,
OpacityEffect.fadeIn(
EffectController(duration: 0.75),
target: _borderOpacityProvider,
),
);
} else {
flower.add(
OpacityEffect.fadeIn(
OpacityEffect.to(
0.2,
EffectController(duration: 0.75),
target: _borderOpacityProvider,
),
);
}
reset = !reset;
}
}
9 changes: 5 additions & 4 deletions doc/flame/examples/lib/opacity_to_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ class OpacityToEffectGame extends FlameGame {
}

void _onTap(Flower flower) {
if (reset = !reset) {
if (reset) {
flower.add(
OpacityEffect.to(
0.2,
OpacityEffect.fadeIn(
EffectController(duration: 0.75),
),
);
} else {
flower.add(
OpacityEffect.fadeIn(
OpacityEffect.to(
0.2,
EffectController(duration: 0.75),
),
);
}
reset = !reset;
}
}
27 changes: 27 additions & 0 deletions doc/flame/examples/lib/rotate_around_effect.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:doc_flame_examples/flower.dart';
import 'package:flame/effects.dart';
import 'package:flame/game.dart';
import 'package:flame/geometry.dart';

class RotateAroundEffectGame extends FlameGame {
bool reset = false;

@override
Future<void> onLoad() async {
final flower = Flower(
size: 60,
position: canvasSize / 4,
onTap: (flower) {
flower.add(
RotateAroundEffect(
reset != reset ? tau : -tau,
center: canvasSize / 2,
EffectController(duration: 1),
),
);
reset = !reset;
},
);
add(flower);
}
}
23 changes: 8 additions & 15 deletions doc/flame/examples/lib/rotate_by_effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,20 @@ import 'package:flame/geometry.dart';

class RotateByEffectGame extends FlameGame {
bool reset = false;

@override
Future<void> onLoad() async {
final flower = Flower(
size: 60,
position: canvasSize / 2,
onTap: (flower) {
if (reset = !reset) {
flower.add(
RotateEffect.by(
tau / 4,
EffectController(duration: 2),
),
);
} else {
flower.add(
RotateEffect.by(
-tau / 4,
EffectController(duration: 2),
),
);
}
flower.add(
RotateEffect.by(
reset ? tau / 4 : -tau / 4,
EffectController(duration: 2),
),
);
reset = !reset;
},
);
add(flower);
Expand Down
Loading

0 comments on commit 0688f41

Please sign in to comment.