之前通过Flame 实现了人物的移动以及边界的判断。地址juejin.cn/post/743995…
但是之前的逻辑是通过坐标移动物体。并通过碰撞来判断的到达边界。这种方式判断边界够用,但是如果是检测跟场景里面的障碍物碰撞,就不够用了。
下面的效果是使用flame_forge2d的api实现的,实现了边界碰撞以及场景内建筑物碰撞停止前进的效果。
关键代码:
在flame_forge2d中,要设置二维属性,实现的是BodyComponent
然后重写createBody(设置二维属性)和onLoad(加载资源)
第一步:创建人物Body
@override
Body createBody() {
final shape = PolygonShape()..setAsBoxXY(100, 100);
final fixtureDef = FixtureDef(
shape,
restitution: 0,//设置回弹系数为0 碰撞后就不会反弹
density: 1,
friction: 0, //摩擦
);
final bodyDef = BodyDef(
userData: this,
angularDamping: 0.8,
type: BodyType.dynamic,
position: Vector2.zero()
);
renderBody = false;
return world.createBody(bodyDef)..createFixture(fixtureDef)
..setFixedRotation(true);//设置碰撞后不旋转
}
第二步:加载人物内容
@override
Future<void> onLoad() async{
add(PlayerFooterAura()
..anchor = Anchor.center
..size = Vector2(200, 200));
gamePlayer = GamePlayer();
add(gamePlayer);
return super.onLoad();
}
第三步:创建建筑物就是那个小房子
重写onload 跟 createBody
@override
Future<void> onLoad() async{
add(GameHouse());
return super.onLoad();
}
@override
Body createBody() {
final shape = PolygonShape()..setAsBoxXY(150, 100);
final fixtureDef = FixtureDef(
shape,
restitution: 0,
density: 0.1,
friction: 0.0, //摩擦
);
renderBody = false;
final bodyDef = BodyDef(
userData: this,
angularDamping: 0,
type: BodyType.static,
position: game.size / 4
);
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
第四步:控制移动,这里判断键盘按键的方式还是跟之前的一样。不一样的是这里不通过坐标移动,而是通过给Body 设置速度来移动。
void onKeyEvent(KeyEvent event, Set<LogicalKeyboardKey> keysPressed){
//判断键盘按下 上 下 左 右 方向
final isKeyDown = event is KeyDownEvent;
final keyLeft = (event.logicalKey == LogicalKeyboardKey.arrowLeft) ||
(event.logicalKey == LogicalKeyboardKey.keyA);
final keyRight = (event.logicalKey == LogicalKeyboardKey.arrowRight) ||
(event.logicalKey == LogicalKeyboardKey.keyD);
final keyUp = (event.logicalKey == LogicalKeyboardKey.arrowUp) ||
(event.logicalKey == LogicalKeyboardKey.keyW);
// var mass = 1 / body.inverseMass;
// body.applyLinearImpulse(Vector2(mass * 300, mass * 300));
debugPrint("=====KeyDownEvent===${event}");
debugPrint("=====KeyDownEvent===${keysPressed.contains(LogicalKeyboardKey.keyA)}");
if (isKeyDown) {
if (keyLeft) {
velocity.x = -runSpeed;
} else if (keyRight) {
velocity.x = runSpeed;
}else if(keyUp){
velocity.y = -runSpeed;
}else {
velocity.y = runSpeed;
}
} else {
final hasLeft = keysPressed.contains(LogicalKeyboardKey.arrowLeft) ||
keysPressed.contains(LogicalKeyboardKey.keyA);
final hasRight = keysPressed.contains(LogicalKeyboardKey.arrowRight) ||
keysPressed.contains(LogicalKeyboardKey.keyD);
final hasTop = keysPressed.contains(LogicalKeyboardKey.arrowUp) ||
keysPressed.contains(LogicalKeyboardKey.keyW);
final hasBottom = keysPressed.contains(LogicalKeyboardKey.arrowDown) ||
keysPressed.contains(LogicalKeyboardKey.keyS);
if (hasLeft && hasRight) {
velocity.x = 0;
} else if (hasLeft) {
velocity.x = -runSpeed;
} else if (hasRight) {
velocity.x = runSpeed;
}else {
velocity.x = 0;
}
if (hasTop && hasBottom) {
velocity.y = 0;
} else if (hasTop) {
velocity.y = -runSpeed;
} else if (hasBottom) {
velocity.y = runSpeed;
} else {
velocity.y = 0;
}
}
body.linearVelocity = velocity;
if(velocity.y > 0){
gamePlayer.updateAnim(3);
}else if(velocity.y < 0){
gamePlayer.updateAnim(2);
}else if(velocity.x > 0){
gamePlayer.updateAnim(1);
}else if(velocity.x < 0){
gamePlayer.updateAnim(0);
}else {
gamePlayer.updateAnim(3);
}
}
关键点: body.linearVelocity = velocity;
第五步:设置边界
import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/cupertino.dart';
//创建wall 墙
List<Wall> createBoundaries(Forge2DGame game, {double? strokeWidth}) {
final visibleRect = game.camera.visibleWorldRect;
final topLeft = visibleRect.topLeft.toVector2();
final topRight = visibleRect.topRight.toVector2();
final bottomRight = visibleRect.bottomRight.toVector2();
final bottomLeft = visibleRect.bottomLeft.toVector2();
return [
Wall(topLeft, topRight, strokeWidth: strokeWidth),
Wall(topRight, bottomRight, strokeWidth: strokeWidth),
Wall(bottomLeft, bottomRight, strokeWidth: strokeWidth),
Wall(topLeft, bottomLeft, strokeWidth: strokeWidth),
];
}
class Wall extends BodyComponent {
final Vector2 start;
final Vector2 end;
final double strokeWidth;
Wall(this.start, this.end, {double? strokeWidth})
: strokeWidth = strokeWidth ?? 1;
@override
Body createBody() {
final shape = EdgeShape()..set(start, end);
final fixtureDef = FixtureDef(shape, friction: 0.3);
//EdgeShape 不可以设置 type: BodyType.dynamic,
final bodyDef = BodyDef(
userData: this, // To be able to determine object in collision
position: Vector2.zero(), //相当于设置 相对于word 的位置
);
debugMode = true;
paint.strokeWidth = strokeWidth;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
边界就是添加了四个BodyType 为static的Body。这四个Body就是根据 start end 以及strokeWidth确定的一个四边形。也就是效果图里面的白边。
这样运行 就可以达到图片的效果。