Fix ray calculations by normalizing angles properly

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-09-10 21:10:27 +02:00
parent eaa6d76792
commit 2f6db48e4a
+19 -42
View File
@@ -24,8 +24,9 @@ const double gameWidth = 320;
const double gameHeight = 256; const double gameHeight = 256;
extension GameValues on double { extension GameValues on double {
/// Normalizes an angle back into [0, 2π]. /// Normalizes an angle back into [0, 2π) from (-π, π].
double get normalize => (this % (2 * math.pi) + 2 * math.pi) % (2 * math.pi); double get normalizeAngle =>
(this % (2 * math.pi) + 2 * math.pi) % (2 * math.pi);
/// Returns the degree angle /// Returns the degree angle
double get radianToDegree { double get radianToDegree {
@@ -52,14 +53,14 @@ extension GameValues on double {
// Flutter's coordinate system flips the y-axis, which is why we have -sin() -- to flip // Flutter's coordinate system flips the y-axis, which is why we have -sin() -- to flip
// it back in the correct direction. // it back in the correct direction.
Offset get direction => Offset( Offset get direction => Offset(
math.cos(normalize), math.cos(normalizeAngle),
-math.sin(normalize), math.sin(normalizeAngle),
); );
/// Get the delta from the given angle /// Get the delta from the given angle
Offset get playerDelta => Offset( Offset get playerDelta => Offset(
math.cos(this) * Player.speed, direction.dx * Player.speed,
math.sin(this) * Player.speed, direction.dy * Player.speed,
); );
} }
@@ -191,7 +192,7 @@ class _PlayerState extends State<Player> {
widget.onRaysUpdated( widget.onRaysUpdated(
calculateRays( calculateRays(
widget.rayData.playerPosition, widget.rayData.playerPosition,
widget.rayData.playerAngle.playerDelta, widget.rayData.playerAngle,
), ),
); );
@@ -243,28 +244,23 @@ class _PlayerState extends State<Player> {
// Where is the player now? // Where is the player now?
Offset playerPosition = widget.rayData.playerPosition; Offset playerPosition = widget.rayData.playerPosition;
double playerAngle = widget.rayData.playerAngle; double playerAngle = widget.rayData.playerAngle;
final Offset direction = playerAngle.direction;
// How many pixels away from a wall to stay // How many pixels away from a wall to stay
const double buffer = 8; const double buffer = 8;
if (keys.contains(LogicalKeyboardKey.keyA)) { if (keys.contains(LogicalKeyboardKey.keyA)) {
// Move left // Turn left
playerAngle -= 0.1; playerAngle -= 0.1;
if (playerAngle < 0) {
playerAngle += 2 * math.pi;
}
handled = true; handled = true;
} else if (keys.contains(LogicalKeyboardKey.keyD)) { } else if (keys.contains(LogicalKeyboardKey.keyD)) {
// Move right // Turn right
playerAngle += 0.1; playerAngle += 0.1;
if (playerAngle > 2 * math.pi) {
playerAngle -= 2 * math.pi;
}
handled = true; handled = true;
} }
// Capture the direction *after* it's potentially mutated
final Offset direction = playerAngle.direction;
if (keys.contains(LogicalKeyboardKey.keyW)) { if (keys.contains(LogicalKeyboardKey.keyW)) {
if (safeDistanceToWall(playerPosition, direction) > if (safeDistanceToWall(playerPosition, direction) >
Player.speed + buffer) { Player.speed + buffer) {
@@ -283,7 +279,7 @@ class _PlayerState extends State<Player> {
if (handled) { if (handled) {
widget.onRaysUpdated( widget.onRaysUpdated(
calculateRays(playerPosition, playerAngle.playerDelta), calculateRays(playerPosition, playerAngle),
); );
widget.onAngleUpdated(playerAngle); widget.onAngleUpdated(playerAngle);
widget.onPositionUpdated(playerPosition); widget.onPositionUpdated(playerPosition);
@@ -293,7 +289,7 @@ class _PlayerState extends State<Player> {
return false; return false;
} }
List<Ray> calculateRays(Offset offset, Offset delta) { List<Ray> calculateRays(Offset offset, double playerAngle) {
const double dr = math.pi / 180; const double dr = math.pi / 180;
final List<Ray> rays = []; final List<Ray> rays = [];
@@ -312,14 +308,7 @@ class _PlayerState extends State<Player> {
double rayY = 0; double rayY = 0;
double disT = 0; double disT = 0;
double rayAngle = delta.direction - (dr * 30); double rayAngle = (playerAngle - (dr * 30)).normalizeAngle;
if (rayAngle < 0) {
rayAngle += 2 * math.pi;
}
if (rayAngle > 2 * math.pi) {
rayAngle -= 2 * math.pi;
}
int r; int r;
for (r = 0; r < 60; r++) { for (r = 0; r < 60; r++) {
@@ -492,14 +481,8 @@ class _PlayerState extends State<Player> {
} }
// * Increase the ray angle to draw the next ray // * Increase the ray angle to draw the next ray
rayAngle += dr; rayAngle =
(playerAngle.normalizeAngle - (dr * 30) + r * dr).normalizeAngle;
if (rayAngle < 0) {
rayAngle += 2 * math.pi;
}
if (rayAngle > 2 * math.pi) {
rayAngle -= 2 * math.pi;
}
} }
return rays; return rays;
@@ -608,13 +591,7 @@ class WallPainter extends CustomPainter {
const double dr = math.pi / 180; const double dr = math.pi / 180;
final double rayAngle = playerAngle - (dr * 30) + (i * dr); final double rayAngle = playerAngle - (dr * 30) + (i * dr);
double correctedAngle = playerAngle - rayAngle; final double correctedAngle = (playerAngle - rayAngle).normalizeAngle;
if (correctedAngle < 0) {
correctedAngle += 2 * math.pi;
}
if (correctedAngle > 2 * math.pi) {
correctedAngle -= 2 * math.pi;
}
final double disT = ray.distance * math.cos(correctedAngle); final double disT = ray.distance * math.cos(correctedAngle);