From createBoundaries used in examples, I see how to create "Walls"/EdgeShape.
When moving the camera I get lines drawn. Du you know how to not draw these lines or make them transparent - looked in the FixtureDef?
import 'package:flame_forge2d/flame_forge2d.dart';
class Wall extends BodyComponent {
final Vector2 start;
final Vector2 end;
Wall(this.start, this.end);
#override
Body createBody() {
final shape = EdgeShape()..set(start, end);
final fixtureDef = FixtureDef(shape)
..restitution = 0.0
..friction = 0.3;
final bodyDef = BodyDef()
..userData = this // To be able to determine object in collision
..position = Vector2.zero()
..type = BodyType.static;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
Set renderBody = false or override render to be empty in the BodyComponent, Wall in this case.
Related
I am trying to render a grid with flutter canvas with Canvas.drawLine method.
Some lines are rendered semi-transparent and some are not even being rendered on the canvas.
class Background extends PositionComponent with HasGameRef<RokokoGame>{
Offset start = Offset.zero;
Offset end = Offset.zero;
// will be different across devices
late final double canvasX;
late final double canvasY;
final int cellSize = GameConfig.cellSize;
Background(this.canvasX, this.canvasY);
#override
Future<void>? onLoad() {
start = Offset(0, 0);
end = Offset(this.canvasX, this.canvasY);
}
#override
void render(Canvas canvas) {
canvas.drawRect(Rect.fromPoints(Offset.zero, end), Styles.white);
_drawVerticalLines(canvas);
_drawHorizontalLines(canvas);
}
void _drawVerticalLines(Canvas c) {
for (double x = start.dx; x <= end.dx; x += cellSize) {
c.drawLine(Offset(x, start.dy), Offset(x, end.dy), Styles.red);
}
}
void _drawHorizontalLines(Canvas c) {
for (double y = start.dy; y <= end.dy; y += cellSize) {
c.drawLine(Offset(start.dx, y), Offset(end.dx, y), Styles.blue);
}
}
}
So, i was able to solve the issue by applying some stroke width in my Styles class.
class Styles {
static Paint white = BasicPalette.white.paint();
static Paint blue = BasicPalette.blue.paint()..strokeWidth = 3;
static Paint red = BasicPalette.red.paint()..strokeWidth = 3;
}
how to let SpriteAnimationComponent follow BodyComponent, which can fall due to gravity. currently SpriteAnimationComponent still keep in the air, here is my code:
class Chick extends BodyComponent {
Vector2 fallPosition;
SpriteAnimationComponent chick = SpriteAnimationComponent();
Chick({
this.fallPosition,
});
final spriteSize = Vector2(32, 34) / 2;
#override
Future<void> onLoad() async {
await super.onLoad();
var spriteData = SpriteAnimationData.sequenced(
amount: 14, stepTime: 0.1, textureSize: Vector2(32, 34));
chick = SpriteAnimationComponent.fromFrameData(
spriteSize, ImageTool.image('chicken.png'), spriteData)
..x = fallPosition.x
..y = fallPosition.y
..anchor = Anchor.center
..size = spriteSize;
await addChild(chick);
}
#override
void update(double dt) {
chick.position = body.position;
print('body.position ! ${body.position} == $fallPosition}');
super.update(dt);
}
#override
Body createBody() {
debugMode = true;
final shape = CircleShape()..radius = spriteSize.x / 2;
var position = fallPosition.clone();
var worldPosition = viewport.getScreenToWorld(position);
final fixtureDef = FixtureDef()
..shape = shape
..restitution = 0.1
..density = 0.1
..friction = 0.1;
final bodyDef = BodyDef()
..userData = this
..angularDamping = 0.1
..position = worldPosition
..type = BodyType.DYNAMIC;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
I realize fallPosition, fallPosition, and chick.position has different value, but I dont know how to make this SpriteAnimationComponent follow Body, thanks for any help!
Add the SpriteBodyComponent as a child to the BodyComponent by simply running add, and remove the attempts that you have at synchronizing the positions, this will be done automatically once you have added it as a child.
To do this you also need to upgrade to a newer version of Flame (preferably v1.4.0 or newer) and a new version of flame_forge2d (> 0.12.3). Do note that addChild has been renamed to add.
From this, I would expect the following RevoluteJoint bodyB, to be higher up than the blue box on the y-axe - setting
revoluteJointDef.localAnchorA?
flame_forge2d: ^0.11.0
class Box extends BaseBox { // just a BodyComponent for same shape
BaseBox? boxB;
Box(position, paint, [this.boxB]) : super(position, paint);
#override
Body createBody() {
super.createBody();
if (this.boxB != null) {
paint.color = Colors.blue;
final revoluteJointDef = RevoluteJointDef();
revoluteJointDef.bodyA = body;
revoluteJointDef.bodyB = this.boxB!.body;
revoluteJointDef.localAnchorA.setFrom(Vector2(1, 1));
RevoluteJoint joint = RevoluteJoint(revoluteJointDef);
world.createJoint(joint);
}
return body;
}
}
I would expect it to be like this:
In flame_forge2d 0.11.0 the coordinate system was flipped on the y-axis to be the same coordinate system as Flame, so larger y-values will result in further down, instead of further up like it is in normal forge2d.
Just negate the y-value of the anchor and you should get your intended result:
revoluteJointDef.localAnchorA.setFrom(Vector2(1, -1));
I'm trying to create a polygon at the center of the screen with a mouse joint, very simple.
A CircleShape works great. Also the mouse joint behaves strangely and I couldn't find a pattern.
All code is in the main file here. I kept the code to a minimum.
Vector2 vec2Median(List<Vector2> vecs) {
var sum = Vector2(0, 0);
for (final v in vecs) {
sum += v;
}
return sum / vecs.length.toDouble();
}
void main() {
final game = MyGame();
runApp(GameWidget(game: game));
}
class MyGame extends Forge2DGame with MultiTouchDragDetector, HasTappables {
MouseJoint? mouseJoint;
static late BodyComponent grabbedBody;
late Body groundBody;
MyGame() : super(gravity: Vector2(0, -10.0));
#override
Future<void> onLoad() async {
final boundaries = createBoundaries(this); //Adding boundries
boundaries.forEach(add);
groundBody = world.createBody(BodyDef());
final center = screenToWorld(camera.viewport.effectiveSize / 2);
final poly = Polygon([
center + Vector2(0, 0),
center + Vector2(0, 5),
center + Vector2(5, 0),
center + Vector2(5, 5)
], bodyType: BodyType.dynamic);
add(poly);
grabbedBody = poly;
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo details) {
final mouseJointDef = MouseJointDef()
..maxForce = 3000 * grabbedBody.body.mass * 10 //Not neccerly needed
..dampingRatio = 1
..frequencyHz = 5
..target.setFrom(grabbedBody.body.position)
..collideConnected = false //Maybe set to true
..bodyA = groundBody
..bodyB = grabbedBody.body;
mouseJoint ??= world.createJoint(mouseJointDef) as MouseJoint;
mouseJoint?.setTarget(details.eventPosition.game);
return false;
}
#override
bool onDragEnd(int pointerId, DragEndInfo details) {
if (mouseJoint == null) {
return true;
}
world.destroyJoint(mouseJoint!);
mouseJoint = null;
return false;
}
}
abstract class TappableBodyComponent extends BodyComponent with Tappable {
final Vector2 position;
final BodyType bodyType;
TappableBodyComponent(this.position, {this.bodyType = BodyType.dynamic});
#override
bool onTapDown(_) {
MyGame.grabbedBody = this;
return false;
}
Body tappableBCreateBody(Shape shape) {
final fixtureDef = FixtureDef(shape)
..restitution = 0.8
..density = 1.0
..friction = 0.4;
final bodyDef = BodyDef()
// To be able to determine object in collision
..userData = this
..angularDamping = 0.8
..position = position
..type = bodyType;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class Polygon extends TappableBodyComponent {
final List<Vector2> vertecies;
Polygon(this.vertecies, {BodyType bodyType = BodyType.dynamic})
: super(vec2Median(vertecies), bodyType: bodyType);
#override
Body createBody() {
final shape = PolygonShape()..set(vertecies);
return tappableBCreateBody(shape);
}
}
tappableBCreateBody encapsulate Tappable and body creation methods, Polygon is the object I'm trying to create, vec2Median returns the center of the polygon (by vertices).
Thank you very much!
I think that you have to remove center from the vertices and only add that as the position of the BodyComponent instead, like you already do in the super call of your Polygon class.
I am having trouble applying gravity to a Rect object I want to fall freely along the Y-axis by updating Rect's position In my code with the body.position.y. Here is a snippet of my code :
import 'dart:ui';
import 'package:box2d_flame/box2d.dart';
import 'package:flame/sprite.dart';
import 'package:mimo/mimo-game.dart';
class Mimo {
final MimoGame game;
CircleShape shape;
Body body;
List<Sprite> mimoSprite;
List<Sprite> deadSprite;
double flyingSpriteIndex = 0;
Rect mimoRect;
bool isDead = false;
bool isOffScreen = false;
Mimo(this.game, double x, double y) {
shape = CircleShape(); //build in shape, just set the radius
shape.p.setFrom(Vector2.zero());
shape.radius = .1; //10cm ball
BodyDef bd = BodyDef();
bd.position = new Vector2(x,y);
bd.type = BodyType.DYNAMIC;
body = game.world.createBody(bd);
body.userData = this;
FixtureDef fd = FixtureDef();
fd.restitution = 0.5;
fd.density = 0.05;
fd.friction = 0;
fd.shape = shape;
body.createFixtureFromFixtureDef(fd);
mimoSprite = List();
mimoSprite.add(Sprite('mimo/mimo-1.png'));
mimoSprite.add(Sprite('mimo/mimo-2.png'));
mimoSprite.add(Sprite('mimo/mimo-3.png'));
mimoSprite.add(Sprite('mimo/mimo-4.png'));
mimoSprite.add(Sprite('mimo/mimo-5.png'));
deadSprite = List();
mimoRect = Rect.fromLTWH(body.position.x, body.position.y, game.mimoSize, game.mimoSize);
}
void render(Canvas c) {
mimoSprite[flyingSpriteIndex.toInt()].renderRect(c, mimoRect.inflate(2));
}
void update(double t) {
mimoRect = mimoRect.translate(body.position.x, body.position.y);
}
}
in the update method I use the line mimoRect = mimoRect.translate(body.position.x, body.position.y); so the body.position can update my Rect object in real-time. but nothing happens as my spawned object is always fixed at a position and does not move. I decided to log body.position.y to the console and noticed it does not change.
In my main class, I create a world object like this :
//Needed for Box2D
static const int WORLD_POOL_SIZE = 100;
static const int WORLD_POOL_CONTAINER_SIZE = 10;
//Main physic object -> our game world
World world;
//Zero vector -> no gravity
final Vector2 _gravity = Vector2(0, 4.0);
Body body;
CircleShape shape;
//Scale to get from rad/s to something in the game, I like the number 5
double sensorScale = 5;
//Draw class
Paint paint;
//Initial acceleration -> no movement as its (0,0)
Vector2 acceleration = Vector2.zero();
MimoGame() {
world = new World.withPool(_gravity,
DefaultWorldPool(WORLD_POOL_SIZE, WORLD_POOL_CONTAINER_SIZE));
initialize();
}
Please any idea on what I can do?
You need to use the Box2DGame (flame 0.22.0^) class in flame for your game and the object that you want to apply gravity to needs to extend BodyComponent, then you create an instance of your BodyComponent in your Box2DGame and use the add function to add it to the game loop which will make sure that update and render is called on it every iteration.
There is a good example in the flame source here.
Also remember that if your gravity is positive, your object will be flying upwards.