Why removing other sprite after collision not working in Flame? - flutter

I have two sprites in the game e.g Player and Enemy. After collision detection why remove(Component) method is not working?
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/geometry.dart';
import 'package:flutter/material.dart';
void main() async {
runApp(GameWidget(
game: CGame(),
));
}
class CGame extends FlameGame with HasCollidables {
#override
Future<void>? onLoad() async {
add(Enemy());
add(Player());
return super.onLoad();
}
}
class Enemy extends SpriteComponent with HasGameRef, HasHitboxes, Collidable {
Enemy() : super(priority: 1);
#override
Future<void>? onLoad() async {
sprite = await Sprite.load('crate.png');
size = Vector2(100, 100);
position = Vector2(200, gameRef.size.y / 3 * 2);
anchor = Anchor.center;
addHitbox(HitboxRectangle());
return super.onLoad();
}
}
class Player extends SpriteComponent with HasGameRef, HasHitboxes, Collidable {
#override
Future<void>? onLoad() async {
sprite = await Sprite.load('player.png');
size = Vector2(100, 100);
position = Vector2(0, gameRef.size.y / 3 * 2);
anchor = Anchor.center;
addHitbox(HitboxRectangle());
return super.onLoad();
}
#override
void update(double dt) {
position += Vector2(1, 0);
}
#override
void onCollision(Set<Vector2> intersectionPoints, Collidable other) {
if (other is Enemy) {
print('Player hit the Enemy!');
remove(Enemy()); //<== Why this line is not working?
}
}
}

You are trying to remove a new instance of an enemy component, you have to remove the specific one that you collided with, which in this case is other.
You also want to remove other from the game where it is added, if you do remove on the component you are trying to remove a subcomponent.
#override
void onCollision(Set<Vector2> intersectionPoints, Collidable other) {
if (other is Enemy) {
other.removeFromParent();
// It can also be done like this since you have the `HasGameRef` mixin
// gameRef.remove(other);
}
}
}

Related

How can I change anchor to Anchor.center in SpriteComponent in Flutter Flame?

I'm trying to change my object(Horse()) anchor point to Anchor.center in the creation of the object. But I wasn't able to. If I change it inside FlameGame using horse.anchor = Anchor.center it works but I want to create it with Anchor.center.
import 'package:flame/components.dart';
class Horse extends SpriteComponent {
final String name;
static const double spriteSize = 64;
#override
set anchor(Anchor anchor) {
super.anchor = Anchor.center;
}
#override
Future<void> onLoad() async {
sprite = await Sprite.load('$name.jpg');
}
Horse(this.name) : super(size: Vector2.all(spriteSize));
}
You can pass in the anchor directly to the super constructor:
import 'package:flame/components.dart';
class Horse extends SpriteComponent {
Horse(this.name) : super(size: Vector2.all(spriteSize), anchor: Anchor.center);
final String name;
static const double spriteSize = 64;
#override
Future<void> onLoad() async {
sprite = await Sprite.load('$name.jpg');
}
}
If you don't want to extend SpriteComponent you can also do this:
final sprite = await loadSprite('horse.jpg');
final spriteSize = 64;
final component = SpriteComponent(
sprite: sprite,
size: Vector2.all(spriteSize),
anchor: Anchor.center,
);
I changed my code to this and it now works but I don't think this is the ideal solution so I still want your answers pls
import 'package:flame/components.dart';
class Horse extends SpriteComponent {
final String name;
static const double spriteSize = 64;
anchorChange() {
super.anchor = Anchor.center;
}
#override
Future<void> onLoad() async {
sprite = await Sprite.load('$name.jpg');
anchorChange();
}
Horse(this.name) : super(size: Vector2.all(spriteSize));
}

Flame-engine, Draggable component doesn't work

