Files
wolf_dart/lib/features/entities/pushwall_manager.dart

122 lines
3.3 KiB
Dart

import 'dart:math' as math;
import 'package:wolf_dart/classes/matrix.dart';
import 'package:wolf_dart/features/entities/map_objects.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++) {
if (objectGrid[y][x] == MapObjectId.secretDoor) {
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;
}
}
}
}