4 minutes
Dart Box2D Fundamentals: Setup
Setting up the project
Firstly you should install Flutter if you have not yet done so. Checkout Flutter Get started for more information.
After you have installed Flutter we can create a new project like so:
flutter create ./box2d_and_flame
Add the following to your dependency list in pubspec.yaml
:
...
flame: ^0.24.0
box2d_flame: ^0.4.6
...
Source: /examples/setup/pubspec.yaml
And run flutter pub get
after saving the file.
After retrieving the dependencies clear the content in your main.dart
and lets write our own.
First let us define a class called Box2DAndFlame
. This will be the base of our game, it will extends the Flame Game
class, providing us with an update
and render
method:
import 'package:box2d_flame/box2d.dart' as Box2D;
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
class Box2DAndFlame extends Game {
Box2D.World _world;
Box2DAndFlame() : _world = Box2D.World.withGravity(Box2D.Vector2(0, 9.81));
@override
void render(Canvas canvas) {
_world.forEachBody((body) {
for (var fixture = body.getFixtureList();
fixture != null;
fixture = fixture.getNext()) {
final color = body.getType() == Box2D.BodyType.STATIC
? Colors.red
: body.getType() == Box2D.BodyType.DYNAMIC
? Colors.blue
: Colors.green;
final Box2D.Shape shape = fixture.getShape();
if (shape is Box2D.EdgeShape) {
canvas.save();
canvas.translate(body.position.x, body.position.y);
canvas.drawLine(
Offset(shape.vertex1.x, shape.vertex1.y),
Offset(shape.vertex2.x, shape.vertex2.y),
Paint()..color = color,
);
canvas.restore();
} else if (shape is Box2D.CircleShape) {
canvas.save();
canvas.translate(body.position.x, body.position.y);
canvas.rotate(body.getAngle());
canvas.drawCircle(
Offset(shape.p.x, shape.p.y),
shape.radius,
Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = 0.5,
);
canvas.drawCircle(
Offset(shape.p.x, shape.p.y),
shape.radius,
Paint()..color = color.withAlpha(50),
);
canvas.drawLine(
Offset(shape.p.x, shape.p.y),
Offset(shape.p.x + shape.radius, shape.p.y),
Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = 0.5,
);
canvas.restore();
} else if (shape is Box2D.PolygonShape) {
final List<Box2D.Vector2> vertices =
Box2D.Vec2Array().get(shape.count);
for (int i = 0; i < shape.count; ++i) {
body.getWorldPointToOut(shape.vertices[i],
vertices[i]); // Copy world point to our List.
}
final List<Offset> points = [];
for (int i = 0; i < shape.count; i++) {
points.add(Offset(
vertices[i].x, vertices[i].y)); // Convert Vertice to Offset.
}
final path = Path()
..addPolygon(
points, true); // Create a path based on the points and draw it.
canvas.drawPath(
path,
Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = 0.5,
);
canvas.drawPath(path, Paint()..color = color.withAlpha(50));
}
}
});
}
@override
void update(double delta) {
var velocityIterations = 8; // How strongly to correct velocity.
var positionIterations = 3; // How strongly to correct position.
_world.stepDt(delta, velocityIterations, positionIterations);
}
}
...
Source: /examples/setup/lib/main.dart
Note: Flame provides a Box2DGame
class as well, in most situations you would use that for ease-of-use. But I decided to go with the Game
class so you get a better hands-on experience with Box2D.
As you can see we also have a property called _world
. The world is the main object in Box2D, it handles both the creation and deletion of physics objects.
The render
method goes through each object in the world and simply render its shape to our screen. Don’t worry if you are not fully understanding what is happening there, in a later article we will go more in-depth with the rendering, for now we are just going to focus on the physics part.
We also call the stepDt
in the update
method, this ensures our world goes to the next step in the physics simulation. The velocity iterations and position iterations affect the way objects react when they collide. When two objects collide they get stuck(overlapped) and some calculation is needed get them not to overlap, how to move or rotate them. The higher the values the better your simulation, but at the cost of performance.
In a later article we will also go more in-depth into the World object and his capabilities, for now just accept that it is there.
Now we only need to add a main
method and we can run the application:
...
runApp(Box2DAndFlame().widget);
}
Source: /examples/setup/lib/main.dart
You can run the application using flutter run
.
Previous: Introduction • Next up: Bodies
See Dart Box2D Fundamentals series for all the articles.
Author: The explanations and code examples are based on https://www.iforce2d.net/b2dtut, I highly suggests to read those articles as well.