I am completely newbie in flutter world specially flame-engine. Maybe it's a simple issue. But currently I couldn't figure it out. So please help me!
The main issue is my Draggable component doesn't work all event handler functions seem like doesn't not work correctly. Do you have any idea?
Draggable component code:
import 'package:flame/components.dart';
import 'package:flame/input.dart';
// Zooh bolomjtoi component
class DrawerComponent extends PositionComponent with Draggable {
late final mainRectangle;
Vector2? dragDeltaPosition;
bool get isDragging => dragDeltaPosition != null;
#override
Future<void>? onLoad() async {
final bg = await Sprite.load('drawer.png');
final localSize = Vector2(350, 210);
final mainRectangle = SpriteComponent(size: localSize, sprite: bg);
mainRectangle.position = isDragging ? (dragDeltaPosition)! : Vector2(0, 0);
add(mainRectangle);
}
#override
bool onDragStart(DragStartInfo info) {
print("Drag ehelleee..");
dragDeltaPosition = info.eventPosition.game - position;
return false;
}
#override
bool onDragUpdate(DragUpdateInfo info) {
print("Drag update..");
if (isDragging) {
final localCoords = info.eventPosition.game;
position.setFrom(localCoords - dragDeltaPosition!);
}
return false;
}
#override
bool onDragEnd(DragEndInfo info) {
print("Drag end...");
dragDeltaPosition = null;
return false;
}
#override
bool onDragCancel() {
dragDeltaPosition = null;
return false;
}
}
Main FlameGame class:
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:furniture/drawer.dart';
class Core extends FlameGame with HasDraggables {
late final SpriteComponent mainRectangle;
#override
Future<void>? onLoad() async {
final bg = await Sprite.load('example.jpeg');
final localSize = Vector2(super.size.x * 0.7, super.size.y * 0.6);
final mainRectangle = SpriteComponent(size: localSize, sprite: bg);
mainRectangle.position = Vector2(super.size.x * 0.15, super.size.y * 0.2);
mainRectangle.angle = 0;
add(mainRectangle);
add(DrawerComponent());
}
}
Flutter main class:
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:furniture/core.dart';
void main() {
final game = Core();
runApp(GameWidget(game: game));
}
I think your problem is into your onLoad() because you don't declare the values correctly, I have this example for you:
class Sushi extends SpriteComponent with Draggable, HasGameRef<JapaneseChef>{
/// Sushi constructor
Sushi( this._img, this._position, this._isMove, this._isDraggable,){
position = _position;
size = Vector2(250,250);
}
late final String _img;
late final Vector2 _position;
late Vector2 _dragDeltaPosition;
late final bool _isMove;
late final bool _isDraggable;
/// Get delta position
Vector2 get dragDeltaPosition => _dragDeltaPosition;
set dragDeltaPosition(Vector2? dragDeltaPosition) {
if(dragDeltaPosition != null){
_dragDeltaPosition = dragDeltaPosition;
}
}
#override
Future<void>? onLoad() async{
final spriteSushi = await Sprite.load(_img);
sprite = spriteSushi;
changePriorityWithoutResorting(5);
return super.onLoad();
}
#override
void update(double dt) {
if (_isMove) {
position.x -= 0.6;
if (position.x < -size.x) {
remove(this);
}
}
super.update(dt);
}
#override
bool onDragStart(int pointerId, DragStartInfo info) {
if(_isDraggable) {
dragDeltaPosition = info.eventPosition.game - position;
}
return false;
}
#override
bool onDragCancel(int pointerId) {
dragDeltaPosition = null;
return super.onDragCancel(pointerId);
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo info) {
if (parent is! JapaneseChef) {
return true;
}
final dragDeltaPosition = this.dragDeltaPosition;
position.setFrom(info.eventPosition.game - dragDeltaPosition);
return false;
}
#override
bool onDragEnd(int pointerId, DragEndInfo info) {
dragDeltaPosition = null;
return false;
}
}
Also, you can see the example from Flame engine
Example result

How to detect screen boundaries with Flame in Flutter?

I want to detect when an object goes outside of the screen in Flame Flutter. I think there is two way to accomplish this either with Collidable mixin or with Forge2D. If possible explain it in both of them.
Flame version: flame: 1.0.0-releasecandidate.18
It is way overkill to use Forge2D for this (that complicates a lot of other things too). But you can use the built-in collision detection system, or you can check in the update-loop whether it is within the screen or not (this would be the most efficient).
By using the collision detection system we can use the built-in ScreenCollidable and you can do something like this:
class ExampleGame extends FlameGame with HasCollidables {
...
#override
Future<void> onLoad() async {
await super.onLoad();
add(ScreenCollidable());
}
}
class YourComponent extends PositionComponent with HasHitboxes, Collidable {
#override
Future<void> onLoad() async {
await super.onLoad();
// Change this if you want the components to collide with each other
// and not only the screen.
collidableType = CollidableType.passive;
addHitbox(HitboxRectangle());
}
// Do note that this doesn't work if the component starts
// to go outside of the screen but then comes back.
#override
void onCollisionEnd(Collidable other) {
if (other is ScreenCollidable) {
removeFromParent();
}
}
}
and by just calculating it in the update-loop:
class YourComponent extends PositionComponent with HasGameRef {
#override
void update(double dt) {
final topLeft = absoluteTopLeftPosition;
final gameSize = gameRef.size;
if(topLeft.x > gameSize.x || topLeft.y > gameSize.y) {
removeFromParent();
return;
}
final bottomRight = absolutePositionOfAnchor(Anchor.bottomRight);
if(bottomRight.x < 0 || bottomRight.y < 0) {
removeFromParent();
return;
}
}
}
I also recommend that you update to Flame 1.0.0 now when it is released. :)
There is no longer a Collidable mixin.
See the Flame documentation

Can a Flame game object such as PositionComponent be Collidable and Draggable

