docs: WeldJoint docs and example (#2525)

WeldJoint docs and example
This commit is contained in:
Eugene Kleshnin
2023-05-01 19:22:28 +01:00
committed by GitHub
parent 0b68be8a6f
commit 472356df31
5 changed files with 134 additions and 2 deletions

View File

@ -27,7 +27,7 @@ Currently, Forge2D supports the following joints:
- [`PulleyJoint`](#pulleyjoint) - [`PulleyJoint`](#pulleyjoint)
- [`RevoluteJoint`](#revolutejoint) - [`RevoluteJoint`](#revolutejoint)
- [`RopeJoint`](#ropejoint) - [`RopeJoint`](#ropejoint)
- WeldJoint - [`WeldJoint`](#weldjoint)
- WheelJoint - WheelJoint
@ -599,3 +599,38 @@ will have no effect.
The joint assumes that the maximum length doesn't change during simulation. The joint assumes that the maximum length doesn't change during simulation.
See `DistanceJoint` if you want to dynamically control length. See `DistanceJoint` if you want to dynamically control length.
``` ```
### `WeldJoint`
A `WeldJoint` is used to restrict all relative motion between two bodies, effectively joining them
together.
`WeldJointDef` requires two bodies that will be connected, and a world anchor:
```dart
final weldJointDef = WeldJointDef()
..initialize(bodyA, bodyB, anchor);
world.createJoint(WeldJoint(weldJointDef));
```
```{flutter-app}
:sources: ../../examples
:page: weld_joint
:subfolder: stories/bridge_libraries/forge2d/joints
:show: code popup
```
- `bodyA`, `bodyB`: Two bodies that will be connected
- `anchor`: Anchor point in world coordinates, at which two bodies will be welded together
to 0, the higher the value, the less springy the joint becomes.
#### Breakable Bodies and WeldJoint
Since the Forge2D constraint solver is iterative, joints are somewhat flexible. This means that the
bodies connected by a WeldJoint may bend slightly. If you want to simulate a breakable body, it's
better to create a single body with multiple fixtures. When the body breaks, you can destroy a
fixture and recreate it on a new body instead of relying on a `WeldJoint`.

View File

@ -16,6 +16,7 @@ import 'package:examples/stories/bridge_libraries/forge2d/joints/prismatic_joint
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/joints/rope_joint.dart';
import 'package:examples/stories/bridge_libraries/forge2d/joints/weld_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';
@ -50,6 +51,7 @@ void main() {
'prismatic_joint': PrismaticJointExample.new, 'prismatic_joint': PrismaticJointExample.new,
'revolute_joint': RevoluteJointExample.new, 'revolute_joint': RevoluteJointExample.new,
'rope_joint': RopeJointExample.new, 'rope_joint': RopeJointExample.new,
'weld_joint': WeldJointExample.new,
}; };
final game = routes[page]?.call(); final game = routes[page]?.call();
if (game != null) { if (game != null) {

View File

@ -17,6 +17,7 @@ import 'package:examples/stories/bridge_libraries/forge2d/joints/prismatic_joint
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/joints/rope_joint.dart';
import 'package:examples/stories/bridge_libraries/forge2d/joints/weld_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';
@ -166,5 +167,11 @@ void addJointsStories(Dashbook dashbook) {
(DashbookContext ctx) => GameWidget(game: RopeJointExample()), (DashbookContext ctx) => GameWidget(game: RopeJointExample()),
codeLink: link('rope_joint.dart'), codeLink: link('rope_joint.dart'),
info: RopeJointExample.description, info: RopeJointExample.description,
)
.add(
'WeldJoint',
(DashbookContext ctx) => GameWidget(game: WeldJointExample()),
codeLink: link('weld_joint.dart'),
info: WeldJointExample.description,
); );
} }

View File

@ -0,0 +1,75 @@
import 'package:examples/stories/bridge_libraries/forge2d/utils/balls.dart';
import 'package:examples/stories/bridge_libraries/forge2d/utils/boxes.dart';
import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
class WeldJointExample extends Forge2DGame with TapDetector {
static const description = '''
This example shows how to use a `WeldJoint`. Tap the screen to add a
ball to test the bridge built using a `WeldJoint`
''';
@override
Future<void> onLoad() async {
super.onLoad();
const pillarHeight = 20.0;
final leftPillar = Box(
startPosition: Vector2(10, size.y - pillarHeight / 2),
width: 5,
height: pillarHeight,
bodyType: BodyType.static,
color: Colors.white,
);
final rightPillar = Box(
startPosition: Vector2(size.x - 10, size.y - pillarHeight / 2),
width: 5,
height: pillarHeight,
bodyType: BodyType.static,
color: Colors.white,
);
addAll([leftPillar, rightPillar]);
createBridge(size.y - pillarHeight);
}
Future<void> createBridge(double positionY) async {
const sectionsCount = 10;
final sectionWidth = (size.x / sectionsCount).ceilToDouble();
Body? prevSection;
for (var i = 0; i < sectionsCount; i++) {
final section = Box(
startPosition: Vector2(sectionWidth * i, positionY),
width: sectionWidth,
height: 1,
);
await add(section);
if (prevSection != null) {
createJoint(
prevSection,
section.body,
Vector2(sectionWidth * i + sectionWidth, positionY),
);
}
prevSection = section.body;
}
}
void createJoint(Body first, Body second, Vector2 anchor) {
final weldJointDef = WeldJointDef()..initialize(first, second, anchor);
world.createJoint(WeldJoint(weldJointDef));
}
@override
Future<void> onTapDown(TapDownInfo info) async {
super.onTapDown(info);
final ball = Ball(info.eventPosition.game, radius: 5);
add(ball);
}
}

View File

@ -1,5 +1,9 @@
import 'dart:ui';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/events.dart'; import 'package:flame/events.dart';
import 'package:flame/extensions.dart';
import 'package:flame/palette.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
class Box extends BodyComponent { class Box extends BodyComponent {
@ -13,7 +17,16 @@ class Box extends BodyComponent {
required this.width, required this.width,
required this.height, required this.height,
this.bodyType = BodyType.dynamic, this.bodyType = BodyType.dynamic,
}); Color? color,
}) {
if (color != null) {
paint = PaletteEntry(color).paint();
} else {
paint = randomPaint();
}
}
Paint randomPaint() => PaintExtension.random(withAlpha: 0.9, base: 100);
@override @override
Body createBody() { Body createBody() {