foreword
Recently I am learning a Flutter-based game engine Flame
and trying to write a plane battle myself. This article will record the process of project construction and player fighter creation. It is strongly recommended to give priority to the following content before reading the article, which will give you a certain Flame
knowledge base . Of course, the foundation of Flutter is also necessary.
Environment and resource construction
After creating a new project, pubspec.yaml
add the core dependencies of Flame in . ps: Here the author is using the latest version 1.2.0.
environment:
sdk: ">=2.17.5 <3.0.0"
dependencies:
flutter:
sdk: flutter
flame: ^1.2.0
There is also the regular Flutter static resource configuration. ps: These resources are not all used in this article. The picture resources are all found on the Internet. The resources of WeChat Airplane Wars are only for learning .
Create a fighter
game environment
void main() {
runApp(GameWidget(game: Game()));
}
class Game extends FlameGame with HasDraggables {
@override
Future<void> onLoad() async {}
}
In Flutter's main
function, runApp
one is passed in GameWidget
, which is actually one StatefulWidget
. Game
Inherited from FlameGame
, which is the one defined by Flame Component
. Flame relies on Component
unwinding, analogously to how Flutter reliesWidget
. Subsequent objects in the game will be implemented in the FlameGame
objectComponent
.
// game_widget.dart
class GameWidget<T extends Game> extends StatefulWidget {
final T? game;
...
onLoad
It is Component
one of the life cycles in Activity. If you have learned Android, you can compare it with Activity's onCreate.
player fighter
class Player extends SpriteAnimationComponent {
Player({required Vector2 initPosition, required Vector2 size})
: super(position: initPosition, size: size);
@override
Future<void> onLoad() async {
List<Sprite> sprites = [];
for (int i = 1; i <= 2; i++) {
sprites.add(await Sprite.load('player/me$i.png'));
}
final spriteAnimation = SpriteAnimation.spriteList(sprites, stepTime: 0.15);
animation = spriteAnimation;
add(RectangleHitbox()..debugMode = true);
}
Create class Player
:
- 继承自
SpriteAnimationComponent
,这是一个可以加载动画的Component
,也可以理解为序列帧。这里战机共两帧,设置切换间隔为0.15s
。ps:默认是循环播放的,这里没有特殊需求循环即可。
// sprite_animation.dart
factory SpriteAnimation.spriteList(
List<Sprite> sprites, {
required double stepTime,
bool loop = true,
}) {
return SpriteAnimation(
sprites.map((sprite) => SpriteAnimationFrame(sprite, stepTime)).toList(),
loop: loop,
);
}
- 构造方法需要传入
initPosition
,size
,即初始位置和大小。两者都为Vector2
。ps:由于SpriteAnimationComponent
继承自PositionComponent
,所以会有anchor
锚点的概念,默认是左上角的,锚点的变更会影响position的值,以及后续在布局上的参考位置。 - 添加一个
RectangleHitbox
,可以观察战机当前的位置。
控制战机
在手机上操作战机一般会使用拖拽,或者是拖动的交互。可以在Player中加入HasGameRef
和Draggable
的混入。前者是用于获取最上层FlameGame
对象,即我们自定义的Game对象(ps:加入的Component也是一个树状结构);后者用于实现单个对象的拖拽效果。
class Player extends SpriteAnimationComponent with HasGameRef, Draggable {
Player({required Vector2 initPosition, required Vector2 size})
: super(position: initPosition, size: size);
@override
Future<void> onLoad() async {
// 。。。
}
@override
bool onDragUpdate(DragUpdateInfo info) {
final willToPosition = position + info.delta.global;
double x = willToPosition.x;
double y = willToPosition.y;
if (x < 0) {
x = 0;
} else if (x > gameRef.size.x - size.x) {
x = gameRef.size.x - size.x;
}
if (y < 0) {
y = 0;
} else if (y > gameRef.size.y - size.y) {
y = gameRef.size.y - size.y;
}
position = Vector2(x, y);
return true;
}
onDragUpdate
方法会返回一个DragUpdateInfo
对象,这里取info.delta.global
,即为相对于当前位置的移动差值。正常情况下只需要叠加到position即可。考虑到边界问题,所以需要获取Game对象的大小进行计算,再更新position。
ps: Draggable
There are onDragStart
other onDragEnd
methods that can be implemented, and the mechanism is similar to the native touch event mechanism .
The Component
outermost layer is HasDraggables
the mixin that Game needs to add so that events can be passed down .
class Game extends FlameGame with HasDraggables {
achieve effect
Finally, let's take a look at the implementation effect. Here, a parallax component is added as a background.
at last
This article documents the basic Flame environment construction and the creation of player fighters in Aircraft Wars. The logic of fighter bullets will be recorded later.