Successfully implemented a Draggable component. When adding the Hitbox and Collidable mixins to the class extended by PositionComponent the drag functionality stops working.
Is it possible to have a draggable component that is also collidable?
Flutter version: 2.2.3
Flame version: 1.0.0-releasecandidate.13
main.dart
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'DraggablesGame.dart';
void main() {
runApp(
GameWidget(
game: DraggablesGame(),
),
);
}
DraggablesGame.dart
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'DraggableSquare.dart';
class DraggablesGame extends BaseGame with HasDraggableComponents, HasCollidables {
#override
Future<void> onLoad() async {
add(DraggableSquare());
add(DraggableSquare()..y = 350);
}
}
DraggableSquare.dart
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flutter/material.dart' show Colors;
import 'DraggablesGame.dart';
class DraggableSquare extends PositionComponent
with Draggable, HasGameRef<DraggablesGame>, Hitbox, Collidable {
#override
bool debugMode = true;
DraggableSquare({Vector2? position})
: super(
position: position ?? Vector2.all(100),
size: Vector2.all(100),
);
Vector2? dragDeltaPosition;
bool get isDragging => dragDeltaPosition != null;
#override
void update(double dt) {
super.update(dt);
debugColor = isDragging ? Colors.greenAccent : Colors.purple;
}
#override
bool onDragStart(int pointerId, DragStartInfo info) {
dragDeltaPosition = info.eventPosition.game - position;
return false;
}
#override
bool onDragUpdate(int pointerId, DragUpdateInfo event) {
final dragDeltaPosition = this.dragDeltaPosition;
if (dragDeltaPosition == null) {
return false;
}
position.setFrom(event.eventPosition.game - dragDeltaPosition);
return false;
}
#override
bool onDragEnd(int pointerId, _) {
dragDeltaPosition = null;
return false;
}
#override
bool onDragCancel(int pointerId) {
dragDeltaPosition = null;
return false;
}
}
Update based on answer
Spydon's answer suggested using addHitbox(HitboxRectangle());. This resulted in the following error:
The method 'addHitbox' isn't defined for the type 'DraggableSquare'.
Instead this modified constructor allows for both the dragging and colliding.
Updated DraggableSquare Constructor
DraggableSquare({Vector2? position})
: super(
position: position,
size: Vector2.all(100),
) {
final hitBox = HitboxRectangle();
addShape(hitBox);
}
When you add the Hitbox mixin you also have to add some hitboxes, otherwise it will not be able to know what it should count as a "hit".
The simplest solution is to add an empty hitbox of either the HitboxRectangle or HitboxCircle type. These hitbox will will the full size of the component if you don't define anything more specific in them.
So to add a HitboxRectangle, you modify your constructor to this:
DraggableSquare({Vector2? position})
: super(
position: position ?? Vector2.all(100),
size: Vector2.all(100),
) {
addShape(HitboxRectangle());
}
If you set debugMode = true you will be able to visually see the hitboxes that you add.

Flutter: onTapDown function not always called

I'm new in flutter development. I add onTapdown listener if i perform any clicked action on the screen. It's worked,but the problem is sometime when i clicked,onTapdown function not get called.I don't know what problem i have done.Hope can help me solve this problem.Thank you in advance.
import 'package:flame/game.dart';
import 'package:flame/components/parallax_component.dart';
import 'package:flame/util.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Util flameUtil = Util();
await flameUtil.fullScreen();
runApp(MyGame(flameUtil).widget);
}
class MyGame extends BaseGame {
MyGame(Util flameUtil) {
final images = [
ParallaxImage("space/bg_base.png",repeat: ImageRepeat.repeat,fill: LayerFill.height),
ParallaxImage("space/bg_big_star.png",repeat: ImageRepeat.repeatY,fill: LayerFill.height),
ParallaxImage("space/bg_planet.png",repeat: ImageRepeat.repeat,fill: LayerFill.none),
];
var game = Squres(images);
add(game);
TapGestureRecognizer tapper = TapGestureRecognizer();
tapper.onTapDown = game.onTapDown;
flameUtil.addGestureRecognizer(tapper);
}
}
class Squres extends ParallaxComponent{
Squres(List<ParallaxImage> images) : super(images){
baseSpeed = const Offset(4,0);
layerDelta = const Offset(0,-50);
}
#override
void render(Canvas canvas) {
super.render(canvas);
}
#override
void resize(Size size) {
super.resize(size);
}
#override
void update(double t) {
super.update(t);
}
//not always trigger
void onTapDown(TapDownDetails tap){
print("trigger");
}
}
Make sure you use flame 0.22.0^ and use create your game class like this instead:
class MyGame extends BaseGame with TapDetector {
Squres game;
MyGame() {
final images = [
ParallaxImage("space/bg_base.png",repeat: ImageRepeat.repeat,fill: LayerFill.height),
ParallaxImage("space/bg_big_star.png",repeat: ImageRepeat.repeatY,fill: LayerFill.height),
ParallaxImage("space/bg_planet.png",repeat: ImageRepeat.repeat,fill: LayerFill.none),
];
game = Squres(images);
add(game);
}
#override
void onTapDown(TapUpDetails details) {
print("trigger");
game.onTapDown(details);
}
}
Also, remember that you don't have to override update, resize and render if you only call super on them.