My code files are way too big to post here so I will try to explain as simply as possible. I have a bunch of state values like so:
bool showPhotos = true;
bool showColorPicker = false;
bool showSizePicker = false;
bool showPitchSelection = false;
bool showDesignsSelection = false;
double kitSize = 48;
Color kitColor = Colors.white;
String pitchedSelected = "assets/images/pitch1.png";
Design? designSelected;
List<Design> designs = [];
Player playerOne = Player.defaultPlayer();
Player playerTwo = Player.defaultPlayer();
Player playerThree = Player.defaultPlayer();
Player playerFour = Player.defaultPlayer();
Player playerFive = Player.defaultPlayer();
Player playerSix = Player.defaultPlayer();
Player playerSeven = Player.defaultPlayer();
Player playerEight = Player.defaultPlayer();
Player playerNine = Player.defaultPlayer();
Player playerTen = Player.defaultPlayer();
Player playerEleven = Player.defaultPlayer();
Offset positionOne = const Offset(155, 250);
Offset positionTwo = const Offset(30, 170);
Offset positionThree = const Offset(100, 170);
Offset positionFour = const Offset(200, 170);
Offset positionFive = const Offset(280, 170);
Offset positionSix = const Offset(40, 100);
Offset positionSeven = const Offset(110, 100);
Offset positionEight = const Offset(200, 100);
Offset positionNine = const Offset(270, 100);
Offset positionTen = const Offset(110, 30);
Offset positionEleven = const Offset(200, 30);
I then pass these values into a Stateful Widget:
class Pitch extends StatefulWidget {
Pitch({super.key,
required this.showPhotos,
required this.showColorPicker,
required this.showSizePicker,
required this.showPitchSelection,
required this.showDesignsSelection,
required this.kitSize,
required this.kitColor,
required this.pitchedSelected,
required this.designSelected,
required this.playerOne,
required this.playerTwo,
required this.playerThree,
required this.playerFour,
required this.playerFive,
required this.playerSix,
required this.playerSeven,
required this.playerEight,
required this.playerNine,
required this.playerTen,
required this.playerEleven,
required this.positionOne,
required this.positionTwo,
required this.positionThree,
required this.positionFour,
required this.positionFive,
required this.positionSix,
required this.positionSeven,
required this.positionEight,
required this.positionNine,
required this.positionTen,
required this.positionEleven,
});
bool showPhotos;
bool showColorPicker;
bool showSizePicker;
bool showPitchSelection;
bool showDesignsSelection;
double kitSize;
Color kitColor;
String pitchedSelected;
Design? designSelected;
Player playerOne;
Player playerTwo;
Player playerThree;
Player playerFour;
Player playerFive;
Player playerSix;
Player playerSeven;
Player playerEight;
Player playerNine;
Player playerTen;
Player playerEleven;
Offset positionOne;
Offset positionTwo;
Offset positionThree;
Offset positionFour;
Offset positionFive;
Offset positionSix;
Offset positionSeven;
Offset positionEight;
Offset positionNine;
Offset positionTen;
Offset positionEleven;
#override
_Pitch createState() => _Pitch();
}
class _Pitch extends State<Pitch> {
// build code
}
The values initially are passed in and work fine, but the issue I'm facing is when the values get updated, they seem to reset in the StatefulWidget, what am I doing wrong here?
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 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.
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 have a flutter app using the flame library. I'm trying to make an object move in a flutter game. When I run the update function, I get the following error:
The method '*' was called on null.
Receiver: null
Tried calling: *(0.0)
Seems like something isn't initialized and the update function is ran before that something is initialized. When I comment out player.update(t) it works, but the update function doesn't get called. What am I doing wrong ad how can I fix it? Here's my code:
Game Controller Class
class GameController extends Game {
Size screenSize;
Player player;
GameController() {
initialize();
}
void initialize() async {
final initDimetion = await Flame.util.initialDimensions();
resize(initDimetion);
player = Player(this);
}
void render(Canvas c) {
Rect bgRect = Rect.fromLTWH(0, 0, screenSize.width, screenSize.height);
Paint bgPaint = Paint()..color = Color(0xFFFAFAFA);
c.drawRect(bgRect, bgPaint);
player.render(c);
}
void update(double t) {
if (player is Player) { // Tried adding this if statement but it didn't work
player.update(t);
}
}
void resize(Size size) {
screenSize = size;
}
}
Player Class
class Player {
final GameController gameController;
Rect playerRect;
double speed;
Player(this.gameController) {
final size = 40.0;
playerRect = Rect.fromLTWH(gameController.screenSize.width / 2 - size / 2,
gameController.screenSize.height / 2 - size / 2, size, size);
}
void render(Canvas c) {
Paint color = Paint()..color = Color(0xFF0000FF);
c.drawRect(playerRect, color);
}
void update(double t) {
double stepDistance = speed * t;
Offset stepToSide = Offset.fromDirection(90, stepDistance);
playerRect = playerRect.shift(stepToSide);
}
}
You never initialize the speed attribute of Player to a value. So speed * t in Player.update causes this error.
Simply initialize the speed attribute in the constructor
Player(this.gameController) {
final size = 40.0;
this.speed = 0;
playerRect = Rect.fromLTWH(gameController.screenSize.width / 2 - size / 2,
gameController.screenSize.height / 2 - size / 2, size, size);
}