mirror of
https://github.com/Kapendev/parin.git
synced 2025-05-04 17:09:57 +03:00
More joka changes and map change and engineState is now a pointer.
This commit is contained in:
parent
cf8f71cfaa
commit
14ce68833c
4 changed files with 154 additions and 154 deletions
|
@ -10,18 +10,16 @@
|
||||||
module parin.engine;
|
module parin.engine;
|
||||||
|
|
||||||
import rl = parin.rl;
|
import rl = parin.rl;
|
||||||
|
import stdc = joka.stdc;
|
||||||
import joka.ascii;
|
import joka.ascii;
|
||||||
import joka.io;
|
import joka.io;
|
||||||
import joka.unions;
|
|
||||||
public import joka.containers;
|
public import joka.containers;
|
||||||
public import joka.faults;
|
|
||||||
public import joka.math;
|
public import joka.math;
|
||||||
public import joka.types;
|
public import joka.types;
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
EngineState engineState;
|
EngineState* engineState;
|
||||||
|
|
||||||
enum defaultEngineFontsCapacity = 64;
|
enum defaultEngineFontsCapacity = 64;
|
||||||
enum defaultEngineResourcesCapacity = 256;
|
enum defaultEngineResourcesCapacity = 256;
|
||||||
|
@ -1272,6 +1270,7 @@ void openUrl(IStr url = "https://github.com/Kapendev/parin") {
|
||||||
@trusted
|
@trusted
|
||||||
void openWindow(int width, int height, const(IStr)[] args, IStr title = "Parin") {
|
void openWindow(int width, int height, const(IStr)[] args, IStr title = "Parin") {
|
||||||
if (rl.IsWindowReady) return;
|
if (rl.IsWindowReady) return;
|
||||||
|
engineState = cast(EngineState*) stdc.malloc(EngineState.sizeof);
|
||||||
engineState.envArgsBuffer.clear();
|
engineState.envArgsBuffer.clear();
|
||||||
foreach (arg; args) engineState.envArgsBuffer.append(arg);
|
foreach (arg; args) engineState.envArgsBuffer.append(arg);
|
||||||
// Set raylib stuff.
|
// Set raylib stuff.
|
||||||
|
@ -1429,6 +1428,8 @@ void closeWindow() {
|
||||||
engineState.loadTextBuffer.free();
|
engineState.loadTextBuffer.free();
|
||||||
engineState.saveTextBuffer.free();
|
engineState.saveTextBuffer.free();
|
||||||
engineState.assetsPath.free();
|
engineState.assetsPath.free();
|
||||||
|
stdc.free(engineState);
|
||||||
|
engineState = null;
|
||||||
}
|
}
|
||||||
// This is outside because who knows, maybe raylib needs that.
|
// This is outside because who knows, maybe raylib needs that.
|
||||||
rl.CloseAudioDevice();
|
rl.CloseAudioDevice();
|
||||||
|
|
|
@ -59,27 +59,26 @@ struct Tile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Look at it again now with the Grid changes. It works, I know that :)
|
||||||
|
// NOTE: Things like changing the grid row count might be interesting.
|
||||||
struct TileMap {
|
struct TileMap {
|
||||||
Grid!short data;
|
Grid!short data;
|
||||||
Sz softMaxRowCount;
|
Sz softRowCount;
|
||||||
Sz softMaxColCount;
|
Sz softColCount;
|
||||||
int tileWidth = 16;
|
int tileWidth = 16;
|
||||||
int tileHeight = 16;
|
int tileHeight = 16;
|
||||||
Vec2 position;
|
Vec2 position;
|
||||||
|
|
||||||
enum maxRowCount = data.maxRowCount;
|
|
||||||
enum maxColCount = data.maxColCount;
|
|
||||||
enum maxCapacity = data.maxCapacity;
|
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
this(int tileWidth, int tileHeight, Vec2 position = Vec2()) {
|
this(Sz rowCount, Sz colCount, int tileWidth, int tileHeight) {
|
||||||
this.tileWidth = tileWidth;
|
this.tileWidth = tileWidth;
|
||||||
this.tileHeight = tileHeight;
|
this.tileHeight = tileHeight;
|
||||||
this.softMaxRowCount = maxRowCount;
|
resizeHard(rowCount, colCount);
|
||||||
this.softMaxColCount = maxColCount;
|
}
|
||||||
this.position = position;
|
|
||||||
this.data.fill(-1);
|
this(int tileWidth, int tileHeight) {
|
||||||
|
this(defaultGridRowCount, defaultGridColCount, tileWidth, tileHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref short opIndex(Sz row, Sz col) {
|
ref short opIndex(Sz row, Sz col) {
|
||||||
|
@ -116,21 +115,7 @@ struct TileMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
Sz opDollar(Sz dim)() {
|
Sz opDollar(Sz dim)() {
|
||||||
static if (dim == 0) {
|
return data.opDollar!dim();
|
||||||
return rowCount;
|
|
||||||
} else static if (dim == 1) {
|
|
||||||
return colCount;
|
|
||||||
} else {
|
|
||||||
assert(0, "WTF!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Sz rowCount() {
|
|
||||||
return data.length ? softMaxRowCount : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sz colCount() {
|
|
||||||
return data.length ? softMaxColCount : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
|
@ -138,29 +123,50 @@ struct TileMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has(Sz row, Sz col) {
|
bool has(Sz row, Sz col) {
|
||||||
return row < rowCount && col < colCount;
|
return row < softRowCount && col < softColCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has(IVec2 position) {
|
bool has(IVec2 position) {
|
||||||
return has(position.y, position.x);
|
return has(position.y, position.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@trusted
|
Sz hardRowCount() {
|
||||||
|
return data.rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sz hardColCount() {
|
||||||
|
return data.colCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resizeHard(Sz newHardRowCount, Sz newHardColCount) {
|
||||||
|
data.resizeBlank(newHardRowCount, newHardColCount);
|
||||||
|
data.fill(-1);
|
||||||
|
softRowCount = newHardRowCount;
|
||||||
|
softColCount = newHardColCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resizeSoft(Sz newSoftRowCount, Sz newSoftColCount) {
|
||||||
|
if (newSoftRowCount > hardRowCount || newSoftColCount > hardColCount) {
|
||||||
|
assert(0, "Soft count must be smaller than hard count.");
|
||||||
|
}
|
||||||
|
softRowCount = newSoftRowCount;
|
||||||
|
softColCount = newSoftColCount;
|
||||||
|
}
|
||||||
|
|
||||||
void fill(short value) {
|
void fill(short value) {
|
||||||
data.fill(value);
|
data.fill(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@trusted
|
|
||||||
void free() {
|
void free() {
|
||||||
data.free();
|
data.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
int width() {
|
int width() {
|
||||||
return cast(int) (colCount * tileWidth);
|
return cast(int) (softColCount * tileWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
int height() {
|
int height() {
|
||||||
return cast(int) (rowCount * tileHeight);
|
return cast(int) (softRowCount * tileHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size of the tile map.
|
/// Returns the size of the tile map.
|
||||||
|
@ -173,25 +179,27 @@ struct TileMap {
|
||||||
return Vec2(tileWidth, tileHeight);
|
return Vec2(tileWidth, tileHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fault parse(IStr csv, int tileWidth, int tileHeight) {
|
Fault parse(IStr csv, int newTileWidth, int newTileHeight) {
|
||||||
if (csv.length == 0) return Fault.invalid;
|
if (csv.length == 0) return Fault.invalid;
|
||||||
this.tileWidth = tileWidth;
|
if (data.isEmpty) {
|
||||||
this.tileHeight = tileHeight;
|
data.resizeBlank(defaultGridRowCount, defaultGridColCount);
|
||||||
this.softMaxRowCount = 0;
|
}
|
||||||
this.softMaxColCount = 0;
|
tileWidth = newTileWidth;
|
||||||
this.data.fill(-1);
|
tileHeight = newTileHeight;
|
||||||
|
softRowCount = 0;
|
||||||
|
softColCount = 0;
|
||||||
auto view = csv;
|
auto view = csv;
|
||||||
while (view.length != 0) {
|
while (view.length != 0) {
|
||||||
softMaxRowCount += 1;
|
softRowCount += 1;
|
||||||
softMaxColCount = 0;
|
softColCount = 0;
|
||||||
if (softMaxRowCount > maxRowCount) return Fault.invalid;
|
if (softRowCount > data.rowCount) return Fault.invalid;
|
||||||
auto line = view.skipLine();
|
auto line = view.skipLine();
|
||||||
while (line.length != 0) {
|
while (line.length != 0) {
|
||||||
softMaxColCount += 1;
|
softColCount += 1;
|
||||||
if (softMaxColCount > maxColCount) return Fault.invalid;
|
if (softColCount > data.colCount) return Fault.invalid;
|
||||||
auto tile = line.skipValue(',').toSigned();
|
auto tile = line.skipValue(',').toSigned();
|
||||||
if (tile.isNone) return Fault.invalid;
|
if (tile.isNone) return Fault.invalid;
|
||||||
data[softMaxRowCount - 1, softMaxColCount - 1] = cast(short) tile.get();
|
data[softRowCount - 1, softColCount - 1] = cast(short) tile.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Fault.none;
|
return Fault.none;
|
||||||
|
@ -226,23 +234,23 @@ struct TileMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
IVec2 firstGridPosition(Vec2 topLeftWorldPosition, DrawOptions options = DrawOptions()) {
|
IVec2 firstGridPosition(Vec2 topLeftWorldPosition, DrawOptions options = DrawOptions()) {
|
||||||
if (rowCount == 0 || colCount == 0) return IVec2();
|
if (softRowCount == 0 || softColCount == 0) return IVec2();
|
||||||
auto result = IVec2();
|
auto result = IVec2();
|
||||||
auto targetTileWidth = cast(int) (tileWidth * options.scale.x);
|
auto targetTileWidth = cast(int) (tileWidth * options.scale.x);
|
||||||
auto targetTileHeight = cast(int) (tileHeight * options.scale.y);
|
auto targetTileHeight = cast(int) (tileHeight * options.scale.y);
|
||||||
result.y = cast(int) floor(clamp((topLeftWorldPosition.y - position.y) / targetTileHeight, 0, rowCount - 1));
|
result.y = cast(int) floor(clamp((topLeftWorldPosition.y - position.y) / targetTileHeight, 0, softRowCount - 1));
|
||||||
result.x = cast(int) floor(clamp((topLeftWorldPosition.x - position.x) / targetTileWidth, 0, colCount - 1));
|
result.x = cast(int) floor(clamp((topLeftWorldPosition.x - position.x) / targetTileWidth, 0, softColCount - 1));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
IVec2 lastGridPosition(Vec2 bottomRightWorldPosition, DrawOptions options = DrawOptions()) {
|
IVec2 lastGridPosition(Vec2 bottomRightWorldPosition, DrawOptions options = DrawOptions()) {
|
||||||
if (rowCount == 0 || colCount == 0) return IVec2();
|
if (softRowCount == 0 || softColCount == 0) return IVec2();
|
||||||
auto result = IVec2();
|
auto result = IVec2();
|
||||||
auto targetTileWidth = cast(int) (tileWidth * options.scale.x);
|
auto targetTileWidth = cast(int) (tileWidth * options.scale.x);
|
||||||
auto targetTileHeight = cast(int) (tileHeight * options.scale.y);
|
auto targetTileHeight = cast(int) (tileHeight * options.scale.y);
|
||||||
auto extraTileCount = options.hook == Hook.topLeft ? 1 : 2;
|
auto extraTileCount = options.hook == Hook.topLeft ? 1 : 2;
|
||||||
result.y = cast(int) floor(clamp((bottomRightWorldPosition.y - position.y) / targetTileHeight + extraTileCount, 0, rowCount - 1));
|
result.y = cast(int) floor(clamp((bottomRightWorldPosition.y - position.y) / targetTileHeight + extraTileCount, 0, softRowCount - 1));
|
||||||
result.x = cast(int) floor(clamp((bottomRightWorldPosition.x - position.x) / targetTileWidth + extraTileCount, 0, colCount - 1));
|
result.x = cast(int) floor(clamp((bottomRightWorldPosition.x - position.x) / targetTileWidth + extraTileCount, 0, softColCount - 1));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +279,7 @@ struct TileMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = Range(
|
auto result = Range(
|
||||||
colCount,
|
softColCount,
|
||||||
firstGridPosition(topLeftWorldPosition, options),
|
firstGridPosition(topLeftWorldPosition, options),
|
||||||
lastGridPosition(bottomRightWorldPosition, options),
|
lastGridPosition(bottomRightWorldPosition, options),
|
||||||
);
|
);
|
||||||
|
@ -286,10 +294,10 @@ struct TileMap {
|
||||||
|
|
||||||
Fault saveTileMap(IStr path, TileMap map) {
|
Fault saveTileMap(IStr path, TileMap map) {
|
||||||
auto csv = prepareTempText();
|
auto csv = prepareTempText();
|
||||||
foreach (row; 0 .. map.rowCount) {
|
foreach (row; 0 .. map.softRowCount) {
|
||||||
foreach (col; 0 .. map.colCount) {
|
foreach (col; 0 .. map.softColCount) {
|
||||||
csv.append(map[row, col].toStr());
|
csv.append(map[row, col].toStr());
|
||||||
if (col != map.colCount - 1) csv.append(',');
|
if (col != map.softColCount - 1) csv.append(',');
|
||||||
}
|
}
|
||||||
csv.append('\n');
|
csv.append('\n');
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
// TODO: Update all the doc comments here.
|
// TODO: Update all the doc comments here.
|
||||||
// TODO: Add spatial partitioning after testing this in a game.
|
|
||||||
// TODO: Add one-way collision support for moving walls.
|
// TODO: Add one-way collision support for moving walls.
|
||||||
// NOTE: Maybe a world pixel size value could be useful.
|
// TODO: Add spatial partitioning.
|
||||||
|
// NOTE: Was working on spatial partitioning. The grid is done, just need to add values in it.
|
||||||
|
|
||||||
/// The `platformer` module provides a pixel-perfect physics engine.
|
/// The `platformer` module provides a pixel-perfect physics engine.
|
||||||
module parin.platformer;
|
module parin.platformer;
|
||||||
|
@ -22,10 +22,17 @@ import joka.types;
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
alias BaseBoxId = int;
|
alias BaseBoxId = int;
|
||||||
|
alias BaseBoxIdGroup = FixedList!(BaseBoxId, 510);
|
||||||
|
|
||||||
alias ActorBoxId = BaseBoxId;
|
alias ActorBoxId = BaseBoxId;
|
||||||
|
alias ActorBoxFlags = ubyte;
|
||||||
alias WallBoxId = BaseBoxId;
|
alias WallBoxId = BaseBoxId;
|
||||||
|
alias WallBoxFlags = ubyte;
|
||||||
alias OneWaySide = RideSide;
|
alias OneWaySide = RideSide;
|
||||||
|
|
||||||
|
enum boxPassableFlag = 0x1;
|
||||||
|
enum boxRidingFlag = 0x2;
|
||||||
|
|
||||||
enum RideSide : ubyte {
|
enum RideSide : ubyte {
|
||||||
none,
|
none,
|
||||||
top,
|
top,
|
||||||
|
@ -111,86 +118,59 @@ struct BoxMover {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Box {
|
|
||||||
IVec2 position;
|
|
||||||
IVec2 size;
|
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
|
||||||
|
|
||||||
pragma(inline, true)
|
|
||||||
this(IVec2 position, IVec2 size) {
|
|
||||||
this.position = position;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline, true)
|
|
||||||
this(int x, int y, int w, int h) {
|
|
||||||
this(IVec2(x, y), IVec2(w, h));
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline, true)
|
|
||||||
this(IVec2 position, int w, int h) {
|
|
||||||
this(position, IVec2(w, h));
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline, true)
|
|
||||||
this(int x, int y, IVec2 size) {
|
|
||||||
this(IVec2(x, y), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma(inline, true)
|
|
||||||
Rect toRect() {
|
|
||||||
return Rect(position.toVec(), size.toVec());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasPoint(IVec2 point) {
|
|
||||||
return (
|
|
||||||
point.x > position.x &&
|
|
||||||
point.x < position.x + size.x &&
|
|
||||||
point.y > position.y &&
|
|
||||||
point.y < position.y + size.y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasIntersection(Box area) {
|
|
||||||
return (
|
|
||||||
position.x + size.x > area.position.x &&
|
|
||||||
position.x < area.position.x + area.size.x &&
|
|
||||||
position.y + size.y > area.position.y &&
|
|
||||||
position.y < area.position.y + area.size.y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a string representation with a limited lifetime.
|
|
||||||
IStr toStr() {
|
|
||||||
return "({}, {}, {}, {})".format(position.x, position.y, size.x, size.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WallBoxProperties {
|
struct WallBoxProperties {
|
||||||
Vec2 remainder;
|
Vec2 remainder;
|
||||||
OneWaySide oneWaySide;
|
OneWaySide oneWaySide;
|
||||||
bool isPassable;
|
WallBoxFlags flags;
|
||||||
|
byte gridX;
|
||||||
|
byte gridY;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ActorBoxProperties {
|
struct ActorBoxProperties {
|
||||||
Vec2 remainder;
|
Vec2 remainder;
|
||||||
RideSide rideSide;
|
RideSide rideSide;
|
||||||
bool isRiding;
|
ActorBoxFlags flags;
|
||||||
bool isPassable;
|
byte gridX;
|
||||||
|
byte gridY;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BoxWorld {
|
struct BoxWorld {
|
||||||
List!Box walls;
|
List!IRect walls;
|
||||||
List!Box actors;
|
List!IRect actors;
|
||||||
List!WallBoxProperties wallsProperties;
|
List!WallBoxProperties wallsProperties;
|
||||||
List!ActorBoxProperties actorsProperties;
|
List!ActorBoxProperties actorsProperties;
|
||||||
List!ActorBoxId squishedIdsBuffer;
|
List!ActorBoxId squishedIdsBuffer;
|
||||||
List!BaseBoxId collisionIdsBuffer;
|
List!BaseBoxId collisionIdsBuffer;
|
||||||
|
Grid!BaseBoxIdGroup grid;
|
||||||
|
int gridTileWidth;
|
||||||
|
int gridTileHeight;
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
ref Box getWall(WallBoxId id) {
|
void enableSpatialGrid(Sz rowCount, Sz colCount, int tileWidth, int tileHeight) {
|
||||||
|
gridTileWidth = tileWidth;
|
||||||
|
gridTileHeight = tileHeight;
|
||||||
|
foreach (i, ref properties; wallsProperties) {
|
||||||
|
properties.gridX = walls[i].position.x / gridTileWidth - (walls[i].position.x < 0);
|
||||||
|
properties.gridY = walls[i].position.y / gridTileHeight - (walls[i].position.y < 0);
|
||||||
|
}
|
||||||
|
foreach (i, ref properties; actorsProperties) {
|
||||||
|
properties.gridX = actors[i].position.x / gridTileWidth - (actors[i].position.x < 0);
|
||||||
|
properties.gridY = actors[i].position.y / gridTileHeight - (actors[i].position.y < 0);
|
||||||
|
}
|
||||||
|
grid.resizeBlank(rowCount, colCount);
|
||||||
|
foreach (ref group; grid) {
|
||||||
|
group.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void disableSpatialGrid() {
|
||||||
|
gridTileWidth = 0;
|
||||||
|
gridTileHeight = 0;
|
||||||
|
grid.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ref IRect getWall(WallBoxId id) {
|
||||||
if (id <= 0) {
|
if (id <= 0) {
|
||||||
assert(0, "ID `0` is always invalid and represents a box that was never created.");
|
assert(0, "ID `0` is always invalid and represents a box that was never created.");
|
||||||
} else if (id > walls.length) {
|
} else if (id > walls.length) {
|
||||||
|
@ -199,7 +179,7 @@ struct BoxWorld {
|
||||||
return walls[id - 1];
|
return walls[id - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
ref Box getActor(ActorBoxId id) {
|
ref IRect getActor(ActorBoxId id) {
|
||||||
if (id <= 0) {
|
if (id <= 0) {
|
||||||
assert(0, "ID `0` is always invalid and represents a box that was never created.");
|
assert(0, "ID `0` is always invalid and represents a box that was never created.");
|
||||||
} else if (id > actors.length) {
|
} else if (id > actors.length) {
|
||||||
|
@ -226,46 +206,54 @@ struct BoxWorld {
|
||||||
return actorsProperties[id - 1];
|
return actorsProperties[id - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
WallBoxId appendWall(Box box, OneWaySide oneWaySide = OneWaySide.none) {
|
WallBoxId appendWall(IRect box, OneWaySide oneWaySide = OneWaySide.none) {
|
||||||
walls.append(box);
|
walls.append(box);
|
||||||
wallsProperties.append(WallBoxProperties());
|
wallsProperties.append(WallBoxProperties());
|
||||||
wallsProperties[$ - 1].oneWaySide = oneWaySide;
|
wallsProperties[$ - 1].oneWaySide = oneWaySide;
|
||||||
|
if (gridTileWidth != 0 || gridTileHeight != 0) {
|
||||||
|
wallsProperties[$ - 1].gridX = box.position.x / gridTileWidth - (box.position.x < 0);
|
||||||
|
wallsProperties[$ - 1].gridY = box.position.y / gridTileHeight - (box.position.y < 0);
|
||||||
|
}
|
||||||
return cast(BaseBoxId) walls.length;
|
return cast(BaseBoxId) walls.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorBoxId appendActor(Box box, RideSide rideSide = RideSide.none) {
|
ActorBoxId appendActor(IRect box, RideSide rideSide = RideSide.none) {
|
||||||
actors.append(box);
|
actors.append(box);
|
||||||
actorsProperties.append(ActorBoxProperties());
|
actorsProperties.append(ActorBoxProperties());
|
||||||
actorsProperties[$ - 1].rideSide = rideSide;
|
actorsProperties[$ - 1].rideSide = rideSide;
|
||||||
|
if (gridTileWidth != 0 || gridTileHeight != 0) {
|
||||||
|
actorsProperties[$ - 1].gridX = box.position.x / gridTileWidth - (box.position.x < 0);
|
||||||
|
actorsProperties[$ - 1].gridY = box.position.y / gridTileHeight - (box.position.y < 0);
|
||||||
|
}
|
||||||
return cast(BaseBoxId) actors.length;
|
return cast(BaseBoxId) actors.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
WallBoxId hasWallCollision(Box box) {
|
WallBoxId hasWallCollision(IRect box) {
|
||||||
foreach (i, wall; walls) {
|
foreach (i, wall; walls) {
|
||||||
if (wall.hasIntersection(box) && !wallsProperties[i].isPassable) return cast(BaseBoxId) (i + 1);
|
if (wall.hasIntersection(box) && ~wallsProperties[i].flags & boxPassableFlag) return cast(BaseBoxId) (i + 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorBoxId hasActorCollision(Box box) {
|
ActorBoxId hasActorCollision(IRect box) {
|
||||||
foreach (i, actor; actors) {
|
foreach (i, actor; actors) {
|
||||||
if (actor.hasIntersection(box) && !actorsProperties[i].isPassable) return cast(BaseBoxId) (i + 1);
|
if (actor.hasIntersection(box) && ~actorsProperties[i].flags & boxPassableFlag) return cast(BaseBoxId) (i + 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
WallBoxId[] getWallCollisions(Box box) {
|
WallBoxId[] getWallCollisions(IRect box) {
|
||||||
collisionIdsBuffer.clear();
|
collisionIdsBuffer.clear();
|
||||||
foreach (i, wall; walls) {
|
foreach (i, wall; walls) {
|
||||||
if (wall.hasIntersection(box) && !wallsProperties[i].isPassable) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
if (wall.hasIntersection(box) && ~wallsProperties[i].flags & boxPassableFlag) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
||||||
}
|
}
|
||||||
return collisionIdsBuffer[];
|
return collisionIdsBuffer[];
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorBoxId[] getActorCollisions(Box box) {
|
ActorBoxId[] getActorCollisions(IRect box) {
|
||||||
collisionIdsBuffer.clear();
|
collisionIdsBuffer.clear();
|
||||||
foreach (i, actor; actors) {
|
foreach (i, actor; actors) {
|
||||||
if (actor.hasIntersection(box) && !actorsProperties[i].isPassable) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
if (actor.hasIntersection(box) && ~actorsProperties[i].flags & boxPassableFlag) collisionIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
||||||
}
|
}
|
||||||
return collisionIdsBuffer[];
|
return collisionIdsBuffer[];
|
||||||
}
|
}
|
||||||
|
@ -281,7 +269,7 @@ struct BoxWorld {
|
||||||
int moveSign = move.sign();
|
int moveSign = move.sign();
|
||||||
properties.remainder.x -= move;
|
properties.remainder.x -= move;
|
||||||
while (move != 0) {
|
while (move != 0) {
|
||||||
auto tempBox = Box(actor.position + IVec2(moveSign, 0), actor.size);
|
auto tempBox = IRect(actor.position + IVec2(moveSign, 0), actor.size);
|
||||||
auto wallId = hasWallCollision(tempBox);
|
auto wallId = hasWallCollision(tempBox);
|
||||||
if (wallId) {
|
if (wallId) {
|
||||||
// One way stuff.
|
// One way stuff.
|
||||||
|
@ -302,11 +290,12 @@ struct BoxWorld {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!properties.isPassable && wallId) {
|
if (~properties.flags & boxPassableFlag && wallId) {
|
||||||
return wallId;
|
return wallId;
|
||||||
} else {
|
} else {
|
||||||
actor.position.x += moveSign;
|
actor.position.x += moveSign;
|
||||||
move -= moveSign;
|
move -= moveSign;
|
||||||
|
properties.gridX = actor.position.x / gridTileWidth - (actor.position.x < 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -335,7 +324,7 @@ struct BoxWorld {
|
||||||
int moveSign = move.sign();
|
int moveSign = move.sign();
|
||||||
properties.remainder.y -= move;
|
properties.remainder.y -= move;
|
||||||
while (move != 0) {
|
while (move != 0) {
|
||||||
auto tempBox = Box(actor.position + IVec2(0, moveSign), actor.size);
|
auto tempBox = IRect(actor.position + IVec2(0, moveSign), actor.size);
|
||||||
auto wallId = hasWallCollision(tempBox);
|
auto wallId = hasWallCollision(tempBox);
|
||||||
if (wallId) {
|
if (wallId) {
|
||||||
// One way stuff.
|
// One way stuff.
|
||||||
|
@ -356,11 +345,12 @@ struct BoxWorld {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!properties.isPassable && wallId) {
|
if (~properties.flags & boxPassableFlag && wallId) {
|
||||||
return wallId;
|
return wallId;
|
||||||
} else {
|
} else {
|
||||||
actor.position.y += moveSign;
|
actor.position.y += moveSign;
|
||||||
move -= moveSign;
|
move -= moveSign;
|
||||||
|
properties.gridY = actor.position.y / gridTileHeight - (actor.position.y < 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -443,8 +433,8 @@ struct BoxWorld {
|
||||||
auto move = properties.remainder.round().toIVec();
|
auto move = properties.remainder.round().toIVec();
|
||||||
if (move.x != 0 || move.y != 0) {
|
if (move.x != 0 || move.y != 0) {
|
||||||
foreach (i, ref actorProperties; actorsProperties) {
|
foreach (i, ref actorProperties; actorsProperties) {
|
||||||
actorProperties.isRiding = false;
|
actorProperties.flags &= ~boxRidingFlag;
|
||||||
if (!actorProperties.rideSide || actorProperties.isPassable) continue;
|
if (!actorProperties.rideSide || actorProperties.flags & boxPassableFlag) continue;
|
||||||
auto rideBox = actors[i];
|
auto rideBox = actors[i];
|
||||||
final switch (actorProperties.rideSide) with (RideSide) {
|
final switch (actorProperties.rideSide) with (RideSide) {
|
||||||
case none: break;
|
case none: break;
|
||||||
|
@ -453,16 +443,17 @@ struct BoxWorld {
|
||||||
case right: rideBox.position.x -= 1; break;
|
case right: rideBox.position.x -= 1; break;
|
||||||
case bottom: rideBox.position.y -= 1; break;
|
case bottom: rideBox.position.y -= 1; break;
|
||||||
}
|
}
|
||||||
actorProperties.isRiding = wall.hasIntersection(rideBox);
|
actorProperties.flags |= wall.hasIntersection(rideBox) ? boxRidingFlag : 0x0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (move.x != 0) {
|
if (move.x != 0) {
|
||||||
wall.position.x += move.x;
|
wall.position.x += move.x;
|
||||||
properties.remainder.x -= move.x;
|
properties.remainder.x -= move.x;
|
||||||
if (!properties.isPassable) {
|
properties.gridX = wall.position.x / gridTileWidth - (wall.position.x < 0);
|
||||||
properties.isPassable = true;
|
if (~properties.flags & boxPassableFlag) {
|
||||||
|
properties.flags |= boxPassableFlag;
|
||||||
foreach (i, ref actor; actors) {
|
foreach (i, ref actor; actors) {
|
||||||
if (actorsProperties[i].isPassable) continue;
|
if (actorsProperties[i].flags & boxPassableFlag) continue;
|
||||||
if (wall.hasIntersection(actor)) {
|
if (wall.hasIntersection(actor)) {
|
||||||
// Push actor.
|
// Push actor.
|
||||||
auto wallLeft = wall.position.x;
|
auto wallLeft = wall.position.x;
|
||||||
|
@ -474,21 +465,22 @@ struct BoxWorld {
|
||||||
// Squish actor.
|
// Squish actor.
|
||||||
squishedIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
squishedIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
||||||
}
|
}
|
||||||
} else if (actorsProperties[i].isRiding) {
|
} else if (actorsProperties[i].flags & boxRidingFlag) {
|
||||||
// Carry actor.
|
// Carry actor.
|
||||||
moveActorX(cast(BaseBoxId) (i + 1), move.x);
|
moveActorX(cast(BaseBoxId) (i + 1), move.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.isPassable = false;
|
properties.flags &= ~boxPassableFlag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (move.y != 0) {
|
if (move.y != 0) {
|
||||||
wall.position.y += move.y;
|
wall.position.y += move.y;
|
||||||
properties.remainder.y -= move.y;
|
properties.remainder.y -= move.y;
|
||||||
if (!properties.isPassable) {
|
properties.gridY = wall.position.y / gridTileHeight - (wall.position.y < 0);
|
||||||
properties.isPassable = true;
|
if (~properties.flags & boxPassableFlag) {
|
||||||
|
properties.flags |= boxPassableFlag;
|
||||||
foreach (i, ref actor; actors) {
|
foreach (i, ref actor; actors) {
|
||||||
if (actorsProperties[i].isPassable) continue;
|
if (actorsProperties[i].flags & boxPassableFlag) continue;
|
||||||
if (wall.hasIntersection(actor)) {
|
if (wall.hasIntersection(actor)) {
|
||||||
// Push actor.
|
// Push actor.
|
||||||
auto wallTop = wall.position.y;
|
auto wallTop = wall.position.y;
|
||||||
|
@ -500,12 +492,12 @@ struct BoxWorld {
|
||||||
// Squish actor.
|
// Squish actor.
|
||||||
squishedIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
squishedIdsBuffer.append(cast(BaseBoxId) (i + 1));
|
||||||
}
|
}
|
||||||
} else if (actorsProperties[i].isRiding) {
|
} else if (actorsProperties[i].flags & boxRidingFlag) {
|
||||||
// Carry actor.
|
// Carry actor.
|
||||||
moveActorY(cast(BaseBoxId) (i + 1), move.y);
|
moveActorY(cast(BaseBoxId) (i + 1), move.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.isPassable = false;
|
properties.flags &= ~boxPassableFlag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return squishedIdsBuffer[];
|
return squishedIdsBuffer[];
|
||||||
|
|
|
@ -15,7 +15,6 @@ import joka.ascii;
|
||||||
import joka.containers;
|
import joka.containers;
|
||||||
import joka.io;
|
import joka.io;
|
||||||
import joka.types;
|
import joka.types;
|
||||||
import joka.unions;
|
|
||||||
|
|
||||||
@safe @nogc nothrow:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue