mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 20:13:50 +08:00
This PR adds a new mixin on Component. When attached to a component, it allows scaling the delta time of that component as well as all its children by a non-negative factor. The idea is to allows slowing down or speeding up the gameplay by change the scaling factor. Note: This approach works only for framerate independent game logic. Code in update() that is not dependent on delta time will remain unaffected by time scale.
124 lines
3.1 KiB
Dart
124 lines
3.1 KiB
Dart
import 'dart:async';
|
|
import 'dart:math';
|
|
|
|
import 'package:flame/collisions.dart';
|
|
import 'package:flame/components.dart';
|
|
import 'package:flame/game.dart';
|
|
import 'package:flame/image_composition.dart';
|
|
import 'package:flame/palette.dart';
|
|
import 'package:flame/sprite.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
|
|
class TimeScaleExample extends FlameGame
|
|
with HasTimeScale, HasCollisionDetection {
|
|
static const description =
|
|
'This example shows how time scale can be used to control game speed.';
|
|
|
|
final gameSpeedText = TextComponent(
|
|
text: 'Time Scale: 1',
|
|
textRenderer: TextPaint(
|
|
style: TextStyle(
|
|
color: BasicPalette.white.color,
|
|
fontSize: 20.0,
|
|
shadows: const [
|
|
Shadow(offset: Offset(1, 1), blurRadius: 1),
|
|
],
|
|
),
|
|
),
|
|
anchor: Anchor.center,
|
|
);
|
|
|
|
@override
|
|
Color backgroundColor() => const Color.fromARGB(255, 88, 114, 97);
|
|
|
|
@override
|
|
Future<void> onLoad() async {
|
|
camera.viewport = FixedResolutionViewport(Vector2(640, 360));
|
|
final spriteSheet = SpriteSheet(
|
|
image: await images.load('animations/chopper.png'),
|
|
srcSize: Vector2.all(48),
|
|
);
|
|
gameSpeedText.position = Vector2(size.x * 0.5, size.y * 0.8);
|
|
|
|
await addAll([
|
|
_Chopper(
|
|
position: Vector2(size.x * 0.3, size.y * 0.45),
|
|
size: Vector2.all(64),
|
|
anchor: Anchor.center,
|
|
angle: -pi / 2,
|
|
animation: spriteSheet.createAnimation(row: 0, stepTime: 0.05),
|
|
),
|
|
_Chopper(
|
|
position: Vector2(size.x * 0.6, size.y * 0.55),
|
|
size: Vector2.all(64),
|
|
anchor: Anchor.center,
|
|
angle: pi / 2,
|
|
animation: spriteSheet.createAnimation(row: 0, stepTime: 0.05),
|
|
),
|
|
gameSpeedText,
|
|
]);
|
|
return super.onLoad();
|
|
}
|
|
|
|
@override
|
|
void update(double dt) {
|
|
gameSpeedText.text = 'Time Scale : $timeScale';
|
|
super.update(dt);
|
|
}
|
|
}
|
|
|
|
class _Chopper extends SpriteAnimationComponent
|
|
with HasGameRef<TimeScaleExample>, CollisionCallbacks {
|
|
_Chopper({
|
|
super.animation,
|
|
super.position,
|
|
super.size,
|
|
super.angle,
|
|
super.anchor,
|
|
}) : _moveDirection = Vector2(0, 1)..rotate(angle ?? 0),
|
|
_initialPosition = position?.clone() ?? Vector2.zero();
|
|
|
|
final Vector2 _moveDirection;
|
|
final _speed = 80.0;
|
|
final Vector2 _initialPosition;
|
|
late final _timer = TimerComponent(
|
|
period: 2,
|
|
onTick: _reset,
|
|
autoStart: false,
|
|
);
|
|
|
|
@override
|
|
Future<void> onLoad() async {
|
|
await add(CircleHitbox());
|
|
await add(_timer);
|
|
return super.onLoad();
|
|
}
|
|
|
|
@override
|
|
void updateTree(double dt) {
|
|
position.setFrom(position + _moveDirection * _speed * dt);
|
|
super.updateTree(dt);
|
|
}
|
|
|
|
@override
|
|
void onCollisionStart(Set<Vector2> _, PositionComponent other) {
|
|
if (other is _Chopper) {
|
|
gameRef.timeScale = 0.25;
|
|
}
|
|
super.onCollisionStart(_, other);
|
|
}
|
|
|
|
@override
|
|
void onCollisionEnd(PositionComponent other) {
|
|
if (other is _Chopper) {
|
|
gameRef.timeScale = 1.0;
|
|
_timer.timer.start();
|
|
}
|
|
super.onCollisionEnd(other);
|
|
}
|
|
|
|
void _reset() {
|
|
position.setFrom(_initialPosition);
|
|
}
|
|
}
|