mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +08:00
docs: Move flame_forge2d examples to main examples (#1588)
This commit is contained in:
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -2,6 +2,7 @@ import 'package:dashbook/dashbook.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'stories/animations/animations.dart';
|
||||
import 'stories/bridge_libraries/forge2d/flame_forge2d.dart';
|
||||
import 'stories/camera_and_viewport/camera_and_viewport.dart';
|
||||
import 'stories/collision_detection/collision_detection.dart';
|
||||
import 'stories/components/components.dart';
|
||||
@ -37,5 +38,8 @@ void main() async {
|
||||
addUtilsStories(dashbook);
|
||||
addWidgetsStories(dashbook);
|
||||
|
||||
// Bridge package examples
|
||||
addForge2DStories(dashbook);
|
||||
|
||||
runApp(dashbook);
|
||||
}
|
||||
|
||||
@ -4,7 +4,51 @@ import 'package:flame/components.dart';
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'boundaries.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class AnimatedBodyExample extends Forge2DGame with TapDetector {
|
||||
static const String description = '''
|
||||
In this example we show how to add an animated chopper, which is created
|
||||
with a SpriteAnimationComponent, on top of a BodyComponent.
|
||||
|
||||
Tap the screen to add more choppers.
|
||||
''';
|
||||
|
||||
AnimatedBodyExample() : super(gravity: Vector2.zero());
|
||||
|
||||
late Image chopper;
|
||||
late SpriteAnimation animation;
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
chopper = await images.load('animations/chopper.png');
|
||||
|
||||
animation = SpriteAnimation.fromFrameData(
|
||||
chopper,
|
||||
SpriteAnimationData.sequenced(
|
||||
amount: 4,
|
||||
textureSize: Vector2.all(48),
|
||||
stepTime: 0.15,
|
||||
),
|
||||
);
|
||||
|
||||
final boundaries = createBoundaries(this);
|
||||
boundaries.forEach(add);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final position = details.eventPosition.game;
|
||||
final spriteSize = Vector2.all(10);
|
||||
final animationComponent = SpriteAnimationComponent(
|
||||
animation: animation,
|
||||
size: spriteSize,
|
||||
anchor: Anchor.center,
|
||||
);
|
||||
add(ChopperBody(position, animationComponent));
|
||||
}
|
||||
}
|
||||
|
||||
class ChopperBody extends BodyComponent {
|
||||
final Vector2 position;
|
||||
@ -39,40 +83,3 @@ class ChopperBody extends BodyComponent {
|
||||
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||
}
|
||||
}
|
||||
|
||||
class PositionBodySample extends Forge2DGame with TapDetector {
|
||||
late Image chopper;
|
||||
late SpriteAnimation animation;
|
||||
|
||||
PositionBodySample() : super(gravity: Vector2.zero());
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
chopper = await images.load('chopper.png');
|
||||
|
||||
animation = SpriteAnimation.fromFrameData(
|
||||
chopper,
|
||||
SpriteAnimationData.sequenced(
|
||||
amount: 4,
|
||||
textureSize: Vector2.all(48),
|
||||
stepTime: 0.15,
|
||||
),
|
||||
);
|
||||
|
||||
final boundaries = createBoundaries(this);
|
||||
boundaries.forEach(add);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final position = details.eventPosition.game;
|
||||
final spriteSize = Vector2.all(10);
|
||||
final animationComponent = SpriteAnimationComponent(
|
||||
animation: animation,
|
||||
size: spriteSize,
|
||||
anchor: Anchor.center,
|
||||
);
|
||||
add(ChopperBody(position, animationComponent));
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,40 @@ import 'dart:math' as math;
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'boundaries.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class BlobExample extends Forge2DGame with TapDetector {
|
||||
static const String description = '''
|
||||
In this example we show the power of joints by showing interactions between
|
||||
bodies tied together.
|
||||
|
||||
Tap the screen to add boxes that will bounce on the "blob" in the center.
|
||||
''';
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final worldCenter = screenToWorld(size * camera.zoom / 2);
|
||||
final blobCenter = worldCenter + Vector2(0, -30);
|
||||
final blobRadius = Vector2.all(6.0);
|
||||
addAll(createBoundaries(this));
|
||||
add(Ground(worldCenter));
|
||||
final jointDef = ConstantVolumeJointDef()
|
||||
..frequencyHz = 20.0
|
||||
..dampingRatio = 1.0
|
||||
..collideConnected = false;
|
||||
|
||||
await addAll([
|
||||
for (var i = 0; i < 20; i++) BlobPart(i, jointDef, blobRadius, blobCenter)
|
||||
]);
|
||||
world.createJoint(ConstantVolumeJoint(world, jointDef));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
add(FallingBox(details.eventPosition.game));
|
||||
}
|
||||
}
|
||||
|
||||
class Ground extends BodyComponent {
|
||||
final Vector2 worldCenter;
|
||||
@ -14,15 +47,16 @@ class Ground extends BodyComponent {
|
||||
Body createBody() {
|
||||
final shape = PolygonShape();
|
||||
shape.setAsBoxXY(20.0, 0.4);
|
||||
final fixtureDef = FixtureDef(shape, friction: 0.2);
|
||||
|
||||
final bodyDef = BodyDef(position: worldCenter.clone());
|
||||
final ground = world.createBody(bodyDef);
|
||||
ground.createFixtureFromShape(shape);
|
||||
ground.createFixture(fixtureDef);
|
||||
|
||||
shape.setAsBox(0.4, 20.0, Vector2(-10.0, 0.0), 0.0);
|
||||
ground.createFixtureFromShape(shape);
|
||||
ground.createFixture(fixtureDef);
|
||||
shape.setAsBox(0.4, 20.0, Vector2(10.0, 0.0), 0.0);
|
||||
ground.createFixtureFromShape(shape);
|
||||
ground.createFixture(fixtureDef);
|
||||
return ground;
|
||||
}
|
||||
}
|
||||
@ -59,7 +93,7 @@ class BlobPart extends BodyComponent {
|
||||
final fixtureDef = FixtureDef(
|
||||
shape,
|
||||
density: 1.0,
|
||||
filter: Filter()..groupIndex = -2,
|
||||
friction: 0.2,
|
||||
);
|
||||
body.createFixture(fixtureDef);
|
||||
jointDef.addBody(body);
|
||||
@ -84,29 +118,3 @@ class FallingBox extends BodyComponent {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
class BlobSample extends Forge2DGame with TapDetector {
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final worldCenter = screenToWorld(size * camera.zoom / 2);
|
||||
final blobCenter = worldCenter + Vector2(0, -30);
|
||||
final blobRadius = Vector2.all(6.0);
|
||||
addAll(createBoundaries(this));
|
||||
add(Ground(worldCenter));
|
||||
final jointDef = ConstantVolumeJointDef()
|
||||
..frequencyHz = 20.0
|
||||
..dampingRatio = 1.0
|
||||
..collideConnected = false;
|
||||
|
||||
await addAll([
|
||||
for (var i = 0; i < 20; i++) BlobPart(i, jointDef, blobRadius, blobCenter)
|
||||
]);
|
||||
world.createJoint(ConstantVolumeJoint(world, jointDef));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
add(FallingBox(details.eventPosition.game));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'domino_example.dart';
|
||||
import 'sprite_body_example.dart';
|
||||
|
||||
class CameraExample extends DominoExample {
|
||||
static const String description = '''
|
||||
This example showcases the possibility to follow BodyComponents with the
|
||||
camera. When the screen is tapped a pizza is added, which the camera will
|
||||
follow. Other than that it is the same as the domino example.
|
||||
''';
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
final position = details.eventPosition.game;
|
||||
final pizza = Pizza(position);
|
||||
add(pizza);
|
||||
pizza.mounted.whenComplete(() => camera.followBodyComponent(pizza));
|
||||
}
|
||||
}
|
||||
@ -5,18 +5,18 @@ import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
const TextStyle _textStyle = TextStyle(color: Colors.white, fontSize: 2);
|
||||
|
||||
class CompositionSample extends Forge2DGame with HasTappables {
|
||||
static const info = '''
|
||||
This example shows how to compose a `BodyComponent` together with a normal Flame
|
||||
component. Click the ball to see the number increment.
|
||||
class CompositionExample extends Forge2DGame with HasTappables {
|
||||
static const description = '''
|
||||
This example shows how to compose a `BodyComponent` together with a normal
|
||||
Flame component. Click the ball to see the number increment.
|
||||
''';
|
||||
|
||||
CompositionSample() : super(zoom: 20, gravity: Vector2(0, 10.0));
|
||||
CompositionExample() : super(zoom: 20, gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
@ -3,17 +3,18 @@ import 'dart:math' as math;
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class ContactCallbacksSample extends Forge2DGame with TapDetector {
|
||||
static const info = '''
|
||||
class ContactCallbacksExample extends Forge2DGame with TapDetector {
|
||||
static const description = '''
|
||||
This example shows how `BodyComponent`s can react to collisions with other
|
||||
bodies.
|
||||
Tap the screen to add balls, the white balls will give an impulse to the balls
|
||||
that it collides with.
|
||||
Tap the screen to add balls, the white balls will give an impulse to the
|
||||
balls that it collides with.
|
||||
''';
|
||||
ContactCallbacksSample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
ContactCallbacksExample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
@ -3,8 +3,49 @@ import 'dart:ui';
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'boundaries.dart';
|
||||
import 'sprite_body_sample.dart';
|
||||
import 'sprite_body_example.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class DominoExample extends Forge2DGame with TapDetector {
|
||||
static const description = '''
|
||||
In this example we can see some domino tiles lined up.
|
||||
If you tap on the screen a pizza is added which can tip the tiles over and
|
||||
cause a chain reaction.
|
||||
''';
|
||||
|
||||
DominoExample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
late Image pizzaImage;
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final boundaries = createBoundaries(this);
|
||||
boundaries.forEach(add);
|
||||
final center = screenToWorld(camera.viewport.effectiveSize / 2);
|
||||
|
||||
const numberOfRows = 7;
|
||||
for (var i = 0; i < numberOfRows - 2; i++) {
|
||||
final position = center + Vector2(0.0, 5.0 * i);
|
||||
add(Platform(position));
|
||||
}
|
||||
|
||||
const numberPerRow = 25;
|
||||
for (var i = 0; i < numberOfRows; ++i) {
|
||||
for (var j = 0; j < numberPerRow; j++) {
|
||||
final position = center +
|
||||
Vector2(-14.75 + j * (29.5 / (numberPerRow - 1)), -12.7 + 5 * i);
|
||||
add(DominoBrick(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final position = details.eventPosition.game;
|
||||
add(Pizza(position)..renderBody = true);
|
||||
}
|
||||
}
|
||||
|
||||
class Platform extends BodyComponent {
|
||||
final Vector2 position;
|
||||
@ -41,38 +82,3 @@ class DominoBrick extends BodyComponent {
|
||||
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||
}
|
||||
}
|
||||
|
||||
class DominoSample extends Forge2DGame with TapDetector {
|
||||
late Image pizzaImage;
|
||||
|
||||
DominoSample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final boundaries = createBoundaries(this);
|
||||
boundaries.forEach(add);
|
||||
final center = screenToWorld(camera.viewport.effectiveSize / 2);
|
||||
|
||||
const numberOfRows = 7;
|
||||
for (var i = 0; i < numberOfRows - 2; i++) {
|
||||
final position = center + Vector2(0.0, 5.0 * i);
|
||||
add(Platform(position));
|
||||
}
|
||||
|
||||
const numberPerRow = 25;
|
||||
for (var i = 0; i < numberOfRows; ++i) {
|
||||
for (var j = 0; j < numberPerRow; j++) {
|
||||
final position = center +
|
||||
Vector2(-14.75 + j * (29.5 / (numberPerRow - 1)), -12.7 + 5 * i);
|
||||
add(DominoBrick(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final position = details.eventPosition.game;
|
||||
add(Pizza(position)..renderBody = true);
|
||||
}
|
||||
}
|
||||
@ -4,11 +4,17 @@ import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:flutter/material.dart' hide Draggable;
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class DraggableSample extends Forge2DGame with HasDraggables {
|
||||
DraggableSample() : super(gravity: Vector2.all(0.0));
|
||||
class DraggableExample extends Forge2DGame with HasDraggables {
|
||||
static const description = '''
|
||||
In this example we use Flame's normal `Draggable` mixin to give impulses to
|
||||
a ball when we are dragging it around. If you are interested in dragging
|
||||
bodies around, also have a look at the MouseJointExample.
|
||||
''';
|
||||
|
||||
DraggableExample() : super(gravity: Vector2.all(0.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
108
examples/lib/stories/bridge_libraries/forge2d/flame_forge2d.dart
Normal file
108
examples/lib/stories/bridge_libraries/forge2d/flame_forge2d.dart
Normal file
@ -0,0 +1,108 @@
|
||||
import 'package:dashbook/dashbook.dart';
|
||||
import 'package:flame/game.dart';
|
||||
|
||||
import '../../../commons/commons.dart';
|
||||
import 'animated_body_example.dart';
|
||||
import 'blob_example.dart';
|
||||
import 'camera_example.dart';
|
||||
import 'composition_example.dart';
|
||||
import 'contact_callbacks_example.dart';
|
||||
import 'domino_example.dart';
|
||||
import 'draggable_example.dart';
|
||||
import 'joint_example.dart';
|
||||
import 'mouse_joint_example.dart';
|
||||
import 'raycast_example.dart';
|
||||
import 'revolute_joint_example.dart';
|
||||
import 'sprite_body_example.dart';
|
||||
import 'tappable_example.dart';
|
||||
import 'widget_example.dart';
|
||||
|
||||
String link(String example) => baseLink('bride_libraries/$example');
|
||||
|
||||
void addForge2DStories(Dashbook dashbook) {
|
||||
dashbook.storiesOf('flame_forge2d')
|
||||
..add(
|
||||
'Blob example',
|
||||
(DashbookContext ctx) => GameWidget(game: BlobExample()),
|
||||
codeLink: link('blob_example.dart'),
|
||||
info: BlobExample.description,
|
||||
)
|
||||
..add(
|
||||
'Composition example',
|
||||
(DashbookContext ctx) => GameWidget(game: CompositionExample()),
|
||||
codeLink: link('composition_example.dart'),
|
||||
info: CompositionExample.description,
|
||||
)
|
||||
..add(
|
||||
'Domino example',
|
||||
(DashbookContext ctx) => GameWidget(game: DominoExample()),
|
||||
codeLink: link('domino_example.dart'),
|
||||
info: DominoExample.description,
|
||||
)
|
||||
..add(
|
||||
'Contact Callbacks',
|
||||
(DashbookContext ctx) => GameWidget(game: ContactCallbacksExample()),
|
||||
codeLink: link('contact_callbacks_example.dart'),
|
||||
info: ContactCallbacksExample.description,
|
||||
)
|
||||
..add(
|
||||
'RevoluteJoint',
|
||||
(DashbookContext ctx) => GameWidget(game: RevoluteJointExample()),
|
||||
codeLink: link('revolute_joint_example.dart'),
|
||||
info: RevoluteJointExample.description,
|
||||
)
|
||||
..add(
|
||||
'Sprite Bodies',
|
||||
(DashbookContext ctx) => GameWidget(game: SpriteBodyExample()),
|
||||
codeLink: link('sprite_body_example.dart'),
|
||||
info: SpriteBodyExample.description,
|
||||
)
|
||||
..add(
|
||||
'Animated Bodies',
|
||||
(DashbookContext ctx) => GameWidget(game: AnimatedBodyExample()),
|
||||
codeLink: link('animated_body_example.dart'),
|
||||
info: AnimatedBodyExample.description,
|
||||
)
|
||||
..add(
|
||||
'Tappable Body',
|
||||
(DashbookContext ctx) => GameWidget(game: TappableExample()),
|
||||
codeLink: link('tappable_example.dart'),
|
||||
info: TappableExample.description,
|
||||
)
|
||||
..add(
|
||||
'Draggable Body',
|
||||
(DashbookContext ctx) => GameWidget(game: DraggableExample()),
|
||||
codeLink: link('draggable_example.dart'),
|
||||
info: DraggableExample.description,
|
||||
)
|
||||
..add(
|
||||
'Basic joint',
|
||||
(DashbookContext ctx) => GameWidget(game: JointExample()),
|
||||
codeLink: link('joint_example.dart'),
|
||||
info: JointExample.description,
|
||||
)
|
||||
..add(
|
||||
'Mouse Joint',
|
||||
(DashbookContext ctx) => GameWidget(game: MouseJointExample()),
|
||||
codeLink: link('mouse_joint_example.dart'),
|
||||
info: MouseJointExample.description,
|
||||
)
|
||||
..add(
|
||||
'Camera',
|
||||
(DashbookContext ctx) => GameWidget(game: CameraExample()),
|
||||
codeLink: link('camera_example.dart'),
|
||||
info: CameraExample.description,
|
||||
)
|
||||
..add(
|
||||
'Raycasting',
|
||||
(DashbookContext ctx) => GameWidget(game: RaycastExample()),
|
||||
codeLink: link('raycast_example.dart'),
|
||||
info: RaycastExample.description,
|
||||
)
|
||||
..add(
|
||||
'Widgets',
|
||||
(DashbookContext ctx) => const BodyWidgetExample(),
|
||||
codeLink: link('widget_example.dart'),
|
||||
info: WidgetExample.description,
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// ignore_for_file: directives_ordering
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
import 'package:shared_preferences_web/shared_preferences_web.dart';
|
||||
import 'package:url_launcher_web/url_launcher_web.dart';
|
||||
|
||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||
|
||||
// ignore: public_member_api_docs
|
||||
void registerPlugins(Registrar registrar) {
|
||||
SharedPreferencesPlugin.registerWith(registrar);
|
||||
UrlLauncherPlugin.registerWith(registrar);
|
||||
registrar.registerMessageHandler();
|
||||
}
|
||||
@ -3,8 +3,32 @@ import 'dart:math';
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class JointExample extends Forge2DGame with TapDetector {
|
||||
static const description = '''
|
||||
In this example we use a joint to keep a body with several fixtures stuck
|
||||
to another body.
|
||||
|
||||
Tap the screen to add more of these combined bodies.
|
||||
''';
|
||||
|
||||
JointExample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
addAll(createBoundaries(this));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final ball = Ball(details.eventPosition.game);
|
||||
add(ball);
|
||||
add(CircleShuffler(ball));
|
||||
}
|
||||
}
|
||||
|
||||
class CircleShuffler extends BodyComponent {
|
||||
final Ball ball;
|
||||
@ -39,27 +63,10 @@ class CircleShuffler extends BodyComponent {
|
||||
body.createFixture(fixtureDef);
|
||||
}
|
||||
|
||||
final revoluteJointDef = RevoluteJointDef()
|
||||
final jointDef = RevoluteJointDef()
|
||||
..initialize(body, ball.body, body.position);
|
||||
world.createJoint(RevoluteJoint(jointDef));
|
||||
|
||||
world.createJoint(RevoluteJoint(revoluteJointDef));
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
class JointSample extends Forge2DGame with TapDetector {
|
||||
JointSample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
addAll(createBoundaries(this));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final ball = Ball(details.eventPosition.game);
|
||||
add(ball);
|
||||
add(CircleShuffler(ball));
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,22 @@
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'circle_stress_sample.dart';
|
||||
import 'revolute_joint_example.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class MouseJointExample extends Forge2DGame with MultiTouchDragDetector {
|
||||
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));
|
||||
|
||||
class MouseJointSample extends Forge2DGame with MultiTouchDragDetector {
|
||||
late Ball ball;
|
||||
late Body groundBody;
|
||||
MouseJoint? mouseJoint;
|
||||
|
||||
MouseJointSample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final boundaries = createBoundaries(this);
|
||||
@ -4,80 +4,16 @@ import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:flutter/material.dart' show Colors, Paint, Canvas;
|
||||
|
||||
import 'boundaries.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
const raycastSampleDescription = '''
|
||||
This example shows how raycasts can be used to find nearest and farthest fixtures.
|
||||
class RaycastExample extends Forge2DGame
|
||||
with TapDetector, MouseMovementDetector {
|
||||
static const String description = '''
|
||||
This example shows how raycasts can be used to find nearest and farthest
|
||||
fixtures.
|
||||
Red ray finds the nearest fixture and blue ray finds the farthest fixture.
|
||||
''';
|
||||
|
||||
class Box extends BodyComponent {
|
||||
final Vector2 position;
|
||||
|
||||
Box(this.position);
|
||||
|
||||
@override
|
||||
Body createBody() {
|
||||
final shape = PolygonShape()..setAsBoxXY(2.0, 4.0);
|
||||
final fixtureDef = FixtureDef(shape, userData: this);
|
||||
final bodyDef = BodyDef(position: position);
|
||||
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||
}
|
||||
}
|
||||
|
||||
class NearestBoxRayCastCallback extends RayCastCallback {
|
||||
Box? box;
|
||||
Vector2? nearestPoint;
|
||||
Vector2? normalAtInter;
|
||||
|
||||
@override
|
||||
double reportFixture(
|
||||
Fixture fixture,
|
||||
Vector2 point,
|
||||
Vector2 normal,
|
||||
double fraction,
|
||||
) {
|
||||
nearestPoint = point.clone();
|
||||
normalAtInter = normal.clone();
|
||||
box = fixture.userData as Box?;
|
||||
|
||||
// Returning fraction implies that we care only about
|
||||
// fixtures that are closer to ray start point than
|
||||
// the current fixture
|
||||
return fraction;
|
||||
}
|
||||
}
|
||||
|
||||
class FarthestBoxRayCastCallback extends RayCastCallback {
|
||||
Box? box;
|
||||
Vector2? farthestPoint;
|
||||
Vector2? normalAtInter;
|
||||
double previousFraction = 0.0;
|
||||
|
||||
@override
|
||||
double reportFixture(
|
||||
Fixture fixture,
|
||||
Vector2 point,
|
||||
Vector2 normal,
|
||||
double fraction,
|
||||
) {
|
||||
// Value of fraction is directly proportional to
|
||||
// the distance of fixture from ray start point.
|
||||
// So we are interested in the current fixture only if
|
||||
// it has a higher fraction value than previousFraction.
|
||||
if (previousFraction < fraction) {
|
||||
farthestPoint = point.clone();
|
||||
normalAtInter = normal.clone();
|
||||
box = fixture.userData as Box?;
|
||||
previousFraction = fraction;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
class RaycastSample extends Forge2DGame
|
||||
with TapDetector, MouseMovementDetector {
|
||||
final random = Random();
|
||||
|
||||
final redPoints = List<Vector2>.empty(growable: true);
|
||||
@ -86,7 +22,7 @@ class RaycastSample extends Forge2DGame
|
||||
Box? nearestBox;
|
||||
Box? farthestBox;
|
||||
|
||||
RaycastSample() : super(gravity: Vector2.zero());
|
||||
RaycastExample() : super(gravity: Vector2.zero());
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
@ -192,3 +128,68 @@ class RaycastSample extends Forge2DGame
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Box extends BodyComponent {
|
||||
final Vector2 position;
|
||||
|
||||
Box(this.position);
|
||||
|
||||
@override
|
||||
Body createBody() {
|
||||
final shape = PolygonShape()..setAsBoxXY(2.0, 4.0);
|
||||
final fixtureDef = FixtureDef(shape, userData: this);
|
||||
final bodyDef = BodyDef(position: position);
|
||||
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||
}
|
||||
}
|
||||
|
||||
class NearestBoxRayCastCallback extends RayCastCallback {
|
||||
Box? box;
|
||||
Vector2? nearestPoint;
|
||||
Vector2? normalAtInter;
|
||||
|
||||
@override
|
||||
double reportFixture(
|
||||
Fixture fixture,
|
||||
Vector2 point,
|
||||
Vector2 normal,
|
||||
double fraction,
|
||||
) {
|
||||
nearestPoint = point.clone();
|
||||
normalAtInter = normal.clone();
|
||||
box = fixture.userData as Box?;
|
||||
|
||||
// Returning fraction implies that we care only about
|
||||
// fixtures that are closer to ray start point than
|
||||
// the current fixture
|
||||
return fraction;
|
||||
}
|
||||
}
|
||||
|
||||
class FarthestBoxRayCastCallback extends RayCastCallback {
|
||||
Box? box;
|
||||
Vector2? farthestPoint;
|
||||
Vector2? normalAtInter;
|
||||
double previousFraction = 0.0;
|
||||
|
||||
@override
|
||||
double reportFixture(
|
||||
Fixture fixture,
|
||||
Vector2 point,
|
||||
Vector2 normal,
|
||||
double fraction,
|
||||
) {
|
||||
// Value of fraction is directly proportional to
|
||||
// the distance of fixture from ray start point.
|
||||
// So we are interested in the current fixture only if
|
||||
// it has a higher fraction value than previousFraction.
|
||||
if (previousFraction < fraction) {
|
||||
farthestPoint = point.clone();
|
||||
normalAtInter = normal.clone();
|
||||
box = fixture.userData as Box?;
|
||||
previousFraction = fraction;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -3,19 +3,51 @@ import 'dart:math';
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class RevoluteJointExample extends Forge2DGame with TapDetector {
|
||||
static const String description = '''
|
||||
This example showcases a revolute joint, which is the spinning balls in the
|
||||
center.
|
||||
|
||||
If you tap the screen some colourful balls are added and will
|
||||
interact with the bodies tied to the revolute joint once they have fallen
|
||||
down the funnel.
|
||||
''';
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final boundaries = createBoundaries(this);
|
||||
boundaries.forEach(add);
|
||||
final center = screenToWorld(camera.viewport.effectiveSize / 2);
|
||||
add(CircleShuffler(center));
|
||||
add(CornerRamp(center, isMirrored: true));
|
||||
add(CornerRamp(center));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final tapPosition = details.eventPosition.game;
|
||||
final random = Random();
|
||||
List.generate(15, (i) {
|
||||
final randomVector = (Vector2.random() - Vector2.all(-0.5)).normalized();
|
||||
add(Ball(tapPosition + randomVector, radius: random.nextDouble()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class CircleShuffler extends BodyComponent {
|
||||
final Vector2 _center;
|
||||
|
||||
CircleShuffler(this._center);
|
||||
|
||||
final Vector2 _center;
|
||||
|
||||
@override
|
||||
Body createBody() {
|
||||
final bodyDef = BodyDef(
|
||||
type: BodyType.dynamic,
|
||||
position: _center + Vector2(0.0, -25.0),
|
||||
position: _center + Vector2(0.0, 25.0),
|
||||
);
|
||||
const numPieces = 5;
|
||||
const radius = 6.0;
|
||||
@ -53,11 +85,11 @@ class CircleShuffler extends BodyComponent {
|
||||
}
|
||||
|
||||
class CornerRamp extends BodyComponent {
|
||||
CornerRamp(this._center, {this.isMirrored = false});
|
||||
|
||||
final bool isMirrored;
|
||||
final Vector2 _center;
|
||||
|
||||
CornerRamp(this._center, {this.isMirrored = false});
|
||||
|
||||
@override
|
||||
Body createBody() {
|
||||
final shape = ChainShape();
|
||||
@ -78,26 +110,3 @@ class CornerRamp extends BodyComponent {
|
||||
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||
}
|
||||
}
|
||||
|
||||
class CircleStressSample extends Forge2DGame with TapDetector {
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
final boundaries = createBoundaries(this);
|
||||
boundaries.forEach(add);
|
||||
final center = screenToWorld(camera.viewport.effectiveSize / 2);
|
||||
add(CircleShuffler(center));
|
||||
add(CornerRamp(center, isMirrored: true));
|
||||
add(CornerRamp(center));
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
super.onTapDown(details);
|
||||
final tapPosition = details.eventPosition.game;
|
||||
final random = Random();
|
||||
List.generate(15, (i) {
|
||||
final randomVector = (Vector2.random() - Vector2.all(-0.5)).normalized();
|
||||
add(Ball(tapPosition + randomVector, radius: random.nextDouble()));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -4,10 +4,15 @@ import 'package:flame/components.dart';
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'boundaries.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class SpriteBodySample extends Forge2DGame with TapDetector {
|
||||
SpriteBodySample() : super(gravity: Vector2(0, 10.0));
|
||||
class SpriteBodyExample extends Forge2DGame with TapDetector {
|
||||
static const String description = '''
|
||||
In this example we show how to add a sprite on top of a `BodyComponent`.
|
||||
Tap the screen to add more pizzas.
|
||||
''';
|
||||
|
||||
SpriteBodyExample() : super(gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
@ -3,11 +3,17 @@ import 'package:flame/game.dart';
|
||||
import 'package:flame/palette.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'balls.dart';
|
||||
import 'boundaries.dart';
|
||||
import 'utils/balls.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
class TappableSample extends Forge2DGame with HasTappables {
|
||||
TappableSample() : super(zoom: 20, gravity: Vector2(0, 10.0));
|
||||
class TappableExample extends Forge2DGame with HasTappables {
|
||||
static const String description = '''
|
||||
In this example we show how to use Flame's tappable mixin to react to taps
|
||||
on `BodyComponent`s.
|
||||
Tap the ball to give it a random impulse, or the text to add an effect to
|
||||
it.
|
||||
''';
|
||||
TappableExample() : super(zoom: 20, gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
@ -3,20 +3,21 @@ import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart' hide Transform;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'boundaries.dart';
|
||||
import 'utils/boundaries.dart';
|
||||
|
||||
const widgetSampleDescription = '''
|
||||
This examples shows how to render a widget on top of a Forge2D body.
|
||||
class WidgetExample extends Forge2DGame with TapDetector {
|
||||
static const String description = '''
|
||||
This examples shows how to render a widget on top of a Forge2D body outside
|
||||
of Flame.
|
||||
''';
|
||||
|
||||
class WidgetSample extends Forge2DGame with TapDetector {
|
||||
List<Function()> updateStates = [];
|
||||
Map<int, Body> bodyIdMap = {};
|
||||
List<int> addLaterIds = [];
|
||||
|
||||
Vector2 screenPosition(Body body) => worldToScreen(body.worldCenter);
|
||||
|
||||
WidgetSample() : super(zoom: 20, gravity: Vector2(0, 10.0));
|
||||
WidgetExample() : super(zoom: 20, gravity: Vector2(0, 10.0));
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
@ -38,7 +39,8 @@ class WidgetSample extends Forge2DGame with TapDetector {
|
||||
final fixtureDef = FixtureDef(
|
||||
shape,
|
||||
density: 1.0,
|
||||
restitution: 0.95,
|
||||
restitution: 0.8,
|
||||
friction: 0.2,
|
||||
);
|
||||
body.createFixture(fixtureDef);
|
||||
return body;
|
||||
@ -59,13 +61,13 @@ class WidgetSample extends Forge2DGame with TapDetector {
|
||||
}
|
||||
}
|
||||
|
||||
class BodyWidgetSample extends StatelessWidget {
|
||||
const BodyWidgetSample({Key? key}) : super(key: key);
|
||||
class BodyWidgetExample extends StatelessWidget {
|
||||
const BodyWidgetExample({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GameWidget<WidgetSample>(
|
||||
game: WidgetSample(),
|
||||
return GameWidget<WidgetExample>(
|
||||
game: WidgetExample(),
|
||||
overlayBuilderMap: {
|
||||
'button1': (ctx, game) {
|
||||
return BodyButtonWidget(game, game.createBodyId());
|
||||
@ -80,7 +82,7 @@ class BodyWidgetSample extends StatelessWidget {
|
||||
}
|
||||
|
||||
class BodyButtonWidget extends StatefulWidget {
|
||||
final WidgetSample _game;
|
||||
final WidgetExample _game;
|
||||
final int _bodyId;
|
||||
|
||||
const BodyButtonWidget(
|
||||
@ -96,7 +98,7 @@ class BodyButtonWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _BodyButtonState extends State<BodyButtonWidget> {
|
||||
final WidgetSample _game;
|
||||
final WidgetExample _game;
|
||||
final int _bodyId;
|
||||
Body? _body;
|
||||
|
||||
@ -40,7 +40,7 @@ class MultipleShapesExample extends FlameGame
|
||||
add(screenHitbox);
|
||||
add(snowman);
|
||||
var totalAdded = 1;
|
||||
while (totalAdded < 100) {
|
||||
while (totalAdded < 1000) {
|
||||
lastToAdd = nextRandomCollidable(lastToAdd, screenHitbox);
|
||||
final lastBottomRight = lastToAdd.toAbsoluteRect().bottomRight;
|
||||
if (lastBottomRight.dx < size.x && lastBottomRight.dy < size.y) {
|
||||
|
||||
@ -12,6 +12,7 @@ environment:
|
||||
dependencies:
|
||||
flame: ^1.1.1
|
||||
flame_svg: ^1.2.0
|
||||
flame_forge2d: ^0.11.0
|
||||
dashbook: 0.1.6
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1,15 +0,0 @@
|
||||
import 'package:flame/input.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
|
||||
import 'domino_sample.dart';
|
||||
import 'sprite_body_sample.dart';
|
||||
|
||||
class CameraSample extends DominoSample {
|
||||
@override
|
||||
void onTapDown(TapDownInfo details) {
|
||||
final position = details.eventPosition.game;
|
||||
final pizza = Pizza(position);
|
||||
add(pizza);
|
||||
pizza.mounted.whenComplete(() => camera.followBodyComponent(pizza));
|
||||
}
|
||||
}
|
||||
@ -1,112 +1,7 @@
|
||||
import 'package:dashbook/dashbook.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'animated_body_sample.dart';
|
||||
import 'blob_sample.dart';
|
||||
import 'camera_sample.dart';
|
||||
import 'circle_stress_sample.dart';
|
||||
import 'composition_sample.dart';
|
||||
import 'contact_callbacks_sample.dart';
|
||||
import 'domino_sample.dart';
|
||||
import 'draggable_sample.dart';
|
||||
import 'joint_sample.dart';
|
||||
import 'mouse_joint_sample.dart';
|
||||
import 'raycast_sample.dart';
|
||||
import 'sprite_body_sample.dart';
|
||||
import 'tappable_sample.dart';
|
||||
import 'widget_sample.dart';
|
||||
|
||||
String link(String example) =>
|
||||
'https://github.com/flame-engine/flame_forge2d/tree/main/example/lib/$example';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final dashbook = Dashbook(theme: ThemeData.dark());
|
||||
|
||||
dashbook.storiesOf('Flame with Forge2D').decorator(TopDecorator())
|
||||
..add(
|
||||
'Blob sample',
|
||||
(DashbookContext ctx) => GameWidget(game: BlobSample()),
|
||||
codeLink: link('blob_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Composition sample',
|
||||
(DashbookContext ctx) => GameWidget(game: CompositionSample()),
|
||||
codeLink: link('composition_sample.dart'),
|
||||
info: CompositionSample.info,
|
||||
)
|
||||
..add(
|
||||
'Domino sample',
|
||||
(DashbookContext ctx) => GameWidget(game: DominoSample()),
|
||||
codeLink: link('domino_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Contact Callbacks',
|
||||
(DashbookContext ctx) => GameWidget(game: ContactCallbacksSample()),
|
||||
codeLink: link('contact_callbacks_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Circle stress sample',
|
||||
(DashbookContext ctx) => GameWidget(game: CircleStressSample()),
|
||||
codeLink: link('circle_stress_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Sprite Bodies',
|
||||
(DashbookContext ctx) => GameWidget(game: SpriteBodySample()),
|
||||
codeLink: link('sprite_body_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'PositionBodyComponent',
|
||||
(DashbookContext ctx) => GameWidget(game: PositionBodySample()),
|
||||
codeLink: link('animated_body_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Tappable Body',
|
||||
(DashbookContext ctx) => GameWidget(game: TappableSample()),
|
||||
codeLink: link('tappable_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Draggable Body',
|
||||
(DashbookContext ctx) => GameWidget(game: DraggableSample()),
|
||||
codeLink: link('draggable_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Basic joint',
|
||||
(DashbookContext ctx) => GameWidget(game: JointSample()),
|
||||
codeLink: link('joint_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Mouse Joint',
|
||||
(DashbookContext ctx) => GameWidget(game: MouseJointSample()),
|
||||
codeLink: link('mouse_joint_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Camera',
|
||||
(DashbookContext ctx) => GameWidget(game: CameraSample()),
|
||||
codeLink: link('camera_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Widget sample',
|
||||
(DashbookContext ctx) => const BodyWidgetSample(),
|
||||
info: widgetSampleDescription,
|
||||
codeLink: link('widget_sample.dart'),
|
||||
)
|
||||
..add(
|
||||
'Raycast sample',
|
||||
(DashbookContext ctx) => GameWidget(game: RaycastSample()),
|
||||
codeLink: link('raycast_sample.dart'),
|
||||
info: raycastSampleDescription,
|
||||
);
|
||||
runApp(dashbook);
|
||||
}
|
||||
|
||||
class TopDecorator extends Decorator {
|
||||
@override
|
||||
Widget decorate(Widget child) {
|
||||
return Align(
|
||||
child: child,
|
||||
alignment: Alignment.topCenter,
|
||||
);
|
||||
}
|
||||
// There will be a new example in here after Google I/O, stay tuned!
|
||||
// If you want to see the previous examples, go to the flame_forge2d section
|
||||
// of https://examples.flame-engine.org
|
||||
// The sourcecode lives here:
|
||||
// https://github.com/flame-engine/flame/tree/main/examples/lib/stories/bridge_libraries/forge2d
|
||||
}
|
||||
|
||||
@ -25,6 +25,3 @@ dev_dependencies:
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/images/pizza.png
|
||||
- assets/images/chopper.png
|
||||
|
||||
Reference in New Issue
Block a user