Almost done with spatial stuff.

This commit is contained in:
Kapendev 2025-03-15 12:41:37 +02:00
parent dcb49d6cdd
commit 915b6f92a8
3 changed files with 79 additions and 47 deletions

View file

@ -10,9 +10,9 @@
module parin.engine;
import rl = parin.rl;
import stdc = joka.stdc;
import joka.ascii;
import joka.io;
import joka.memory;
public import joka.containers;
public import joka.math;
public import joka.types;
@ -1257,8 +1257,8 @@ void openUrl(IStr url = "https://github.com/Kapendev/parin") {
@trusted
void openWindow(int width, int height, const(IStr)[] args, IStr title = "Parin") {
if (rl.IsWindowReady) return;
engineState = cast(EngineState*) stdc.malloc(EngineState.sizeof);
stdc.memset(engineState, 0, EngineState.sizeof);
engineState = cast(EngineState*) jokaMalloc(EngineState.sizeof);
jokaMemset(engineState, 0, EngineState.sizeof);
// Raylib stuff.
rl.SetConfigFlags(rl.FLAG_WINDOW_RESIZABLE | rl.FLAG_VSYNC_HINT);
rl.SetTraceLogLevel(rl.LOG_ERROR);
@ -1411,7 +1411,7 @@ void closeWindow() {
engineState.loadTextBuffer.free();
engineState.saveTextBuffer.free();
engineState.assetsPath.free();
stdc.free(engineState);
jokaFree(engineState);
engineState = null;
rl.CloseAudioDevice();
rl.CloseWindow();
@ -1918,34 +1918,28 @@ dchar dequeuePressedRune() {
/// Returns the directional input based on the WASD and arrow keys when they are down.
/// The vector is not normalized.
Vec2 wasd() {
auto result = Vec2();
if (Keyboard.w.isDown || Keyboard.up.isDown) result.y -= 1.0f;
if (Keyboard.a.isDown || Keyboard.left.isDown) result.x -= 1.0f;
if (Keyboard.s.isDown || Keyboard.down.isDown) result.y += 1.0f;
if (Keyboard.d.isDown || Keyboard.right.isDown) result.x += 1.0f;
return result;
with (Keyboard) return Vec2(
(d.isDown || right.isDown) - (a.isDown || left.isDown),
(s.isDown || down.isDown) - (w.isDown || up.isDown),
);
}
/// Returns the directional input based on the WASD and arrow keys when they are pressed.
/// The vector is not normalized.
Vec2 wasdPressed() {
auto result = Vec2();
if (Keyboard.w.isPressed || Keyboard.up.isPressed) result.y -= 1.0f;
if (Keyboard.a.isPressed || Keyboard.left.isPressed) result.x -= 1.0f;
if (Keyboard.s.isPressed || Keyboard.down.isPressed) result.y += 1.0f;
if (Keyboard.d.isPressed || Keyboard.right.isPressed) result.x += 1.0f;
return result;
with (Keyboard) return Vec2(
(d.isPressed || right.isPressed) - (a.isPressed || left.isPressed),
(s.isPressed || down.isPressed) - (w.isPressed || up.isPressed),
);
}
/// Returns the directional input based on the WASD and arrow keys when they are released.
/// The vector is not normalized.
Vec2 wasdReleased() {
auto result = Vec2();
if (Keyboard.w.isReleased || Keyboard.up.isReleased) result.y -= 1.0f;
if (Keyboard.a.isReleased || Keyboard.left.isReleased) result.x -= 1.0f;
if (Keyboard.s.isReleased || Keyboard.down.isReleased) result.y += 1.0f;
if (Keyboard.d.isReleased || Keyboard.right.isReleased) result.x += 1.0f;
return result;
with (Keyboard) return Vec2(
(d.isReleased || right.isReleased) - (a.isReleased || left.isReleased),
(s.isReleased || down.isReleased) - (w.isReleased || up.isReleased),
);
}
/// Plays the specified sound.

View file

@ -155,12 +155,12 @@ struct BoxWorld {
foreach (i, ref properties; wallsProperties) {
auto id = cast(BaseBoxId) (i + 1);
auto point = getWallGridPoint(id);
grid[point.y, point.x].append(id & ~taggedBoxTagBit);
if (hasGridPoint(point)) grid[point.y, point.x].append(id & ~taggedBoxTagBit);
}
foreach (i, ref properties; actorsProperties) {
auto id = cast(BaseBoxId) (i + 1);
auto point = getActorGridPoint(id);
grid[point.y, point.x].append(id | taggedBoxTagBit);
if (hasGridPoint(point)) grid[point.y, point.x].append(id | taggedBoxTagBit);
}
}
@ -171,6 +171,7 @@ struct BoxWorld {
}
IVec2 getGridPoint(IRect box) {
if (!grid.length) assert(0, "Can't get a grid point from a disabled grid.");
return IVec2(
box.position.x / gridTileWidth - (box.position.x < 0),
box.position.y / gridTileHeight - (box.position.y < 0),
@ -207,6 +208,10 @@ struct BoxWorld {
return getGridPoint(actors[id - 1]);
}
bool hasGridPoint(IVec2 point) {
return point.x >= 0 && point.y >= 0 && grid.has(point.y, point.x);
}
WallBoxId appendWall(IRect box, OneWaySide oneWaySide = OneWaySide.none) {
walls.append(box);
wallsProperties.append(WallBoxProperties());
@ -214,8 +219,7 @@ struct BoxWorld {
auto id = cast(BaseBoxId) walls.length;
if (grid.length) {
auto point = getGridPoint(box);
if (box.position.x < 0 || box.position.y < 0 || !grid.has(point.y, point.x)) return id;
grid[point.y, point.x].append(id & ~taggedBoxTagBit);
if (hasGridPoint(point)) grid[point.y, point.x].append(id & ~taggedBoxTagBit);
}
return id;
}
@ -227,65 +231,76 @@ struct BoxWorld {
auto id = cast(BaseBoxId) actors.length;
if (grid.length) {
auto point = getGridPoint(box);
if (box.position.x < 0 || box.position.y < 0 || !grid.has(point.y, point.x)) return id;
grid[point.y, point.x].append(id | taggedBoxTagBit);
if (hasGridPoint(point)) grid[point.y, point.x].append(id | taggedBoxTagBit);
}
return id;
}
WallBoxId[] getWallCollisions(IRect box) {
WallBoxId[] getWallCollisions(IRect box, bool canStopAtFirst = false) {
collisionIdsBuffer.clear();
// TODO: Try not going over every neighboring cell please...
if (grid.length) {
auto point = getGridPoint(box);
foreach (y; -1 .. 2) { foreach (x; -1 .. 2) {
auto otherPoint = IVec2(point.x + x, point.y + y);
if (otherPoint.x < 0 || otherPoint.y < 0 || !grid.has(otherPoint.y, otherPoint.x)) continue;
foreach (taggedId; grid[point.y + y, point.x + x]) {
if (!hasGridPoint(otherPoint)) continue;
foreach (taggedId; grid[otherPoint.y, otherPoint.x]) {
auto i = (taggedId & ~taggedBoxTagBit) - 1;
auto isActor = taggedId & taggedBoxTagBit;
if (isActor) continue;
if (walls[i].hasIntersection(box) && ~wallsProperties[i].flags & boxPassableFlag) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (walls[i].hasIntersection(box) && ~wallsProperties[i].flags & boxPassableFlag) {
collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (canStopAtFirst) return collisionIdsBuffer[];
}
}
}}
} else {
foreach (i, wall; walls) {
if (wall.hasIntersection(box) && ~wallsProperties[i].flags & boxPassableFlag) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (wall.hasIntersection(box) && ~wallsProperties[i].flags & boxPassableFlag) {
collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (canStopAtFirst) return collisionIdsBuffer[];
}
}
}
return collisionIdsBuffer[];
}
ActorBoxId[] getActorCollisions(IRect box) {
ActorBoxId[] getActorCollisions(IRect box, bool canStopAtFirst = false) {
collisionIdsBuffer.clear();
// TODO: Try not going over every neighboring cell please...
if (grid.length) {
auto point = getGridPoint(box);
foreach (y; -1 .. 2) { foreach (x; -1 .. 2) {
auto otherPoint = IVec2(point.x + x, point.y + y);
if (otherPoint.x < 0 || otherPoint.y < 0 || !grid.has(otherPoint.y, otherPoint.x)) continue;
foreach (taggedId; grid[point.y + y, point.x + x]) {
if (!hasGridPoint(otherPoint)) continue;
foreach (taggedId; grid[otherPoint.y, otherPoint.x]) {
auto i = (taggedId & ~taggedBoxTagBit) - 1;
auto isWall = !(taggedId & taggedBoxTagBit);
if (isWall) continue;
if (actors[i].hasIntersection(box) && ~actorsProperties[i].flags & boxPassableFlag) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (actors[i].hasIntersection(box) && ~actorsProperties[i].flags & boxPassableFlag) {
collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (canStopAtFirst) return collisionIdsBuffer[];
}
}
}}
} else {
foreach (i, actor; actors) {
if (actor.hasIntersection(box) && ~actorsProperties[i].flags & boxPassableFlag) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (actor.hasIntersection(box) && ~actorsProperties[i].flags & boxPassableFlag) {
collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
if (canStopAtFirst) return collisionIdsBuffer[];
}
}
}
return collisionIdsBuffer[];
}
WallBoxId hasWallCollision(IRect box) {
auto boxes = getWallCollisions(box);
auto boxes = getWallCollisions(box, true);
return boxes.length ? boxes[0] : 0;
}
ActorBoxId hasActorCollision(IRect box) {
auto boxes = getActorCollisions(box);
auto boxes = getActorCollisions(box, true);
return boxes.length ? boxes[0] : 0;
}
@ -323,8 +338,31 @@ struct BoxWorld {
if (~properties.flags & boxPassableFlag && wallId) {
return wallId;
} else {
actor.position.x += moveSign;
move -= moveSign;
if (grid.length) {
auto oldPoint = getGridPoint(*actor);
actor.position.x += moveSign;
move -= moveSign;
auto newPoint = getGridPoint(*actor);
// TODO: Maybe think of how not to write this again. ...
if (oldPoint != newPoint) {
if (hasGridPoint(oldPoint)) {
foreach (j, taggedId; grid[oldPoint.y, oldPoint.x]) {
auto i = (taggedId & ~taggedBoxTagBit) - 1;
auto isActor = taggedId & taggedBoxTagBit;
if (isActor && (i + 1 == id)) {
grid[oldPoint.y, oldPoint.x].remove(j);
break;
}
}
}
if (hasGridPoint(newPoint)) {
grid[newPoint.y, newPoint.x].append(id | taggedBoxTagBit);
}
}
} else {
actor.position.x += moveSign;
move -= moveSign;
}
}
}
return 0;

View file

@ -10,8 +10,8 @@
module parin.ui;
import rl = parin.rl;
import stdc = joka.stdc;
import joka.ascii;
import joka.memory;
import parin.engine;
@safe @nogc nothrow:
@ -112,10 +112,10 @@ int findSpaceInTextField(IStr text) {
void prepareUi() {
if (uiState == null) {
// NOTE: This leaks. THIS IS SO BAD WHERE IS `Box::leak` IN THIS CODEBASE???
uiState = cast(UiState*) stdc.malloc(UiState.sizeof);
uiPreviousState = cast(UiState*) stdc.malloc(UiState.sizeof);
stdc.memset(uiState, 0, UiState.sizeof);
stdc.memset(uiPreviousState, 0, UiState.sizeof);
uiState = cast(UiState*) jokaMalloc(UiState.sizeof);
uiPreviousState = cast(UiState*) jokaMalloc(UiState.sizeof);
jokaMemset(uiState, 0, UiState.sizeof);
jokaMemset(uiPreviousState, 0, UiState.sizeof);
// TODO: Should be changed to something better looking.
uiState.mouseClickAction = Mouse.left;
uiState.keyboardClickAction = Keyboard.enter;