Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rays outside a CircleHitbox are seen by RaycastResult as inside. #3063

Closed
1 task
wurzelsand opened this issue Mar 2, 2024 · 3 comments · Fixed by #3100
Closed
1 task

Rays outside a CircleHitbox are seen by RaycastResult as inside. #3063

wurzelsand opened this issue Mar 2, 2024 · 3 comments · Fixed by #3100
Labels

Comments

@wurzelsand
Copy link

wurzelsand commented Mar 2, 2024

What happened?

RaycastResult has a field called isInsideHitbox. The documentation explains: Whether the origin of the ray was inside the hitbox.

I tried it with PolygonHitbox, RectangleHitbox and CircleHitbox: I spread several random rays over the screen and marked the position of the origin of the ray with a colored circle when it collided with the hitbox. The inner origins should be red, the outer origins green.

With RectangleHitbox and PolygonHitbox the results were as expected, but not with CircleHitbox: Some of the outside points were evaluated as inside points by the isInsideHitbox field.

Some of the outside points are red, but they should all be green:

All outside points are green for RectangleHitbox and PolygonHitbox, as expected:


What do you expect?

isInsideHitbox should be evaluate as false, when the origin of the ray was outside the hitbox.

How can we reproduce this?

This is how I made the tests:

import 'dart:async';
import 'dart:math';

import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/geometry.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Center(
            child: GameWidget.controlled(gameFactory: MyGame.new),
          ),
        ),
      ),
    );
  }
}

const playArea = Rect.fromLTRB(-100, -100, 100, 100);

class MyGame extends FlameGame {
  MyGame()
      : super(
          world: MyWorld(),
          camera: CameraComponent.withFixedResolution(
            width: playArea.width,
            height: playArea.height,
          ),
        );
}

final whiteStroke = Paint()
  ..color = const Color(0xffffffff)
  ..style = PaintingStyle.stroke;

final lightStroke = Paint()
  ..color = const Color(0x50ffffff)
  ..style = PaintingStyle.stroke;

final greenStroke = Paint()
  ..color = const Color(0xff00ff00)
  ..style = PaintingStyle.stroke;

final redStroke = Paint()
  ..color = const Color(0xffff0000)
  ..style = PaintingStyle.stroke;

class MyWorld extends World
    with HasGameReference<MyGame>, HasCollisionDetection, TapCallbacks {
  final _rng = Random();
  List<Ray2> _rays = [];

  List<Ray2> randomRays(int count) => List<Ray2>.generate(
        count,
        (index) => Ray2(
          origin: (Vector2.random(_rng)) * playArea.size.width -
              playArea.size.toVector2() / 2,
          direction: (Vector2.random(_rng) - Vector2(0.5, 0.5)).normalized(),
        ),
      );

  int _componentIndex = 0;

  final _components = [
    CircleComponent(
      radius: 60,
      anchor: Anchor.center,
      position: Vector2.zero(),
      paint: whiteStroke,
      children: [CircleHitbox()],
    ),
    RectangleComponent(
      size: Vector2(100, 100),
      anchor: Anchor.center,
      position: Vector2.zero(),
      paint: whiteStroke,
      children: [RectangleHitbox()],
    ),
    PositionComponent(
      position: Vector2.zero(),
      children: [
        PolygonHitbox.relative(
          [
            Vector2(-0.7, -1),
            Vector2(1, -0.4),
            Vector2(0.3, 1),
            Vector2(-1, 0.6),
          ],
          parentSize: Vector2(100, 100),
          anchor: Anchor.center,
          position: Vector2.zero(),
        )
          ..paint = whiteStroke
          ..renderShape = true,
      ],
    )
  ];

  @override
  FutureOr<void> onLoad() {
    super.onLoad();
    add(_components[_componentIndex]);
    _rays = randomRays(200);
  }

  @override
  void onTapUp(TapUpEvent event) {
    super.onTapUp(event);
    remove(_components[_componentIndex]);
    _componentIndex = (_componentIndex + 1) % _components.length;
    add(_components[_componentIndex]);
    _recording.clear();
    _rays = randomRays(200);
  }

  final Map<Ray2, RaycastResult<ShapeHitbox>?> _recording = {};

  @override
  void update(double dt) {
    super.update(dt);

    for (final ray in _rays) {
      final result = collisionDetection.raycast(ray);
      _recording.addAll({ray: result});
    }
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    for (final ray in _recording.keys) {
      final result = _recording[ray];
      if (result == null) {
        canvas.drawLine(
          ray.origin.toOffset(),
          (ray.origin + ray.direction.scaled(10)).toOffset(),
          lightStroke,
        );
        canvas.drawCircle(ray.origin.toOffset(), 1, lightStroke);
      } else {
        canvas.drawLine(
          ray.origin.toOffset(),
          result.intersectionPoint!.toOffset(),
          lightStroke,
        );
        canvas.drawCircle(
          ray.origin.toOffset(),
          1,
          result.isInsideHitbox ? redStroke : greenStroke,
        );
      }
    }
  }
}

What steps should take to fix this?

No response

Do have an example of where the bug occurs?

No response

Relevant log output

No response

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

[✓] Flutter (Channel stable, 3.19.2, on macOS 14.2.1 23C71 darwin-x64, locale
en-US)
• Flutter version 3.19.2 on channel stable at /Users/user/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 7482962148 (4 days ago), 2024-02-27 16:51:22 -0500
• Engine revision 04817c99c9
• Dart version 3.3.0
• DevTools version 2.31.1

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at /Users/user/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• Java binary at: /Applications/Android
Studio.app/Contents/jbr/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
17.0.7+0-17.0.7b1000.6-10550314)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15C500b
• CocoaPods version 1.14.3

[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.1)
• Android Studio at /Applications/Android Studio.app/Contents
• 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.7+0-17.0.7b1000.6-10550314)

[✓] VS Code (version 1.87.0)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.84.0

[✓] Connected device (2 available)
• macOS (desktop) • macos • darwin-x64 • macOS 14.2.1 23C71 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 122.0.6261.94
! Error: Browsing on the local area network for iPad von Andreas. Ensure the
device is unlocked and attached with a cable or associated with the same
local area network as this Mac.
The device must be opted into Developer Mode to connect wirelessly. (code
-27)

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

• No issues found!

Affected platforms

All

Other information

No response

Are you interested in working on a PR for this?

  • I want to work on this
@wurzelsand wurzelsand added the bug label Mar 2, 2024
@spydon
Copy link
Member

spydon commented Mar 2, 2024

Good find! I wonder how that happened, the circle calculation should be the simplest. I'll have a look tomorrow

@spydon
Copy link
Member

spydon commented Mar 26, 2024

Thanks for the absolutely terrific MRE! The issue is now solved in in #3100.
I took your MRE and added it to the examples directory, I hope you don't mind. :)

spydon added a commit that referenced this issue Mar 26, 2024
Previously some rays that originated outside of the `CircleHitbox` were
counted as inside, this solves that and adds an example of how to use
the `isInsideHitbox` functionality (thanks to @wurzelsand).


Closes #3063
@wurzelsand
Copy link
Author

wurzelsand commented Mar 27, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants