Can now open secret walls and pick up machine gun
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -46,9 +46,20 @@ class DoorManager {
|
||||
return offsets;
|
||||
}
|
||||
|
||||
void tryOpenDoor(int x, int y) {
|
||||
String key = '$x,$y';
|
||||
if (doors.containsKey(key)) {
|
||||
// If it's closed or closing, interact() will usually start it opening
|
||||
if (doors[key]!.offset == 0.0) {
|
||||
doors[key]!.interact();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isDoorOpenEnough(int x, int y) {
|
||||
String key = '$x,$y';
|
||||
if (doors.containsKey(key)) {
|
||||
// 0.7 offset means 70% open, similar to the original engine's check
|
||||
return doors[key]!.offset > 0.7;
|
||||
}
|
||||
return false; // Not a door we manage
|
||||
|
||||
@@ -58,18 +58,26 @@ class BrownGuard extends Enemy {
|
||||
required Coordinate2D playerPosition,
|
||||
required bool Function(int x, int y) isWalkable,
|
||||
required void Function(int damage) onDamagePlayer,
|
||||
required void Function(int x, int y) tryOpenDoor,
|
||||
}) {
|
||||
Coordinate2D movement = const Coordinate2D(0, 0);
|
||||
double newAngle = angle;
|
||||
|
||||
// 1. Wake up logic
|
||||
// 1. Wake up logic (Matches SightPlayer & FirstSighting)
|
||||
if (state == EntityState.idle &&
|
||||
hasLineOfSight(playerPosition, isWalkable)) {
|
||||
state = EntityState.patrolling;
|
||||
lastActionTime = elapsedMs;
|
||||
if (reactionTimeMs == 0) {
|
||||
// Init reaction delay: ~1 to 4 tics in C (1 tic = ~14ms, but plays out longer in engine ticks).
|
||||
// Let's approximate human-feeling reaction time: 200ms - 800ms
|
||||
reactionTimeMs = elapsedMs + 200 + math.Random().nextInt(600);
|
||||
} else if (elapsedMs >= reactionTimeMs) {
|
||||
state =
|
||||
EntityState.patrolling; // Equivalent to FirstSighting chase frame
|
||||
lastActionTime = elapsedMs;
|
||||
reactionTimeMs = 0; // Reset
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Pre-calculate spatial relations
|
||||
double distance = position.distanceTo(playerPosition);
|
||||
double angleToPlayer = position.angleTo(playerPosition);
|
||||
|
||||
@@ -77,7 +85,7 @@ class BrownGuard extends Enemy {
|
||||
newAngle = angleToPlayer;
|
||||
}
|
||||
|
||||
// Calculate Octant for sprite direction
|
||||
// Octant logic remains the same
|
||||
double diff = newAngle - angleToPlayer;
|
||||
while (diff <= -math.pi) {
|
||||
diff += 2 * math.pi;
|
||||
@@ -85,6 +93,7 @@ class BrownGuard extends Enemy {
|
||||
while (diff > math.pi) {
|
||||
diff -= 2 * math.pi;
|
||||
}
|
||||
|
||||
int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
|
||||
if (octant < 0) octant += 8;
|
||||
|
||||
@@ -96,22 +105,34 @@ class BrownGuard extends Enemy {
|
||||
|
||||
case EntityState.patrolling:
|
||||
if (distance > 0.8) {
|
||||
// Calculate movement intent
|
||||
movement =
|
||||
Coordinate2D(math.cos(newAngle), math.sin(newAngle)) * speed;
|
||||
// Jitter fix: Use continuous vector movement instead of single-axis snapping
|
||||
double moveX = math.cos(angleToPlayer) * speed;
|
||||
double moveY = math.sin(angleToPlayer) * speed;
|
||||
|
||||
Coordinate2D intendedMovement = Coordinate2D(moveX, moveY);
|
||||
|
||||
// Pass tryOpenDoor down!
|
||||
movement = getValidMovement(
|
||||
intendedMovement,
|
||||
isWalkable,
|
||||
tryOpenDoor,
|
||||
);
|
||||
}
|
||||
|
||||
// Animation fix: Update the sprite so he actually turns and walks!
|
||||
int walkFrame = (elapsedMs ~/ 150) % 4;
|
||||
spriteIndex = 58 + (walkFrame * 8) + octant;
|
||||
|
||||
if (distance < 5.0 && elapsedMs - lastActionTime > 2000) {
|
||||
// Shooting fix: Give him permission to stop and shoot you
|
||||
// (1500ms delay between shots)
|
||||
if (distance < 6.0 && elapsedMs - lastActionTime > 1500) {
|
||||
if (hasLineOfSight(playerPosition, isWalkable)) {
|
||||
state = EntityState.shooting;
|
||||
lastActionTime = elapsedMs;
|
||||
_hasFiredThisCycle = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break; // Fallthrough fix: Don't forget the break!
|
||||
|
||||
case EntityState.shooting:
|
||||
int timeShooting = elapsedMs - lastActionTime;
|
||||
@@ -152,6 +173,7 @@ class BrownGuard extends Enemy {
|
||||
spriteIndex = 95;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -51,21 +51,28 @@ class Dog extends Enemy {
|
||||
required int elapsedMs,
|
||||
required Coordinate2D playerPosition,
|
||||
required bool Function(int x, int y) isWalkable,
|
||||
required void Function(int x, int y) tryOpenDoor, // NEW
|
||||
required void Function(int damage) onDamagePlayer,
|
||||
}) {
|
||||
Coordinate2D movement = const Coordinate2D(0, 0);
|
||||
double newAngle = angle;
|
||||
|
||||
// 1. Wake up logic
|
||||
if (state == EntityState.idle &&
|
||||
hasLineOfSight(playerPosition, isWalkable)) {
|
||||
state = EntityState.patrolling;
|
||||
lastActionTime = elapsedMs;
|
||||
if (reactionTimeMs == 0) {
|
||||
reactionTimeMs = elapsedMs + 100 + math.Random().nextInt(200);
|
||||
} else if (elapsedMs >= reactionTimeMs) {
|
||||
state = EntityState.patrolling;
|
||||
lastActionTime = elapsedMs;
|
||||
reactionTimeMs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double distance = position.distanceTo(playerPosition);
|
||||
double angleToPlayer = position.angleTo(playerPosition);
|
||||
|
||||
if (state == EntityState.patrolling || state == EntityState.shooting) {
|
||||
if (state != EntityState.idle && state != EntityState.dead) {
|
||||
newAngle = angleToPlayer;
|
||||
}
|
||||
|
||||
@@ -76,36 +83,60 @@ class Dog extends Enemy {
|
||||
while (diff > math.pi) {
|
||||
diff -= 2 * math.pi;
|
||||
}
|
||||
|
||||
int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8;
|
||||
if (octant < 0) octant += 8;
|
||||
|
||||
if (state == EntityState.idle) {
|
||||
spriteIndex = 99 + octant;
|
||||
} else if (state == EntityState.patrolling) {
|
||||
if (distance > 0.8) {
|
||||
movement = Coordinate2D(math.cos(newAngle), math.sin(newAngle)) * speed;
|
||||
}
|
||||
// 3. Clean State Machine
|
||||
switch (state) {
|
||||
case EntityState.idle:
|
||||
spriteIndex = 99 + octant;
|
||||
break;
|
||||
|
||||
int walkFrame = (elapsedMs ~/ 100) % 4;
|
||||
spriteIndex = 107 + (walkFrame * 8) + octant;
|
||||
case EntityState.patrolling:
|
||||
if (distance > 0.8) {
|
||||
double deltaX = playerPosition.x - position.x;
|
||||
double deltaY = playerPosition.y - position.y;
|
||||
|
||||
if (distance < 1.0 && elapsedMs - lastActionTime > 1000) {
|
||||
state = EntityState.shooting;
|
||||
lastActionTime = elapsedMs;
|
||||
_hasBittenThisCycle = false;
|
||||
}
|
||||
} else if (state == EntityState.shooting) {
|
||||
int timeAttacking = elapsedMs - lastActionTime;
|
||||
if (timeAttacking < 200) {
|
||||
spriteIndex = 139;
|
||||
if (!_hasBittenThisCycle) {
|
||||
onDamagePlayer(5); // DOG BITE
|
||||
_hasBittenThisCycle = true;
|
||||
double moveX = deltaX > 0 ? speed : (deltaX < 0 ? -speed : 0);
|
||||
double moveY = deltaY > 0 ? speed : (deltaY < 0 ? -speed : 0);
|
||||
|
||||
Coordinate2D intendedMovement = Coordinate2D(moveX, moveY);
|
||||
|
||||
// Pass tryOpenDoor down!
|
||||
movement = getValidMovement(
|
||||
intendedMovement,
|
||||
isWalkable,
|
||||
tryOpenDoor,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
state = EntityState.patrolling;
|
||||
lastActionTime = elapsedMs;
|
||||
}
|
||||
|
||||
int walkFrame = (elapsedMs ~/ 100) % 4;
|
||||
spriteIndex = 107 + (walkFrame * 8) + octant;
|
||||
|
||||
if (distance < 1.0 && elapsedMs - lastActionTime > 1000) {
|
||||
state = EntityState.shooting;
|
||||
lastActionTime = elapsedMs;
|
||||
_hasBittenThisCycle = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EntityState.shooting:
|
||||
int timeAttacking = elapsedMs - lastActionTime;
|
||||
if (timeAttacking < 200) {
|
||||
spriteIndex = 139;
|
||||
if (!_hasBittenThisCycle) {
|
||||
onDamagePlayer(5);
|
||||
_hasBittenThisCycle = true;
|
||||
}
|
||||
} else {
|
||||
state = EntityState.patrolling;
|
||||
lastActionTime = elapsedMs;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (movement: movement, newAngle: newAngle);
|
||||
|
||||
@@ -14,21 +14,22 @@ abstract class Enemy extends Entity {
|
||||
super.lastActionTime,
|
||||
});
|
||||
|
||||
// Standard guard health
|
||||
int health = 25;
|
||||
int damage = 10;
|
||||
bool isDying = false;
|
||||
bool hasDroppedItem = false;
|
||||
|
||||
// Replaces ob->temp2 for reaction delays
|
||||
int reactionTimeMs = 0;
|
||||
|
||||
void takeDamage(int amount, int currentTime) {
|
||||
if (state == EntityState.dead) return;
|
||||
|
||||
health -= amount;
|
||||
// Mark the start of the death/pain
|
||||
lastActionTime = currentTime;
|
||||
|
||||
if (health <= 0) {
|
||||
state = EntityState.dead;
|
||||
// This triggers the dying animation
|
||||
isDying = true;
|
||||
} else if (math.Random().nextDouble() < 0.5) {
|
||||
state = EntityState.pain;
|
||||
@@ -37,12 +38,9 @@ abstract class Enemy extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
// Decodes the Map ID to figure out which way the enemy is facing
|
||||
static double getInitialAngle(int objId) {
|
||||
int normalizedId = (objId - 108) % 36;
|
||||
// 0=East, 1=North, 2=West, 3=South
|
||||
int direction = normalizedId % 4;
|
||||
|
||||
switch (direction) {
|
||||
case 0:
|
||||
return 0.0;
|
||||
@@ -57,14 +55,19 @@ abstract class Enemy extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
// The enemy can now check its own line of sight!
|
||||
// Matches WL_STATE.C's 'CheckLine' using canonical Integer DDA traversal
|
||||
bool hasLineOfSight(
|
||||
Coordinate2D playerPosition,
|
||||
bool Function(int x, int y) isWalkable,
|
||||
) {
|
||||
double distance = position.distanceTo(playerPosition);
|
||||
// 1. Proximity Check (Matches WL_STATE.C 'MINSIGHT')
|
||||
// If the player is very close, sight is automatic regardless of facing angle.
|
||||
// This compensates for our lack of a noise/gunshot alert system!
|
||||
if (position.distanceTo(playerPosition) < 2.0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 1. FOV Check
|
||||
// 2. FOV Check (Matches original sight angles)
|
||||
double angleToPlayer = position.angleTo(playerPosition);
|
||||
double diff = angle - angleToPlayer;
|
||||
|
||||
@@ -77,40 +80,92 @@ abstract class Enemy extends Entity {
|
||||
|
||||
if (diff.abs() > math.pi / 2) return false;
|
||||
|
||||
// 2. Map Check
|
||||
Coordinate2D dir = (playerPosition - position).normalized;
|
||||
double stepSize = 0.2;
|
||||
// 3. Map Check (Corrected Integer Bresenham)
|
||||
int currentX = position.x.toInt();
|
||||
int currentY = position.y.toInt();
|
||||
int targetX = playerPosition.x.toInt();
|
||||
int targetY = playerPosition.y.toInt();
|
||||
|
||||
for (double i = 0; i < distance; i += stepSize) {
|
||||
Coordinate2D checkPos = position + (dir * i);
|
||||
if (!isWalkable(checkPos.x.toInt(), checkPos.y.toInt())) return false;
|
||||
int dx = (targetX - currentX).abs();
|
||||
int dy = -(targetY - currentY).abs();
|
||||
int sx = currentX < targetX ? 1 : -1;
|
||||
int sy = currentY < targetY ? 1 : -1;
|
||||
int err = dx + dy;
|
||||
|
||||
while (true) {
|
||||
if (!isWalkable(currentX, currentY)) return false;
|
||||
if (currentX == targetX && currentY == targetY) break;
|
||||
|
||||
int e2 = 2 * err;
|
||||
if (e2 >= dy) {
|
||||
err += dy;
|
||||
currentX += sx;
|
||||
}
|
||||
if (e2 <= dx) {
|
||||
err += dx;
|
||||
currentY += sy;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The weapon asks the enemy if it is unobstructed from the shooter
|
||||
bool hasLineOfSightFrom(
|
||||
Coordinate2D source,
|
||||
double sourceAngle,
|
||||
double distance,
|
||||
Coordinate2D getValidMovement(
|
||||
Coordinate2D intendedMovement,
|
||||
bool Function(int x, int y) isWalkable,
|
||||
void Function(int x, int y) tryOpenDoor,
|
||||
) {
|
||||
double dirX = math.cos(sourceAngle);
|
||||
double dirY = math.sin(sourceAngle);
|
||||
double newX = position.x + intendedMovement.x;
|
||||
double newY = position.y + intendedMovement.y;
|
||||
|
||||
for (double i = 0.5; i < distance; i += 0.2) {
|
||||
int checkX = (source.x + dirX * i).toInt();
|
||||
int checkY = (source.y + dirY * i).toInt();
|
||||
if (!isWalkable(checkX, checkY)) return false;
|
||||
int currentTileX = position.x.toInt();
|
||||
int currentTileY = position.y.toInt();
|
||||
int targetTileX = newX.toInt();
|
||||
int targetTileY = newY.toInt();
|
||||
|
||||
bool movedX = currentTileX != targetTileX;
|
||||
bool movedY = currentTileY != targetTileY;
|
||||
|
||||
// 1. Check Diagonal Movement
|
||||
if (movedX && movedY) {
|
||||
bool canMoveX = isWalkable(targetTileX, currentTileY);
|
||||
bool canMoveY = isWalkable(currentTileX, targetTileY);
|
||||
bool canMoveDiag = isWalkable(targetTileX, targetTileY);
|
||||
|
||||
if (!canMoveX || !canMoveY || !canMoveDiag) {
|
||||
// Trigger doors if they are blocking the path
|
||||
if (!canMoveX) tryOpenDoor(targetTileX, currentTileY);
|
||||
if (!canMoveY) tryOpenDoor(currentTileX, targetTileY);
|
||||
if (!canMoveDiag) tryOpenDoor(targetTileX, targetTileY);
|
||||
|
||||
if (canMoveX) return Coordinate2D(intendedMovement.x, 0);
|
||||
if (canMoveY) return Coordinate2D(0, intendedMovement.y);
|
||||
return const Coordinate2D(0, 0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// 2. Check Cardinal Movement
|
||||
if (movedX && !movedY) {
|
||||
if (!isWalkable(targetTileX, currentTileY)) {
|
||||
tryOpenDoor(targetTileX, currentTileY); // Try to open!
|
||||
return Coordinate2D(0, intendedMovement.y);
|
||||
}
|
||||
}
|
||||
if (movedY && !movedX) {
|
||||
if (!isWalkable(currentTileX, targetTileY)) {
|
||||
tryOpenDoor(currentTileX, targetTileY); // Try to open!
|
||||
return Coordinate2D(intendedMovement.x, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return intendedMovement;
|
||||
}
|
||||
|
||||
// Updated Signature
|
||||
({Coordinate2D movement, double newAngle}) update({
|
||||
required int elapsedMs,
|
||||
required Coordinate2D playerPosition,
|
||||
required bool Function(int x, int y) isWalkable,
|
||||
required void Function(int x, int y) tryOpenDoor, // NEW
|
||||
required void Function(int damage) onDamagePlayer,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,4 +27,40 @@ abstract class Entity<T> {
|
||||
}
|
||||
|
||||
Coordinate2D get position => Coordinate2D(x, y);
|
||||
|
||||
// NEW: Checks if a projectile or sightline from 'source' can reach this entity
|
||||
bool hasLineOfSightFrom(
|
||||
Coordinate2D source,
|
||||
double sourceAngle,
|
||||
double distance,
|
||||
bool Function(int x, int y) isWalkable,
|
||||
) {
|
||||
// Corrected Integer Bresenham Algorithm
|
||||
int currentX = source.x.toInt();
|
||||
int currentY = source.y.toInt();
|
||||
int targetX = x.toInt();
|
||||
int targetY = y.toInt();
|
||||
|
||||
int dx = (targetX - currentX).abs();
|
||||
int dy = -(targetY - currentY).abs();
|
||||
int sx = currentX < targetX ? 1 : -1;
|
||||
int sy = currentY < targetY ? 1 : -1;
|
||||
int err = dx + dy;
|
||||
|
||||
while (true) {
|
||||
if (!isWalkable(currentX, currentY)) return false;
|
||||
if (currentX == targetX && currentY == targetY) break;
|
||||
|
||||
int e2 = 2 * err;
|
||||
if (e2 >= dy) {
|
||||
err += dy;
|
||||
currentX += sx;
|
||||
}
|
||||
if (e2 <= dx) {
|
||||
err += dx;
|
||||
currentY += sy;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,11 @@ typedef EntitySpawner =
|
||||
);
|
||||
|
||||
abstract class EntityRegistry {
|
||||
// Add future enemies (SSGuard, Dog, etc.) to this list!
|
||||
static final List<EntitySpawner> _spawners = [
|
||||
Collectible.trySpawn, // Check collectibles
|
||||
Decorative.trySpawn, // Then check decorations
|
||||
BrownGuard.trySpawn, // Then check guards
|
||||
Dog.trySpawn, // Then check dogs
|
||||
BrownGuard.trySpawn,
|
||||
Dog.trySpawn,
|
||||
Collectible.trySpawn,
|
||||
Decorative.trySpawn,
|
||||
];
|
||||
|
||||
static Entity? spawn(
|
||||
|
||||
121
lib/features/entities/pushwall_manager.dart
Normal file
121
lib/features/entities/pushwall_manager.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:wolf_dart/classes/matrix.dart';
|
||||
|
||||
class Pushwall {
|
||||
int x;
|
||||
int y;
|
||||
int mapId; // The wall texture ID
|
||||
int dirX = 0;
|
||||
int dirY = 0;
|
||||
double offset = 0.0;
|
||||
int tilesMoved = 0;
|
||||
|
||||
Pushwall(this.x, this.y, this.mapId);
|
||||
}
|
||||
|
||||
class PushwallManager {
|
||||
final Map<String, Pushwall> pushwalls = {};
|
||||
Pushwall? activePushwall;
|
||||
|
||||
void initPushwalls(Matrix<int> wallGrid, Matrix<int> objectGrid) {
|
||||
pushwalls.clear();
|
||||
activePushwall = null;
|
||||
|
||||
for (int y = 0; y < objectGrid.length; y++) {
|
||||
for (int x = 0; x < objectGrid[y].length; x++) {
|
||||
// Map ID 98 in the object grid marks a pushwall!
|
||||
if (objectGrid[y][x] == 98) {
|
||||
pushwalls['$x,$y'] = Pushwall(x, y, wallGrid[y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update(Duration elapsed, Matrix<int> wallGrid) {
|
||||
if (activePushwall == null) return;
|
||||
final pw = activePushwall!;
|
||||
|
||||
// Original logic: 1/128 tile per tick.
|
||||
// At 70 ticks/sec, that is roughly 0.54 tiles per second.
|
||||
const double originalSpeed = 0.546875;
|
||||
pw.offset += (elapsed.inMilliseconds / 1000.0) * originalSpeed;
|
||||
|
||||
// Once it crosses a full tile boundary, we update the collision grid!
|
||||
if (pw.offset >= 1.0) {
|
||||
pw.offset -= 1.0;
|
||||
pw.tilesMoved++;
|
||||
|
||||
int nextX = pw.x + pw.dirX;
|
||||
int nextY = pw.y + pw.dirY;
|
||||
|
||||
// Move the solid block in the physical grid
|
||||
wallGrid[nextY][nextX] = pw.mapId;
|
||||
wallGrid[pw.y][pw.x] = 0; // Clear the old space so the player can walk in
|
||||
|
||||
// Update the dictionary key
|
||||
pushwalls.remove('${pw.x},${pw.y}');
|
||||
pw.x = nextX;
|
||||
pw.y = nextY;
|
||||
pushwalls['${pw.x},${pw.y}'] = pw;
|
||||
|
||||
// Check if we should keep sliding
|
||||
bool blocked = false;
|
||||
int checkX = pw.x + pw.dirX;
|
||||
int checkY = pw.y + pw.dirY;
|
||||
|
||||
if (checkX < 0 ||
|
||||
checkX >= wallGrid[0].length ||
|
||||
checkY < 0 ||
|
||||
checkY >= wallGrid.length) {
|
||||
blocked = true;
|
||||
} else if (wallGrid[checkY][checkX] != 0) {
|
||||
blocked = true; // Blocked by another wall or a door
|
||||
}
|
||||
|
||||
// Standard Wolf3D pushwalls move exactly 2 tiles (or 1 if blocked)
|
||||
if (pw.tilesMoved >= 2 || blocked) {
|
||||
activePushwall = null;
|
||||
pw.offset = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleInteraction(
|
||||
double playerX,
|
||||
double playerY,
|
||||
double playerAngle,
|
||||
Matrix<int> wallGrid,
|
||||
) {
|
||||
// Only one pushwall can move at a time in the original engine!
|
||||
if (activePushwall != null) return;
|
||||
|
||||
int targetX = (playerX + math.cos(playerAngle)).toInt();
|
||||
int targetY = (playerY + math.sin(playerAngle)).toInt();
|
||||
|
||||
String key = '$targetX,$targetY';
|
||||
if (pushwalls.containsKey(key)) {
|
||||
final pw = pushwalls[key]!;
|
||||
|
||||
// Determine the push direction based on the player's relative position
|
||||
double dx = (targetX + 0.5) - playerX;
|
||||
double dy = (targetY + 0.5) - playerY;
|
||||
|
||||
if (dx.abs() > dy.abs()) {
|
||||
pw.dirX = dx > 0 ? 1 : -1;
|
||||
pw.dirY = 0;
|
||||
} else {
|
||||
pw.dirX = 0;
|
||||
pw.dirY = dy > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
// Make sure the tile behind the wall is empty before starting the push
|
||||
int checkX = targetX + pw.dirX;
|
||||
int checkY = targetY + pw.dirY;
|
||||
|
||||
if (wallGrid[checkY][checkX] == 0) {
|
||||
activePushwall = pw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user