iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Mobile Development

用Flutter Flame做遊戲!Live!系列 第 26

週末,罷工一下....MouseJoint的垃圾官方範例...

  • 分享至 

  • xImage
  •  

以下是官方關於「MouseJoint」的範例


import 'package:examples/stories/bridge_libraries/flame_forge2d/revolute_joint_with_motor_example.dart';
import 'package:examples/stories/bridge_libraries/flame_forge2d/utils/balls.dart';
import 'package:examples/stories/bridge_libraries/flame_forge2d/utils/boundaries.dart';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame_forge2d/flame_forge2d.dart';

class MouseJointExample extends Forge2DGame {
  static const description = '''
    In this example we use a `MouseJoint` to make the ball follow the mouse
    when you drag it around.
  ''';

  MouseJointExample()
      : super(gravity: Vector2(0, 10.0), world: MouseJointWorld());
}

class MouseJointWorld extends Forge2DWorld
    with DragCallbacks, HasGameReference<Forge2DGame> {
  late Ball ball;
  late Body groundBody;
  MouseJoint? mouseJoint;

  @override
  Future<void> onLoad() async {
    super.onLoad();
    final boundaries = createBoundaries(game);
    addAll(boundaries);

    final center = Vector2.zero();
    groundBody = createBody(BodyDef());
    ball = Ball(center, radius: 5);
    add(ball);
    add(CornerRamp(center));
    add(CornerRamp(center, isMirrored: true));
  }

  @override
  void onDragStart(DragStartEvent info) {
    super.onDragStart(info);
    final mouseJointDef = MouseJointDef()
      ..maxForce = 3000 * ball.body.mass * 10
      ..dampingRatio = 0.1
      ..frequencyHz = 5
      ..target.setFrom(ball.body.position)
      ..collideConnected = false
      ..bodyA = groundBody
      ..bodyB = ball.body;

    if (mouseJoint == null) {
      mouseJoint = MouseJoint(mouseJointDef);
      createJoint(mouseJoint!);
    }
  }

  @override
  void onDragUpdate(DragUpdateEvent info) {
    mouseJoint?.setTarget(info.localEndPosition);
  }

  @override
  void onDragEnd(DragEndEvent info) {
    super.onDragEnd(info);
    destroyJoint(mouseJoint!);
    mouseJoint = null;
  }
}

這段範例被我評為「垃圾」,因為「createJoint」和「destroyJoint」已經不再由「Forge2DGame」提供了,必須要經由「Forge2DWorld」取得。
也就是說「這段範例無法運作」,而且官方SDK是直接報錯、完全不提供修正指引或相容版本,即使官方文件上仍舊提供這段程式碼。
反正,在這裡指出修正辦法。


另外,這段範例設計上奇妙的地方是「點擊滑鼠不要放開,目標圓球會往滑鼠游標移動,直到圓球到達定位點或點擊放開。」
但「圓球到達定位點」和「點擊放開」是有不同結果的。
前者,圓球會停留在定位點上,但如果在這之前放開點擊,圓球會維持著一個慣性動能。

所以如果要用這個範例來製作「點擊、物件往點擊處移動」的效果,基本上是不夠的。
不是不行,而是還要加很多功。
最大的問題是...


void onTapUp(TapUpEvent event)

void onDragUpdate(DragUpdateEvent event)

上述這兩個用來處理「點擊」和「拖曳」的函數回傳入的Event裡面的「座標」竟然是不同系統的!
一個是「螢幕座標」,也就是傳統標準Canvas使用的座標。
一個是「世界座標」,也就是Flame遊戲引擎為了適應遊戲尺寸自由變化而特別設計的座標。

MouseJoint使用的是「世界座標」,但「點擊」取得的卻是「螢幕座標」,兩種座標之間的轉換需要經過換算,否則兩種系統使用的原點與尺度都不一樣,是絕對沒有互通的可能的!(點擊後取得的「螢幕座標」交給MouseJoint,運行結果可不僅僅是差一點而已。)

但...換算並不是什麼難事啦!其實螢幕的大小與「世界座標的邊界」都能取得,自然也就能換算。
處理完換算問題後,繼續把遊戲完成吧!


上一篇
用「拖曳物件到螢幕邊緣」來移動camera
下一篇
關於Vector2和「往特定方向移動」「往特定座標移動」
系列文
用Flutter Flame做遊戲!Live!32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言