Files
flame/lib/box2d/box2d_component.dart

179 lines
4.5 KiB
Dart

import 'dart:ui';
import 'package:box2d_flame/box2d.dart' hide Timer;
import 'package:flame/box2d/viewport.dart';
import 'package:flame/components/component.dart';
abstract class Box2DComponent extends Component {
static const int DEFAULT_WORLD_POOL_SIZE = 100;
static const int DEFAULT_WORLD_POOL_CONTAINER_SIZE = 10;
static const double DEFAULT_GRAVITY = -10.0;
static const int DEFAULT_VELOCITY_ITERATIONS = 10;
static const int DEFAULT_POSITION_ITERATIONS = 10;
static const double DEFAULT_SCALE = 1.0;
Size dimensions;
int velocityIterations;
int positionIterations;
World world;
List<BodyComponent> components = [];
Viewport viewport;
Box2DComponent({
this.dimensions: null,
int worldPoolSize: DEFAULT_WORLD_POOL_SIZE,
int worldPoolContainerSize: DEFAULT_WORLD_POOL_CONTAINER_SIZE,
double gravity: DEFAULT_GRAVITY,
this.velocityIterations: DEFAULT_VELOCITY_ITERATIONS,
this.positionIterations: DEFAULT_POSITION_ITERATIONS,
double scale: DEFAULT_SCALE,
}) {
if (this.dimensions == null) {
this.dimensions = window.physicalSize;
}
final pool = DefaultWorldPool(worldPoolSize, worldPoolContainerSize);
this.world = World.withPool(Vector2(0.0, gravity), pool);
this.viewport = Viewport(dimensions, scale);
}
@override
void update(t) {
world.stepDt(t, velocityIterations, positionIterations);
components.forEach((c) {
c.update(t);
});
}
@override
void render(canvas) {
if (viewport.size == Size(0.0, 0.0)) {
return;
}
components.forEach((c) {
if (c.body.isActive()) {
c.render(canvas);
}
});
}
@override
void resize(Size size) {
viewport.resize(size);
components.forEach((c) {
c.resize(size);
});
}
void add(BodyComponent component) {
components.add(component);
}
void addAll(List<BodyComponent> component) {
components.addAll(component);
}
void remove(BodyComponent component) {
components.remove(component);
world.destroyBody(component.body);
}
void initializeWorld();
void cameraFollow(
BodyComponent component, {
double horizontal,
double vertical,
}) {
viewport.cameraFollow(
component,
horizontal: horizontal,
vertical: vertical,
);
}
}
abstract class BodyComponent extends Component {
static const MAX_POLYGON_VERTICES = 10;
Box2DComponent box;
Body body;
BodyComponent(this.box);
World get world => box.world;
Viewport get viewport => box.viewport;
@override
void update(double t) {
// usually all update will be handled by the world physics
}
@override
void render(Canvas canvas) {
body.getFixtureList();
for (Fixture fixture = body.getFixtureList();
fixture != null;
fixture = fixture.getNext()) {
switch (fixture.getType()) {
case ShapeType.CHAIN:
throw Exception('not implemented');
break;
case ShapeType.CIRCLE:
_renderCircle(canvas, fixture);
break;
case ShapeType.EDGE:
throw Exception('not implemented');
break;
case ShapeType.POLYGON:
_renderPolygon(canvas, fixture);
break;
}
}
}
Vector2 get center => this.body.worldCenter;
void _renderCircle(Canvas canvas, Fixture fixture) {
Vector2 center = Vector2.zero();
CircleShape circle = fixture.getShape();
body.getWorldPointToOut(circle.p, center);
viewport.getWorldToScreen(center, center);
renderCircle(
canvas, Offset(center.x, center.y), circle.radius * viewport.scale);
}
void renderCircle(Canvas canvas, Offset center, double radius) {
final Paint paint = Paint()
..color = const Color.fromARGB(255, 255, 255, 255);
canvas.drawCircle(center, radius, paint);
}
void _renderPolygon(Canvas canvas, Fixture fixture) {
PolygonShape polygon = fixture.getShape();
assert(polygon.count <= MAX_POLYGON_VERTICES);
List<Vector2> vertices = Vec2Array().get(polygon.count);
for (int i = 0; i < polygon.count; ++i) {
body.getWorldPointToOut(polygon.vertices[i], vertices[i]);
viewport.getWorldToScreen(vertices[i], vertices[i]);
}
List<Offset> points = [];
for (int i = 0; i < polygon.count; i++) {
points.add(Offset(vertices[i].x, vertices[i].y));
}
renderPolygon(canvas, points);
}
void renderPolygon(Canvas canvas, List<Offset> points) {
final path = Path()..addPolygon(points, true);
final Paint paint = Paint()
..color = const Color.fromARGB(255, 255, 255, 255);
canvas.drawPath(path, paint);
}
}