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,運行結果可不僅僅是差一點而已。)
但...換算並不是什麼難事啦!其實螢幕的大小與「世界座標的邊界」都能取得,自然也就能換算。
處理完換算問題後,繼續把遊戲完成吧!