flame-engine / flame

A Flutter based game engine.
https://flame-engine.org
MIT License
9.14k stars 894 forks source link

Colisions does not respect coordinate system #3270

Open CodeDoctorDE opened 1 month ago

CodeDoctorDE commented 1 month ago

What happened?

The collisions seems to be offsetted when having a collision in different coordinate systems.

What do you expect?

Convert all positions to global ones to have the same coordinate system.

How can we reproduce this?

Create a collider inside camera.viewport and one in world

What steps should take to fix this?

Maybe use localToGlobal or something like this on all colliders

Do have an example of where the bug occurs?

https://dartpad.dev/?id=931319d09967e36386690e817afb0baa click on run and then you see that it collides if the cursor is on the top left corner.

Relevant log output

No errors reported

Execute in a terminal and put output into the code block below

[✓] Flutter (Channel stable, 3.24.0, on Fedora Linux 40 (KDE Plasma) 6.10.4-200.fc40.x86_64, locale de_DE.UTF-8) • Flutter version 3.24.0 on channel stable at /home/codedoctor/Tools/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 80c2e84975 (3 weeks ago), 2024-07-30 23:06:49 +0700 • Engine revision b8800d88be • Dart version 3.5.0 • DevTools version 2.37.2

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at /home/codedoctor/Android/Sdk • Platform android-34, build-tools 34.0.0 • Java binary at: /home/codedoctor/.local/share/JetBrains/Toolbox/apps/android-studio/jbr/bin/java • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314) • All Android licenses accepted.

[✓] Chrome - develop for the web • CHROME_EXECUTABLE = /usr/bin/chromium-browser

[✓] Linux toolchain - develop for Linux desktop • clang version 18.1.6 (Fedora 18.1.6-3.fc40) • cmake version 3.28.2 • ninja version 1.12.1 • pkg-config version 2.1.1

[✓] Android Studio (version 2024.1) • Android Studio at /home/codedoctor/.local/share/JetBrains/Toolbox/apps/android-studio • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314)

[✓] IntelliJ IDEA Ultimate Edition (version 2024.2) • IntelliJ at /home/codedoctor/.local/share/JetBrains/Toolbox/apps/intellij-idea-ultimate • Flutter plugin version 80.0.2 • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.92.2) • VS Code at /usr/share/code • Flutter extension version 3.94.0

[✓] Connected device (2 available) • Linux (desktop) • linux • linux-x64 • Fedora Linux 40 (KDE Plasma) 6.10.4-200.fc40.x86_64 • Chrome (web) • chrome • web-javascript • Chromium 127.0.6533.99 Fedora Project

[✓] Network resources • All expected network resources are available.

• No issues found!

Affected platforms

All

Other information

Also reported on discord: https://discord.com/channels/509714518008528896/1274083884451102762.

I would like to help with this but I have 0 idea how this all works. I'm currently using a workaround by moving the collider in the world space if it isn't interacting with camera viewport elements

Are you interested in working on a PR for this?

ufrshubham commented 4 weeks ago

Imo the collision is work as expected. All the collision checks are indeed performed in global coordinates space. It might be looking like an issue because the default settings of the camera renders the world's origin at the center of the viewport. If you just move the camera by half size of the viewport, it will look correct. Adding following line in the MyGame.onLoad, produces this output:

camera.moveTo(camera.viewport.virtualSize * 0.5);

https://github.com/user-attachments/assets/5ca81c76-9a6b-4fcd-9aca-08a739e6d6f7

Note: To make it work in the DartPad version, you might have to move the camera to size * 0.5 on the onGameResize.

CodeDoctorDE commented 4 weeks ago

On your end it looks okay. See the dartpad version for reference. This is the default behavior and for me as a user it's very confusing that with default rendering settings, the collisions are offsetted. Maybe this should get subtracted if the camera has this offset or at least be noted somewhere in the documentation.

I will try out your solution and reply if it works

spydon commented 4 weeks ago

Aaah right, @ufrshubham is correct of course. The docs should be improved and mention this though, I don't think they do now.

CodeDoctorDE commented 4 weeks ago

Hmm, I tested it myself but doesn't accept the solution right now. My game looks like this: Screenshot_20240818_203458 You can move the camera by dragging with the mouse on the game table. Internally it uses moveBy to navigate through the world. But when moving this way, the offset gets bigger and bigger. For me this makes no sense that these positions are moved with the world because it doesn't render like this. The camera position should be independent from the offset of the camera. I think the camera offset should be considered in the collision system.

spydon commented 4 weeks ago

The camera position should be independent from the offset of the camera.

Do you mean that the viewport position should be independent of the viewfinder? Because it is...

But when moving this way, the offset gets bigger and bigger. For me this makes no sense that these positions are moved with the world because it doesn't render like this.

That makes sense, since all collisions will be in world coordinates, not in screen/viewport coordinates (or any other local coordinate system).

ufrshubham commented 4 weeks ago

I can understand the confusion, but we cannot just make all the collision calculation based on the viewport/viewfinders configurations. For a multi-camera system it would mean we will have to perform the collision step per camera. An alternate approach to solve your problem is to add the cursor to the world and manually update its position based on actually mouse position and the camera's configuration.

class MyGame extends FlameGame with PointerMoveCallbacks, HasCollisionDetection {

  @override
  Future<void> onLoad() async {
    ...
    world.add(_cursor = Cursor());
  }

  @override
  void onPointerMove(PointerMoveEvent event) {
    _cursor.position = camera.globalToLocal(event.localPosition);
  }
}
spydon commented 4 weeks ago

@ufrshubham the problem he had from the beginning was that the cursor needed to collide with components both in the viewport and the world, which is a bit tricky without moving the cursor component between the world and the viewport, which was what I suggested in the discord thread.

ufrshubham commented 4 weeks ago

Can those component be added to the viewfinder instead? If I am not wrong, collisions with viewfinder.children will work as expected, right?

CodeDoctorDE commented 4 weeks ago

Yeah I want to collide with both the camera and the world. I'm not an expert in flame but my setup looks like this:

FlameGame (which has CollisionDetection)
-> World
  -> BoardGrid
    -> GridCell (which has a passive, solid Hitbox)
-> Camera
  -> Viewport
    -> Positioned with custom painter (to have the black background)
      -> Multiple HandItem (which spawns a cursor when starting dragging)

Now I want to check if the hand item when dragged should be put on a different cell or it should be moved inside the hand (to the front for example).

I don't know what you mean with viewfinder. If I added components there, it should be added in the background right?

If you have questions to my setup, my code is opensource and can be found here: https://github.com/LinwoodDev/Quokka/blob/bd191bece663326c4c28ad62d879bced2321b1cc/app/lib/board/game.dart

spydon commented 4 weeks ago

Can those component be added to the viewfinder instead? If I am not wrong, collisions with viewfinder.children will work as expected, right?

Those components are tied to the worlds coordinate system, because the camera has to be able to move over the different rows of cards.

To explain a bit more what he has: