I'm not getting consistent results from the collision detection. Sometimes things are colliding, sometimes they are not.
When using the arrow keys to move the circle through the red area full of colliders I would expect that it would refuse to enter it because this.isColliding == true
. Instead it just seems to stutter, sometimes failing to move, sometimes not.
In this example, on one update a collider is added that represents where the component will move. If it doesn't collide it will actually execute the move on the next update. Then the hitbox is removed and a new one is added which represents the next move.
I attempted removing the hitbox if there is a collision instead of using isColliding
and I got the same results.
No response
import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
Vector2 CalcPerpendicular(Vector2 vec, {bool clockwise = true}) {
if (clockwise) {
return Vector2(vec.y, -vec.x);
} else {
return Vector2(-vec.y, vec.x);
}
}
class Ninja extends RectangleComponent
with KeyboardHandler, CollisionCallbacks {
final Set<LogicalKeyboardKey> keysPressed = {};
final Set<LogicalKeyboardKey> keysDown = {};
final double speed = 64;
PolygonComponent? _hitbox;
Vector2? _delta;
@override
void render(Canvas canvas) {
super.render(canvas);
canvas.drawCircle(Offset(this.size.x / 2, this.size.y / 2), this.size.x / 2,
Paint()..color = Color.fromARGB(255, 178, 186, 247));
}
@override
void update(double dt) {
if (_hitbox != null) {
if (!isColliding) {
print('move');
this.position += _delta!;
}
remove(_hitbox!);
_hitbox = null;
}
double dx = 0;
double dy = 0;
if (keysPressed.contains(LogicalKeyboardKey.arrowRight)) {
dx = dt * speed;
}
if (keysPressed.contains(LogicalKeyboardKey.arrowLeft)) {
dx = -dt * speed;
}
if (keysPressed.contains(LogicalKeyboardKey.arrowUp)) {
dy = -dt * speed;
}
if (keysPressed.contains(LogicalKeyboardKey.arrowDown)) {
dy = dt * speed;
}
_delta = Vector2(dx, dy);
if (_delta!.length2 > 0) {
_hitbox = PolygonHitbox([
CalcPerpendicular(_delta!, clockwise: true).normalized() * (width / 2) +
(this.size * 0.5),
CalcPerpendicular(_delta!, clockwise: false).normalized() *
(width / 2) +
(this.size * 0.5),
CalcPerpendicular(_delta!, clockwise: false).normalized() *
(width / 2) +
(this.size * 0.5) +
_delta! +
_delta!.normalized() * 16,
CalcPerpendicular(_delta!, clockwise: true).normalized() * (width / 2) +
(this.size * 0.5) +
_delta! +
_delta!.normalized() * 16,
]);
print('attempt ${_delta} ${_hitbox!.vertices}');
_hitbox!.debugColor = Color(0xffff0000);
add(_hitbox!);
}
}
bool onKeyEvent(KeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
this.keysDown.clear();
for (final key in keysPressed) {
if (!this.keysPressed.contains(key)) {
this.keysDown.add(key);
}
}
this.keysPressed.clear();
this.keysPressed.addAll(keysPressed);
return false;
}
@override
void onCollision(Set<Vector2> points, PositionComponent other) {
print('collision $other');
super.onCollision(points, other);
}
}
class NinjaWorld extends World {
@override
Future<void> onLoad() async {
final test =
RectangleComponent(position: Vector2(100, 100), size: Vector2(16, 16))
..add(RectangleHitbox())
..debugMode = true;
add(test);
for (int j = 12; j <= 14; ++j) {
for (int i = 0; i < 30; ++i) {
int xpos = i * 16;
int ypos = j * 16;
final ShapeComponent shape = RectangleComponent(
position: Vector2(xpos.toDouble(), ypos.toDouble()),
paint: Paint()..color = Color.fromARGB(255, 205, 35, 35),
size: Vector2(16, 16))
..add(RectangleHitbox());
add(shape);
}
}
final ninja = Ninja();
ninja.position = Vector2(0, 0);
ninja.size = Vector2(32, 32);
ninja.debugMode = true;
add(ninja);
}
}
class NinjaGame extends FlameGame
with HasKeyboardHandlerComponents, HasQuadTreeCollisionDetection {
NinjaGame()
: super(
camera:
CameraComponent.withFixedResolution(width: 512, height: 288),
world: NinjaWorld());
@override
Future<void> onLoad() async {
initializeCollisionDetection(
mapDimensions: const Rect.fromLTWH(0, 0, 5120, 288),
);
camera.moveTo(Vector2(256, 144));
camera.viewfinder.zoom = 1.0;
}
}
void main() {
final game = NinjaGame();
runApp(GameWidget(game: game));
}
flutter: attempt [0.533312,0.0] [[0.0,0.0], [0.0,32.0], [16.533311999999995,32.0], [16.533311999999995,0.0]]
flutter: collision RectangleComponent(
position: Vector2(256.0, 208.0),
size: Vector2(16.0, 16.0),
angle: 0.0,
scale: [1.0,1.0],
)
flutter: move
Notice that there is a collision happening, but the "move" command is still printed out afterwards.
### Execute in a terminal and put output into the code block below
[!] Flutter (Channel [user-branch], 3.27.0-1.0.pre.644, on macOS 14.7.1 23H222 darwin-arm64, locale en)
! Flutter version 3.27.0-1.0.pre.644 on channel [user-branch] at /Users/aaclarke/dev/flutter
Currently on an unknown channel. Run flutter channel
to switch to an official channel.
If that doesn't fix the issue, reinstall Flutter by following instructions at https://flutter.dev/setup.
! Upstream repository unknown source is not a standard remote.
Set environment variable "FLUTTER_GIT_URL" to unknown source to dismiss this error.
• Framework revision f3f72ede04 (3 weeks ago), 2024-11-25 16:14:30 -0800
• Engine revision fe45a66086
• Dart version 3.7.0 (build 3.7.0-183.0.dev)
• DevTools version 2.41.0-dev.2
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and
upgrades.
### Affected platforms
macOS
### Other information
Flame version: 1.22.0
### Are you interested in working on a PR for this?
- [ ] I want to work on this
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too