mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 11:43:19 +08:00
docs: RopeJoint documentation and example (#2520)
RopeJoint documentation and example
This commit is contained in:
@ -23,10 +23,10 @@ Currently, Forge2D supports the following joints:
|
|||||||
- [`GearJoint`](#gearjoint)
|
- [`GearJoint`](#gearjoint)
|
||||||
- [`MotorJoint`](#motorjoint)
|
- [`MotorJoint`](#motorjoint)
|
||||||
- [`MouseJoint`](#mousejoint)
|
- [`MouseJoint`](#mousejoint)
|
||||||
- [`PrismaticJoint`] (#prismaticjoint)
|
- [`PrismaticJoint`](#prismaticjoint)
|
||||||
- [`PulleyJoint`](#pulleyjoint)
|
- [`PulleyJoint`](#pulleyjoint)
|
||||||
- [`RevoluteJoint`](#revolutejoint)
|
- [`RevoluteJoint`](#revolutejoint)
|
||||||
- RopeJoint
|
- [`RopeJoint`](#ropejoint)
|
||||||
- WeldJoint
|
- WeldJoint
|
||||||
- WheelJoint
|
- WheelJoint
|
||||||
|
|
||||||
@ -564,3 +564,38 @@ Also, you can get the joint angle and speed using the following methods:
|
|||||||
revoluteJoint.jointAngle();
|
revoluteJoint.jointAngle();
|
||||||
revoluteJoint.jointSpeed();
|
revoluteJoint.jointSpeed();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### `RopeJoint`
|
||||||
|
|
||||||
|
A `RopeJoint` restricts the maximum distance between two points on two bodies.
|
||||||
|
|
||||||
|
`RopeJointDef` requires two body anchor points and the maximum length.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
final ropeJointDef = RopeJointDef()
|
||||||
|
..bodyA = firstBody
|
||||||
|
..localAnchorA.setFrom(firstBody.getLocalCenter())
|
||||||
|
..bodyB = secondBody
|
||||||
|
..localAnchorB.setFrom(secondBody.getLocalCenter())
|
||||||
|
..maxLength = (secondBody.worldCenter - firstBody.worldCenter).length;
|
||||||
|
|
||||||
|
world.createJoint(RopeJoint(ropeJointDef));
|
||||||
|
```
|
||||||
|
|
||||||
|
```{flutter-app}
|
||||||
|
:sources: ../../examples
|
||||||
|
:page: rope_joint
|
||||||
|
:subfolder: stories/bridge_libraries/forge2d/joints
|
||||||
|
:show: code popup
|
||||||
|
```
|
||||||
|
|
||||||
|
- `bodyA`, `bodyB`: Connected bodies
|
||||||
|
- `localAnchorA`, `localAnchorB`: Optional parameter, anchor point relative to the body's origin.
|
||||||
|
- `maxLength`: The maximum length of the rope. This must be larger than `linearSlop`, or the joint
|
||||||
|
will have no effect.
|
||||||
|
|
||||||
|
```{warning}
|
||||||
|
The joint assumes that the maximum length doesn't change during simulation.
|
||||||
|
See `DistanceJoint` if you want to dynamically control length.
|
||||||
|
```
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import 'package:examples/stories/bridge_libraries/forge2d/joints/mouse_joint.dar
|
|||||||
import 'package:examples/stories/bridge_libraries/forge2d/joints/prismatic_joint.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/prismatic_joint.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/joints/pulley_joint.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/pulley_joint.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/joints/revolute_joint.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/revolute_joint.dart';
|
||||||
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/rope_joint.dart';
|
||||||
import 'package:examples/stories/camera_and_viewport/camera_and_viewport.dart';
|
import 'package:examples/stories/camera_and_viewport/camera_and_viewport.dart';
|
||||||
import 'package:examples/stories/collision_detection/collision_detection.dart';
|
import 'package:examples/stories/collision_detection/collision_detection.dart';
|
||||||
import 'package:examples/stories/components/components.dart';
|
import 'package:examples/stories/components/components.dart';
|
||||||
@ -48,6 +49,7 @@ void main() {
|
|||||||
'pulley_joint': PulleyJointExample.new,
|
'pulley_joint': PulleyJointExample.new,
|
||||||
'prismatic_joint': PrismaticJointExample.new,
|
'prismatic_joint': PrismaticJointExample.new,
|
||||||
'revolute_joint': RevoluteJointExample.new,
|
'revolute_joint': RevoluteJointExample.new,
|
||||||
|
'rope_joint': RopeJointExample.new,
|
||||||
};
|
};
|
||||||
final game = routes[page]?.call();
|
final game = routes[page]?.call();
|
||||||
if (game != null) {
|
if (game != null) {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import 'package:examples/stories/bridge_libraries/forge2d/joints/mouse_joint.dar
|
|||||||
import 'package:examples/stories/bridge_libraries/forge2d/joints/prismatic_joint.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/prismatic_joint.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/joints/pulley_joint.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/pulley_joint.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/joints/revolute_joint.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/revolute_joint.dart';
|
||||||
|
import 'package:examples/stories/bridge_libraries/forge2d/joints/rope_joint.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/raycast_example.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/raycast_example.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/revolute_joint_with_motor_example.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/revolute_joint_with_motor_example.dart';
|
||||||
import 'package:examples/stories/bridge_libraries/forge2d/sprite_body_example.dart';
|
import 'package:examples/stories/bridge_libraries/forge2d/sprite_body_example.dart';
|
||||||
@ -159,5 +160,11 @@ void addJointsStories(Dashbook dashbook) {
|
|||||||
(DashbookContext ctx) => GameWidget(game: RevoluteJointExample()),
|
(DashbookContext ctx) => GameWidget(game: RevoluteJointExample()),
|
||||||
codeLink: link('revolute_joint.dart'),
|
codeLink: link('revolute_joint.dart'),
|
||||||
info: RevoluteJointExample.description,
|
info: RevoluteJointExample.description,
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
'RopeJoint',
|
||||||
|
(DashbookContext ctx) => GameWidget(game: RopeJointExample()),
|
||||||
|
codeLink: link('rope_joint.dart'),
|
||||||
|
info: RopeJointExample.description,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,79 @@
|
|||||||
|
import 'package:examples/stories/bridge_libraries/forge2d/utils/balls.dart';
|
||||||
|
import 'package:examples/stories/bridge_libraries/forge2d/utils/boxes.dart';
|
||||||
|
import 'package:flame/events.dart';
|
||||||
|
import 'package:flame/input.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class RopeJointExample extends Forge2DGame with TapDetector, HasDraggables {
|
||||||
|
static const description = '''
|
||||||
|
This example shows how to use a `RopeJoint`.
|
||||||
|
|
||||||
|
Drag the box handle along the axis and observe the rope respond to the
|
||||||
|
movement
|
||||||
|
''';
|
||||||
|
|
||||||
|
double handleWidth = 6;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
super.onLoad();
|
||||||
|
|
||||||
|
final handleBody = await createHandle();
|
||||||
|
createRope(handleBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Body> createHandle() async {
|
||||||
|
final anchor = Vector2(size.x / 2, 5);
|
||||||
|
|
||||||
|
final box =
|
||||||
|
DraggableBox(startPosition: anchor, width: handleWidth, height: 3);
|
||||||
|
await add(box);
|
||||||
|
|
||||||
|
createPrismaticJoint(box.body, anchor);
|
||||||
|
return box.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> createRope(Body handle) async {
|
||||||
|
const length = 50;
|
||||||
|
var prevBody = handle;
|
||||||
|
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
final newPosition = prevBody.worldCenter + Vector2(0, 1);
|
||||||
|
final ball = Ball(newPosition, radius: 0.5, color: Colors.white);
|
||||||
|
await add(ball);
|
||||||
|
|
||||||
|
createRopeJoint(ball.body, prevBody);
|
||||||
|
prevBody = ball.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createPrismaticJoint(Body box, Vector2 anchor) {
|
||||||
|
final groundBody = world.createBody(BodyDef());
|
||||||
|
|
||||||
|
final prismaticJointDef = PrismaticJointDef()
|
||||||
|
..initialize(
|
||||||
|
box,
|
||||||
|
groundBody,
|
||||||
|
anchor,
|
||||||
|
Vector2(1, 0),
|
||||||
|
)
|
||||||
|
..enableLimit = true
|
||||||
|
..lowerTranslation = -size.x / 2 + handleWidth / 2
|
||||||
|
..upperTranslation = size.x / 2 - handleWidth / 2;
|
||||||
|
|
||||||
|
final joint = PrismaticJoint(prismaticJointDef);
|
||||||
|
world.createJoint(joint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createRopeJoint(Body first, Body second) {
|
||||||
|
final ropeJointDef = RopeJointDef()
|
||||||
|
..bodyA = first
|
||||||
|
..localAnchorA.setFrom(first.getLocalCenter())
|
||||||
|
..bodyB = second
|
||||||
|
..localAnchorB.setFrom(second.getLocalCenter())
|
||||||
|
..maxLength = (second.worldCenter - first.worldCenter).length;
|
||||||
|
|
||||||
|
world.createJoint(RopeJoint(ropeJointDef));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,8 +14,17 @@ class Ball extends BodyComponent with ContactCallbacks {
|
|||||||
|
|
||||||
final Paint _blue = BasicPalette.blue.paint();
|
final Paint _blue = BasicPalette.blue.paint();
|
||||||
|
|
||||||
Ball(this._position, {this.radius = 2, this.bodyType = BodyType.dynamic}) {
|
Ball(
|
||||||
originalPaint = randomPaint();
|
this._position, {
|
||||||
|
this.radius = 2,
|
||||||
|
this.bodyType = BodyType.dynamic,
|
||||||
|
Color? color,
|
||||||
|
}) {
|
||||||
|
if (color != null) {
|
||||||
|
originalPaint = PaletteEntry(color).paint();
|
||||||
|
} else {
|
||||||
|
originalPaint = randomPaint();
|
||||||
|
}
|
||||||
paint = originalPaint;
|
paint = originalPaint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user