mirror of
https://github.com/Kapendev/parin.git
synced 2025-04-25 20:49:57 +03:00
Everything is back to normal now.
This commit is contained in:
parent
2b6dc55a95
commit
7f2b072482
14 changed files with 187 additions and 89 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -2,13 +2,13 @@
|
||||||
docs.json
|
docs.json
|
||||||
__dummy.html
|
__dummy.html
|
||||||
docs/
|
docs/
|
||||||
/popka
|
/parin
|
||||||
popka.so
|
parin.so
|
||||||
popka.dylib
|
parin.dylib
|
||||||
popka.dll
|
parin.dll
|
||||||
popka.a
|
parin.a
|
||||||
popka.lib
|
parin.lib
|
||||||
popka-test-*
|
parin-test-*
|
||||||
*.exe
|
*.exe
|
||||||
*.pdb
|
*.pdb
|
||||||
*.o
|
*.o
|
||||||
|
|
2
TOUR.md
2
TOUR.md
|
@ -115,7 +115,7 @@ void updateSound(SoundId sound);
|
||||||
## Drawing
|
## Drawing
|
||||||
|
|
||||||
Parin provides a set of drawing functions inside the `parin.engine` module.
|
Parin provides a set of drawing functions inside the `parin.engine` module.
|
||||||
While drawing is not pixel-perfect by default, it can be by calling the `setIsPixelPerfect` function.
|
While drawing is not pixel-perfect by default, it can be by calling the `setIsPixelPerfect` or `setIsPixelSnapped` function.
|
||||||
|
|
||||||
```d
|
```d
|
||||||
void drawRect(Rect area, Color color = white);
|
void drawRect(Rect area, Color color = white);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import parin;
|
||||||
// The game variables.
|
// The game variables.
|
||||||
auto player = Rect(16, 16);
|
auto player = Rect(16, 16);
|
||||||
auto playerSpeed = 120;
|
auto playerSpeed = 120;
|
||||||
|
|
||||||
auto coins = SparseList!Rect();
|
auto coins = SparseList!Rect();
|
||||||
auto coinSize = Vec2(8);
|
auto coinSize = Vec2(8);
|
||||||
auto maxCoinCount = 8;
|
auto maxCoinCount = 8;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/// This example shows how to use the Parin dialogue system.
|
/// This example shows how to use the Parin dialogue system.
|
||||||
import parin;
|
import parin;
|
||||||
|
import parin.dialogue;
|
||||||
|
|
||||||
// The game variables.
|
// The game variables.
|
||||||
auto dialogue = Dialogue();
|
auto dialogue = Dialogue();
|
||||||
|
|
|
@ -19,38 +19,36 @@ void ready() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(float dt) {
|
bool update(float dt) {
|
||||||
// Make some options.
|
// Make the drawing options.
|
||||||
auto mapOptions = DrawOptions(Hook.center);
|
auto mapOptions = DrawOptions(Hook.center);
|
||||||
mapOptions.scale = Vec2(2);
|
mapOptions.scale = Vec2(2);
|
||||||
auto tileOptions = mapOptions;
|
auto tileOptions = mapOptions;
|
||||||
tileOptions.flip = tileLookDirection > 0 ? Flip.x : Flip.none;
|
tileOptions.flip = tileLookDirection > 0 ? Flip.x : Flip.none;
|
||||||
|
|
||||||
// Move tile and camera.
|
// Move the tile and camera.
|
||||||
tile.position += wasd * Vec2(tileSpeed * dt);
|
tile.position += wasd * Vec2(tileSpeed * dt);
|
||||||
camera.followPosition(tile.position, tileSpeed);
|
camera.position = tile.position;
|
||||||
if (wasd.x != 0) tileLookDirection = cast(int) wasd.normalize.round.x;
|
if (wasd.x != 0) tileLookDirection = cast(int) wasd.normalize.round.x;
|
||||||
|
|
||||||
// Check for collisions.
|
// Check for collisions.
|
||||||
auto colRow1 = map.firstMapPosition(camera.area.topLeftPoint, mapOptions);
|
auto collisionArea = Rect();
|
||||||
auto colRow2 = map.lastMapPosition(camera.area.bottomRightPoint, mapOptions);
|
foreach (gridPosition; map.gridPositions(camera.topLeftPoint, camera.bottomRightPoint, mapOptions)) {
|
||||||
foreach (row; colRow1.y .. colRow2.y) {
|
if (map[gridPosition] == -1) continue;
|
||||||
foreach (col; colRow1.x .. colRow2.x) {
|
auto gridTileArea = Rect(map.worldPosition(gridPosition, mapOptions), Vec2(16) * mapOptions.scale);
|
||||||
if (map[row, col] == -1) continue;
|
while (gridTileArea.hasIntersection(Rect(tile.position, tile.size * mapOptions.scale).area(tileOptions.hook))) {
|
||||||
// TODO: Yeah, maybe change it to something better...
|
tile.position -= wasd * Vec2(dt);
|
||||||
auto mapTileRect = Rect(map.worldPosition(row, col, mapOptions), Vec2(16) * mapOptions.scale);
|
camera.position = tile.position;
|
||||||
auto myTileRect = Rect(tile.position, tile.size * mapOptions.scale).area(Hook.center);
|
collisionArea = gridTileArea;
|
||||||
if (mapTileRect.hasIntersection(myTileRect)) {
|
|
||||||
tile.position -= wasd * Vec2(tileSpeed * dt);
|
|
||||||
camera.followPosition(tile.position, tileSpeed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw game.
|
// Draw the game.
|
||||||
camera.attach();
|
camera.attach();
|
||||||
drawTileMap(atlas, map, camera, mapOptions);
|
drawTileMap(atlas, map, camera, mapOptions);
|
||||||
drawTile(atlas, tile, tileOptions);
|
drawTile(atlas, tile, tileOptions);
|
||||||
|
drawRect(collisionArea, yellow.alpha(120));
|
||||||
camera.detach();
|
camera.detach();
|
||||||
|
drawDebugText("Move with arrow keys.", Vec2(8));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,6 @@ bool update(float dt) {
|
||||||
drawRect(ball.centerArea);
|
drawRect(ball.centerArea);
|
||||||
drawRect(paddle1.centerArea);
|
drawRect(paddle1.centerArea);
|
||||||
drawRect(paddle2.centerArea);
|
drawRect(paddle2.centerArea);
|
||||||
|
|
||||||
// Draw the counter.
|
// Draw the counter.
|
||||||
auto textOptions = DrawOptions(Hook.center);
|
auto textOptions = DrawOptions(Hook.center);
|
||||||
textOptions.scale = Vec2(2);
|
textOptions.scale = Vec2(2);
|
||||||
|
|
|
@ -51,7 +51,7 @@ struct Scene2 {
|
||||||
sceneManager.enter!Scene1();
|
sceneManager.enter!Scene1();
|
||||||
}
|
}
|
||||||
|
|
||||||
drawDebugText("Press enter to change scene.", resolution * Vec2(0.5), DrawOptions(Hook.center));
|
drawDebugText("Press space to change scene.", resolution * Vec2(0.5), DrawOptions(Hook.center));
|
||||||
drawDebugText("Scene 2\nNo counter here.", Vec2(8));
|
drawDebugText("Scene 2\nNo counter here.", Vec2(8));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct DialogueUnit {
|
||||||
LStr text;
|
LStr text;
|
||||||
DialogueUnitKind kind;
|
DialogueUnitKind kind;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
text.free();
|
text.free();
|
||||||
|
@ -52,7 +52,7 @@ struct DialogueValue {
|
||||||
LStr name;
|
LStr name;
|
||||||
long value;
|
long value;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
name.free();
|
name.free();
|
||||||
|
@ -60,7 +60,7 @@ struct DialogueValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alias DialogueCommandRunner = void function(IStr[] args);
|
alias DialogueCommandRunner = void function(IStr[] args) @trusted;
|
||||||
|
|
||||||
struct Dialogue {
|
struct Dialogue {
|
||||||
List!DialogueUnit units;
|
List!DialogueUnit units;
|
||||||
|
@ -69,7 +69,13 @@ struct Dialogue {
|
||||||
IStr actor;
|
IStr actor;
|
||||||
Sz unitIndex;
|
Sz unitIndex;
|
||||||
|
|
||||||
@safe:
|
@trusted
|
||||||
|
void run(DialogueCommandRunner runner) {
|
||||||
|
runner(args);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
return units.length == 0;
|
return units.length == 0;
|
||||||
|
@ -169,11 +175,6 @@ struct Dialogue {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(DialogueCommandRunner runner) {
|
|
||||||
runner(args);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove the asserts!
|
// TODO: Remove the asserts!
|
||||||
void update() {
|
void update() {
|
||||||
if (units.length != 0 && unitIndex < units.length - 1) {
|
if (units.length != 0 && unitIndex < units.length - 1) {
|
||||||
|
@ -331,6 +332,8 @@ struct Dialogue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
bool isValidDialogueUnitKind(char c) {
|
bool isValidDialogueUnitKind(char c) {
|
||||||
foreach (kind; DialogueUnitKindChars) {
|
foreach (kind; DialogueUnitKindChars) {
|
||||||
if (c == kind) {
|
if (c == kind) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ public import joka.faults;
|
||||||
public import joka.math;
|
public import joka.math;
|
||||||
public import joka.types;
|
public import joka.types;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
EngineState engineState;
|
EngineState engineState;
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ struct DrawOptions {
|
||||||
Hook hook = Hook.topLeft; /// An value representing the origin point of the drawn object when origin is set to zero.
|
Hook hook = Hook.topLeft; /// An value representing the origin point of the drawn object when origin is set to zero.
|
||||||
Flip flip = Flip.none; /// An value representing flipping orientations.
|
Flip flip = Flip.none; /// An value representing flipping orientations.
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Initializes the options with the given scale.
|
/// Initializes the options with the given scale.
|
||||||
this(Vec2 scale) {
|
this(Vec2 scale) {
|
||||||
|
@ -196,7 +196,7 @@ struct Camera {
|
||||||
bool isAttached; /// Indicates whether the camera is currently in use.
|
bool isAttached; /// Indicates whether the camera is currently in use.
|
||||||
bool isCentered; /// Determines if the camera's origin is at the center instead of the top left.
|
bool isCentered; /// Determines if the camera's origin is at the center instead of the top left.
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Initializes the camera with the given position and optional centering.
|
/// Initializes the camera with the given position and optional centering.
|
||||||
this(float x, float y, bool isCentered = false) {
|
this(float x, float y, bool isCentered = false) {
|
||||||
|
@ -210,11 +210,61 @@ struct Camera {
|
||||||
return isCentered ? Hook.center : Hook.topLeft;
|
return isCentered ? Hook.center : Hook.topLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the origin of the camera.
|
||||||
|
Vec2 origin() {
|
||||||
|
return Rect(position, resolution).origin(hook);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the area covered by the camera.
|
/// Returns the area covered by the camera.
|
||||||
Rect area() {
|
Rect area() {
|
||||||
return Rect(position, resolution).area(hook);
|
return Rect(position, resolution).area(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the top left point of the camera.
|
||||||
|
Vec2 topLeftPoint() {
|
||||||
|
return area.topLeftPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the top point of the camera.
|
||||||
|
Vec2 topPoint() {
|
||||||
|
return area.topPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the top right point of the camera.
|
||||||
|
Vec2 topRightPoint() {
|
||||||
|
return area.topRightPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the left point of the camera.
|
||||||
|
Vec2 leftPoint() {
|
||||||
|
return area.leftPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the center point of the camera.
|
||||||
|
Vec2 centerPoint() {
|
||||||
|
return area.centerPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the right point of the camera.
|
||||||
|
Vec2 rightPoint() {
|
||||||
|
return area.rightPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the bottom left point of the camera.
|
||||||
|
Vec2 bottomLeftPoint() {
|
||||||
|
return area.bottomLeftPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the bottom point of the camera.
|
||||||
|
Vec2 bottomPoint() {
|
||||||
|
return area.bottomPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the bottom right point of the camera.
|
||||||
|
Vec2 bottomRightPoint() {
|
||||||
|
return area.bottomRightPoint;
|
||||||
|
}
|
||||||
|
|
||||||
/// Moves the camera to follow the target position at the specified speed.
|
/// Moves the camera to follow the target position at the specified speed.
|
||||||
void followPosition(Vec2 target, float speed) {
|
void followPosition(Vec2 target, float speed) {
|
||||||
position = position.moveTo(target, Vec2(speed));
|
position = position.moveTo(target, Vec2(speed));
|
||||||
|
@ -243,7 +293,7 @@ struct Camera {
|
||||||
}
|
}
|
||||||
isAttached = true;
|
isAttached = true;
|
||||||
auto temp = this.toRl();
|
auto temp = this.toRl();
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
temp.target.x = floor(temp.target.x);
|
temp.target.x = floor(temp.target.x);
|
||||||
temp.target.y = floor(temp.target.y);
|
temp.target.y = floor(temp.target.y);
|
||||||
temp.offset.x = floor(temp.offset.x);
|
temp.offset.x = floor(temp.offset.x);
|
||||||
|
@ -267,7 +317,7 @@ struct TextId {
|
||||||
GenerationalIndex data;
|
GenerationalIndex data;
|
||||||
alias data this;
|
alias data this;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Returns the length of the text associated with the resource identifier.
|
/// Returns the length of the text associated with the resource identifier.
|
||||||
Sz length() {
|
Sz length() {
|
||||||
|
@ -304,7 +354,7 @@ struct TextId {
|
||||||
struct Texture {
|
struct Texture {
|
||||||
rl.Texture2D data;
|
rl.Texture2D data;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Checks if the texture is not loaded.
|
/// Checks if the texture is not loaded.
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
|
@ -349,7 +399,7 @@ struct TextureId {
|
||||||
GenerationalIndex data;
|
GenerationalIndex data;
|
||||||
alias data this;
|
alias data this;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Returns the width of the texture associated with the resource identifier.
|
/// Returns the width of the texture associated with the resource identifier.
|
||||||
int width() {
|
int width() {
|
||||||
|
@ -398,7 +448,7 @@ struct Font {
|
||||||
int runeSpacing; /// The spacing between individual characters.
|
int runeSpacing; /// The spacing between individual characters.
|
||||||
int lineSpacing; /// The spacing between lines of text.
|
int lineSpacing; /// The spacing between lines of text.
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Checks if the font is not loaded.
|
/// Checks if the font is not loaded.
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
|
@ -433,7 +483,7 @@ struct FontId {
|
||||||
GenerationalIndex data;
|
GenerationalIndex data;
|
||||||
alias data this;
|
alias data this;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Returns the spacing between individual characters of the font associated with the resource identifier.
|
/// Returns the spacing between individual characters of the font associated with the resource identifier.
|
||||||
int runeSpacing() {
|
int runeSpacing() {
|
||||||
|
@ -480,7 +530,7 @@ struct FontId {
|
||||||
struct Sound {
|
struct Sound {
|
||||||
Variant!(rl.Sound, rl.Music) data;
|
Variant!(rl.Sound, rl.Music) data;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Checks if the sound is not loaded.
|
/// Checks if the sound is not loaded.
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
|
@ -575,7 +625,7 @@ struct SoundId {
|
||||||
GenerationalIndex data;
|
GenerationalIndex data;
|
||||||
alias data this;
|
alias data this;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Returns the current playback time of the sound associated with the resource identifier.
|
/// Returns the current playback time of the sound associated with the resource identifier.
|
||||||
float time() {
|
float time() {
|
||||||
|
@ -621,7 +671,7 @@ struct SoundId {
|
||||||
struct Viewport {
|
struct Viewport {
|
||||||
rl.RenderTexture2D data;
|
rl.RenderTexture2D data;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
/// Checks if the viewport is not loaded.
|
/// Checks if the viewport is not loaded.
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
|
@ -663,6 +713,7 @@ struct Viewport {
|
||||||
|
|
||||||
struct EngineFlags {
|
struct EngineFlags {
|
||||||
bool isUpdating;
|
bool isUpdating;
|
||||||
|
bool isPixelSnapped;
|
||||||
bool isPixelPerfect;
|
bool isPixelPerfect;
|
||||||
bool isCursorVisible;
|
bool isCursorVisible;
|
||||||
}
|
}
|
||||||
|
@ -678,7 +729,7 @@ struct EngineResourceGroup(T) {
|
||||||
GenerationalList!LStr names;
|
GenerationalList!LStr names;
|
||||||
GenerationalList!Sz tags;
|
GenerationalList!Sz tags;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
Sz length() {
|
Sz length() {
|
||||||
return data.length;
|
return data.length;
|
||||||
|
@ -741,7 +792,7 @@ struct EngineResources {
|
||||||
EngineResourceGroup!Font fonts;
|
EngineResourceGroup!Font fonts;
|
||||||
EngineResourceGroup!Sound sounds;
|
EngineResourceGroup!Sound sounds;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
void free(Sz tag = 0) {
|
void free(Sz tag = 0) {
|
||||||
texts.free(tag);
|
texts.free(tag);
|
||||||
|
@ -757,7 +808,7 @@ struct EngineViewport {
|
||||||
int targetHeight;
|
int targetHeight;
|
||||||
alias data this;
|
alias data this;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
bool isLocking() {
|
bool isLocking() {
|
||||||
return (targetWidth != 0 && targetHeight != 0) && (data.width != targetWidth && data.height != targetHeight);
|
return (targetWidth != 0 && targetHeight != 0) && (data.width != targetWidth && data.height != targetHeight);
|
||||||
|
@ -792,7 +843,7 @@ struct EngineState {
|
||||||
Filter defaultFilter;
|
Filter defaultFilter;
|
||||||
Sz tickCount;
|
Sz tickCount;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
debug {
|
debug {
|
||||||
|
@ -1170,8 +1221,9 @@ void openWindow(int width, int height, IStr appPath, IStr title = "Parin") {
|
||||||
/// You should avoid calling this function manually.
|
/// You should avoid calling this function manually.
|
||||||
@trusted
|
@trusted
|
||||||
void updateWindow(bool function(float dt) updateFunc) {
|
void updateWindow(bool function(float dt) updateFunc) {
|
||||||
static bool function(float _dt) @trusted _updateFunc;
|
static bool function(float _dt) @trusted @nogc nothrow _updateFunc;
|
||||||
|
|
||||||
|
@trusted @nogc nothrow
|
||||||
static bool _updateWindow() {
|
static bool _updateWindow() {
|
||||||
// Begin drawing.
|
// Begin drawing.
|
||||||
if (isResolutionLocked) {
|
if (isResolutionLocked) {
|
||||||
|
@ -1193,10 +1245,9 @@ void updateWindow(bool function(float dt) updateFunc) {
|
||||||
auto ratio = maxSize / minSize;
|
auto ratio = maxSize / minSize;
|
||||||
auto minRatio = min(ratio.x, ratio.y);
|
auto minRatio = min(ratio.x, ratio.y);
|
||||||
if (isPixelPerfect) {
|
if (isPixelPerfect) {
|
||||||
// TODO: Make an equals function in Joka that can change the epsilon value.
|
|
||||||
auto roundMinRatio = round(minRatio);
|
auto roundMinRatio = round(minRatio);
|
||||||
auto floorMinRation = floor(minRatio);
|
auto floorMinRation = floor(minRatio);
|
||||||
minRatio = (abs(minRatio - roundMinRatio) < 0.015f) ? roundMinRatio : floorMinRation;
|
minRatio = minRatio.equals(roundMinRatio, 0.015f) ? roundMinRatio : floorMinRation;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto targetSize = minSize * Vec2(minRatio);
|
auto targetSize = minSize * Vec2(minRatio);
|
||||||
|
@ -1253,7 +1304,7 @@ void updateWindow(bool function(float dt) updateFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe bad idea, but makes life of no-attribute people easier.
|
// Maybe bad idea, but makes life of no-attribute people easier.
|
||||||
_updateFunc = cast(bool function(float _dt) @trusted) updateFunc;
|
_updateFunc = cast(bool function(float _dt) @trusted @nogc nothrow) updateFunc;
|
||||||
engineState.flags.isUpdating = true;
|
engineState.flags.isUpdating = true;
|
||||||
|
|
||||||
version(WebAssembly) {
|
version(WebAssembly) {
|
||||||
|
@ -1284,6 +1335,21 @@ void closeWindow() {
|
||||||
rl.CloseWindow();
|
rl.CloseWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the drawing is snapped to pixel coordinates.
|
||||||
|
bool isPixelSnapped() {
|
||||||
|
return engineState.flags.isPixelSnapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets whether drawing should be snapped to pixel coordinates.
|
||||||
|
void setIsPixelSnapped(bool value) {
|
||||||
|
engineState.flags.isPixelSnapped = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggles whether drawing is snapped to pixel coordinates on or off.
|
||||||
|
void toggleIsPixelSnapped() {
|
||||||
|
setIsPixelSnapped(!isPixelSnapped);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the drawing is done in a pixel perfect way.
|
/// Returns true if the drawing is done in a pixel perfect way.
|
||||||
bool isPixelPerfect() {
|
bool isPixelPerfect() {
|
||||||
return engineState.flags.isPixelPerfect;
|
return engineState.flags.isPixelPerfect;
|
||||||
|
@ -1490,10 +1556,9 @@ Vec2 mouseScreenPosition() {
|
||||||
auto window = windowSize;
|
auto window = windowSize;
|
||||||
auto minRatio = min(window.x / engineState.viewport.width, window.y / engineState.viewport.height);
|
auto minRatio = min(window.x / engineState.viewport.width, window.y / engineState.viewport.height);
|
||||||
if (isPixelPerfect) {
|
if (isPixelPerfect) {
|
||||||
// TODO: Make an equals function in Joka that can change the epsilon value.
|
|
||||||
auto roundMinRatio = round(minRatio);
|
auto roundMinRatio = round(minRatio);
|
||||||
auto floorMinRation = floor(minRatio);
|
auto floorMinRation = floor(minRatio);
|
||||||
minRatio = (abs(minRatio - roundMinRatio) < 0.015f) ? roundMinRatio : floorMinRation;
|
minRatio = minRatio.equals(roundMinRatio, 0.015f) ? roundMinRatio : floorMinRation;
|
||||||
}
|
}
|
||||||
auto targetSize = engineState.viewport.size * Vec2(minRatio);
|
auto targetSize = engineState.viewport.size * Vec2(minRatio);
|
||||||
// We use touch because it works on desktop, web and mobile.
|
// We use touch because it works on desktop, web and mobile.
|
||||||
|
@ -1781,7 +1846,7 @@ void updateSound(SoundId sound) {
|
||||||
/// Draws a rectangle with the specified area and color.
|
/// Draws a rectangle with the specified area and color.
|
||||||
@trusted
|
@trusted
|
||||||
void drawRect(Rect area, Color color = white) {
|
void drawRect(Rect area, Color color = white) {
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.DrawRectanglePro(area.floor().toRl(), rl.Vector2(0.0f, 0.0f), 0.0f, color.toRl());
|
rl.DrawRectanglePro(area.floor().toRl(), rl.Vector2(0.0f, 0.0f), 0.0f, color.toRl());
|
||||||
} else {
|
} else {
|
||||||
rl.DrawRectanglePro(area.toRl(), rl.Vector2(0.0f, 0.0f), 0.0f, color.toRl());
|
rl.DrawRectanglePro(area.toRl(), rl.Vector2(0.0f, 0.0f), 0.0f, color.toRl());
|
||||||
|
@ -1796,7 +1861,7 @@ void drawVec2(Vec2 point, float size, Color color = white) {
|
||||||
/// Draws a circle with the specified area and color.
|
/// Draws a circle with the specified area and color.
|
||||||
@trusted
|
@trusted
|
||||||
void drawCirc(Circ area, Color color = white) {
|
void drawCirc(Circ area, Color color = white) {
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.DrawCircleV(area.position.floor().toRl(), area.radius, color.toRl());
|
rl.DrawCircleV(area.position.floor().toRl(), area.radius, color.toRl());
|
||||||
} else {
|
} else {
|
||||||
rl.DrawCircleV(area.position.toRl(), area.radius, color.toRl());
|
rl.DrawCircleV(area.position.toRl(), area.radius, color.toRl());
|
||||||
|
@ -1806,7 +1871,7 @@ void drawCirc(Circ area, Color color = white) {
|
||||||
/// Draws a line with the specified area, thickness, and color.
|
/// Draws a line with the specified area, thickness, and color.
|
||||||
@trusted
|
@trusted
|
||||||
void drawLine(Line area, float size, Color color = white) {
|
void drawLine(Line area, float size, Color color = white) {
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.DrawLineEx(area.a.floor().toRl(), area.b.floor().toRl(), size, color.toRl());
|
rl.DrawLineEx(area.a.floor().toRl(), area.b.floor().toRl(), size, color.toRl());
|
||||||
} else {
|
} else {
|
||||||
rl.DrawLineEx(area.a.toRl(), area.b.toRl(), size, color.toRl());
|
rl.DrawLineEx(area.a.toRl(), area.b.toRl(), size, color.toRl());
|
||||||
|
@ -1839,7 +1904,7 @@ void drawTextureArea(Texture texture, Rect area, Vec2 position, DrawOptions opti
|
||||||
}
|
}
|
||||||
|
|
||||||
auto origin = options.origin == Vec2() ? target.origin(options.hook) : options.origin;
|
auto origin = options.origin == Vec2() ? target.origin(options.hook) : options.origin;
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.DrawTexturePro(
|
rl.DrawTexturePro(
|
||||||
texture.data,
|
texture.data,
|
||||||
area.floor().toRl(),
|
area.floor().toRl(),
|
||||||
|
@ -1885,14 +1950,14 @@ void drawRune(Font font, dchar rune, Vec2 position, DrawOptions options = DrawOp
|
||||||
auto rect = toParin(rl.GetGlyphAtlasRec(font.data, rune));
|
auto rect = toParin(rl.GetGlyphAtlasRec(font.data, rune));
|
||||||
auto origin = options.origin == Vec2() ? rect.origin(options.hook) : options.origin;
|
auto origin = options.origin == Vec2() ? rect.origin(options.hook) : options.origin;
|
||||||
rl.rlPushMatrix();
|
rl.rlPushMatrix();
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.rlTranslatef(position.x.floor(), position.y.floor(), 0.0f);
|
rl.rlTranslatef(position.x.floor(), position.y.floor(), 0.0f);
|
||||||
} else {
|
} else {
|
||||||
rl.rlTranslatef(position.x, position.y, 0.0f);
|
rl.rlTranslatef(position.x, position.y, 0.0f);
|
||||||
}
|
}
|
||||||
rl.rlRotatef(options.rotation, 0.0f, 0.0f, 1.0f);
|
rl.rlRotatef(options.rotation, 0.0f, 0.0f, 1.0f);
|
||||||
rl.rlScalef(options.scale.x, options.scale.y, 1.0f);
|
rl.rlScalef(options.scale.x, options.scale.y, 1.0f);
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.rlTranslatef(-origin.x.floor(), -origin.y.floor(), 0.0f);
|
rl.rlTranslatef(-origin.x.floor(), -origin.y.floor(), 0.0f);
|
||||||
} else {
|
} else {
|
||||||
rl.rlTranslatef(-origin.x, -origin.y, 0.0f);
|
rl.rlTranslatef(-origin.x, -origin.y, 0.0f);
|
||||||
|
@ -1916,14 +1981,14 @@ void drawText(Font font, IStr text, Vec2 position, DrawOptions options = DrawOpt
|
||||||
// TODO: Make it work with negative scale values.
|
// TODO: Make it work with negative scale values.
|
||||||
auto origin = Rect(measureTextSize(font, text)).origin(options.hook);
|
auto origin = Rect(measureTextSize(font, text)).origin(options.hook);
|
||||||
rl.rlPushMatrix();
|
rl.rlPushMatrix();
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.rlTranslatef(floor(position.x), floor(position.y), 0.0f);
|
rl.rlTranslatef(floor(position.x), floor(position.y), 0.0f);
|
||||||
} else {
|
} else {
|
||||||
rl.rlTranslatef(position.x, position.y, 0.0f);
|
rl.rlTranslatef(position.x, position.y, 0.0f);
|
||||||
}
|
}
|
||||||
rl.rlRotatef(options.rotation, 0.0f, 0.0f, 1.0f);
|
rl.rlRotatef(options.rotation, 0.0f, 0.0f, 1.0f);
|
||||||
rl.rlScalef(options.scale.x, options.scale.y, 1.0f);
|
rl.rlScalef(options.scale.x, options.scale.y, 1.0f);
|
||||||
if (isPixelPerfect) {
|
if (isPixelSnapped || isPixelPerfect) {
|
||||||
rl.rlTranslatef(floor(-origin.x), floor(-origin.y), 0.0f);
|
rl.rlTranslatef(floor(-origin.x), floor(-origin.y), 0.0f);
|
||||||
} else {
|
} else {
|
||||||
rl.rlTranslatef(-origin.x, -origin.y, 0.0f);
|
rl.rlTranslatef(-origin.x, -origin.y, 0.0f);
|
||||||
|
|
|
@ -10,7 +10,6 @@ module parin;
|
||||||
|
|
||||||
public import joka.ascii;
|
public import joka.ascii;
|
||||||
public import joka.io;
|
public import joka.io;
|
||||||
public import parin.dialogue;
|
|
||||||
public import parin.engine;
|
public import parin.engine;
|
||||||
public import parin.scene;
|
public import parin.scene;
|
||||||
public import parin.sprite;
|
public import parin.sprite;
|
||||||
|
|
|
@ -1258,7 +1258,6 @@ void OpenURL (const(char)* url); // Open URL with default system browser (if ava
|
||||||
|
|
||||||
// NOTE: Following functions implemented in module [utils]
|
// NOTE: Following functions implemented in module [utils]
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
void TraceLog (int logLevel, const(char)* text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
|
|
||||||
void SetTraceLogLevel (int logLevel); // Set the current threshold (minimum) log level
|
void SetTraceLogLevel (int logLevel); // Set the current threshold (minimum) log level
|
||||||
void* MemAlloc (uint size); // Internal memory allocator
|
void* MemAlloc (uint size); // Internal memory allocator
|
||||||
void* MemRealloc (void* ptr, uint size); // Internal memory reallocator
|
void* MemRealloc (void* ptr, uint size); // Internal memory reallocator
|
||||||
|
@ -1641,7 +1640,6 @@ const(char)* CodepointToUTF8 (int codepoint, int* utf8Size); // Encode one codep
|
||||||
int TextCopy (char* dst, const(char)* src); // Copy one string to another, returns bytes copied
|
int TextCopy (char* dst, const(char)* src); // Copy one string to another, returns bytes copied
|
||||||
bool TextIsEqual (const(char)* text1, const(char)* text2); // Check if two text string are equal
|
bool TextIsEqual (const(char)* text1, const(char)* text2); // Check if two text string are equal
|
||||||
uint TextLength (const(char)* text); // Get text length, checks for '\0' ending
|
uint TextLength (const(char)* text); // Get text length, checks for '\0' ending
|
||||||
const(char)* TextFormat (const(char)* text, ...); // Text formatting with variables (sprintf() style)
|
|
||||||
const(char)* TextSubtext (const(char)* text, int position, int length); // Get a piece of a text string
|
const(char)* TextSubtext (const(char)* text, int position, int length); // Get a piece of a text string
|
||||||
char* TextReplace (char* text, const(char)* replace, const(char)* by); // Replace text string (WARNING: memory must be freed!)
|
char* TextReplace (char* text, const(char)* replace, const(char)* by); // Replace text string (WARNING: memory must be freed!)
|
||||||
char* TextInsert (const(char)* text, const(char)* insert, int position); // Insert text in a position (WARNING: memory must be freed!)
|
char* TextInsert (const(char)* text, const(char)* insert, int position); // Insert text in a position (WARNING: memory must be freed!)
|
||||||
|
|
|
@ -14,7 +14,7 @@ module parin.sprite;
|
||||||
|
|
||||||
import parin.engine;
|
import parin.engine;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
struct SpriteAnimation {
|
struct SpriteAnimation {
|
||||||
ubyte frameRow;
|
ubyte frameRow;
|
||||||
|
@ -28,7 +28,7 @@ struct SpriteAnimationGroup2 {
|
||||||
ubyte frameSpeed = 6;
|
ubyte frameSpeed = 6;
|
||||||
enum angleStep = 180.0f;
|
enum angleStep = 180.0f;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
SpriteAnimation pick(float angle) {
|
SpriteAnimation pick(float angle) {
|
||||||
auto id = (cast(int) round(snap(angle, angleStep) / angleStep)) % frameRows.length;
|
auto id = (cast(int) round(snap(angle, angleStep) / angleStep)) % frameRows.length;
|
||||||
|
@ -42,7 +42,7 @@ struct SpriteAnimationGroup4 {
|
||||||
ubyte frameSpeed = 6;
|
ubyte frameSpeed = 6;
|
||||||
enum angleStep = 90.0f;
|
enum angleStep = 90.0f;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
SpriteAnimation pick(float angle) {
|
SpriteAnimation pick(float angle) {
|
||||||
// NOTE: This is a hack to make things look better in simple cases.
|
// NOTE: This is a hack to make things look better in simple cases.
|
||||||
|
@ -61,7 +61,7 @@ struct SpriteAnimationGroup8 {
|
||||||
ubyte frameSpeed = 6;
|
ubyte frameSpeed = 6;
|
||||||
enum angleStep = 45.0f;
|
enum angleStep = 45.0f;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
SpriteAnimation pick(float angle) {
|
SpriteAnimation pick(float angle) {
|
||||||
auto id = (cast(int) round(snap(angle, angleStep) / angleStep)) % frameRows.length;
|
auto id = (cast(int) round(snap(angle, angleStep) / angleStep)) % frameRows.length;
|
||||||
|
@ -75,7 +75,7 @@ struct SpriteAnimationGroup16 {
|
||||||
ubyte frameSpeed = 6;
|
ubyte frameSpeed = 6;
|
||||||
enum angleStep = 22.5f;
|
enum angleStep = 22.5f;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
SpriteAnimation pick(float angle) {
|
SpriteAnimation pick(float angle) {
|
||||||
auto id = (cast(int) round(snap(angle, angleStep) / angleStep)) % frameRows.length;
|
auto id = (cast(int) round(snap(angle, angleStep) / angleStep)) % frameRows.length;
|
||||||
|
@ -92,7 +92,7 @@ struct Sprite {
|
||||||
SpriteAnimation animation;
|
SpriteAnimation animation;
|
||||||
Vec2 position;
|
Vec2 position;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
this(int width, int height, ushort atlasLeft, ushort atlasTop, SpriteAnimation animation = SpriteAnimation()) {
|
this(int width, int height, ushort atlasLeft, ushort atlasTop, SpriteAnimation animation = SpriteAnimation()) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
|
|
@ -21,7 +21,7 @@ public import joka.faults;
|
||||||
public import joka.math;
|
public import joka.math;
|
||||||
public import joka.types;
|
public import joka.types;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
struct Tile {
|
struct Tile {
|
||||||
Sz id;
|
Sz id;
|
||||||
|
@ -29,7 +29,7 @@ struct Tile {
|
||||||
int height;
|
int height;
|
||||||
Vec2 position;
|
Vec2 position;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
Vec2 size() {
|
Vec2 size() {
|
||||||
return Vec2(width, height);
|
return Vec2(width, height);
|
||||||
|
@ -67,13 +67,13 @@ struct TileMap {
|
||||||
Vec2 position;
|
Vec2 position;
|
||||||
alias data this;
|
alias data this;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
this(short value, int tileWidth, int tileHeight) {
|
this(short value, int tileWidth, int tileHeight) {
|
||||||
this.tileWidth = tileWidth;
|
this.tileWidth = tileWidth;
|
||||||
this.tileHeight = tileHeight;
|
this.tileHeight = tileHeight;
|
||||||
this.estimatedMaxRowCount = data.maxRowCount;
|
this.estimatedMaxRowCount = maxRowCount;
|
||||||
this.estimatedMaxColCount = data.maxColCount;
|
this.estimatedMaxColCount = maxColCount;
|
||||||
this.data.fill(value);
|
this.data.fill(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ struct TileMap {
|
||||||
position = position.moveToWithSlowdown(target, Vec2(deltaTime), slowdown);
|
position = position.moveToWithSlowdown(target, Vec2(deltaTime), slowdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the top left world position of a tile.
|
/// Returns the top left world position of a grid position.
|
||||||
Vec2 worldPosition(Sz row, Sz col, DrawOptions options = DrawOptions()) {
|
Vec2 worldPosition(Sz row, Sz col, DrawOptions options = DrawOptions()) {
|
||||||
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);
|
||||||
|
@ -147,7 +147,12 @@ struct TileMap {
|
||||||
return temp.area(options.hook).position;
|
return temp.area(options.hook).position;
|
||||||
}
|
}
|
||||||
|
|
||||||
IVec2 firstMapPosition(Vec2 topLeftWorldPosition, DrawOptions options = DrawOptions()) {
|
/// Returns the top left world position of a grid position.
|
||||||
|
Vec2 worldPosition(IVec2 gridPosition, DrawOptions options = DrawOptions()) {
|
||||||
|
return worldPosition(gridPosition.y, gridPosition.x, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
IVec2 firstGridPosition(Vec2 topLeftWorldPosition, DrawOptions options = DrawOptions()) {
|
||||||
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);
|
||||||
|
@ -156,7 +161,7 @@ struct TileMap {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
IVec2 lastMapPosition(Vec2 bottomRightWorldPosition, DrawOptions options = DrawOptions()) {
|
IVec2 lastGridPosition(Vec2 bottomRightWorldPosition, DrawOptions options = DrawOptions()) {
|
||||||
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);
|
||||||
|
@ -165,6 +170,37 @@ struct TileMap {
|
||||||
result.x = cast(int) floor(clamp((bottomRightWorldPosition.x - position.x) / targetTileWidth + extraTileCount, 0, estimatedMaxColCount));
|
result.x = cast(int) floor(clamp((bottomRightWorldPosition.x - position.x) / targetTileWidth + extraTileCount, 0, estimatedMaxColCount));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto gridPositions(Vec2 topLeftWorldPosition, Vec2 bottomRightWorldPosition, DrawOptions options = DrawOptions()) {
|
||||||
|
static struct Range {
|
||||||
|
IVec2 first;
|
||||||
|
IVec2 last;
|
||||||
|
IVec2 position;
|
||||||
|
|
||||||
|
bool empty() {
|
||||||
|
return position == last;
|
||||||
|
}
|
||||||
|
|
||||||
|
IVec2 front() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront() {
|
||||||
|
position.x += 1;
|
||||||
|
if (position.x >= TileMap.maxColCount) {
|
||||||
|
position.x = first.x;
|
||||||
|
position.y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = Range(
|
||||||
|
firstGridPosition(topLeftWorldPosition, options),
|
||||||
|
lastGridPosition(bottomRightWorldPosition, options),
|
||||||
|
);
|
||||||
|
result.position = result.first;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result!TileMap toTileMap(IStr csv, int tileWidth, int tileHeight) {
|
Result!TileMap toTileMap(IStr csv, int tileWidth, int tileHeight) {
|
||||||
|
@ -185,6 +221,7 @@ Result!TileMap loadRawTileMap(IStr path, int tileWidth, int tileHeight) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawTile(Texture texture, Tile tile, DrawOptions options = DrawOptions()) {
|
void drawTile(Texture texture, Tile tile, DrawOptions options = DrawOptions()) {
|
||||||
|
if (texture.isEmpty) return;
|
||||||
drawTextureArea(texture, tile.textureArea(texture.width / tile.width), tile.position, options);
|
drawTextureArea(texture, tile.textureArea(texture.width / tile.width), tile.position, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,9 +232,8 @@ void drawTile(TextureId texture, Tile tile, DrawOptions options = DrawOptions())
|
||||||
void drawTileMap(Texture texture, TileMap map, Camera camera, DrawOptions options = DrawOptions()) {
|
void drawTileMap(Texture texture, TileMap map, Camera camera, DrawOptions options = DrawOptions()) {
|
||||||
auto targetTileWidth = cast(int) (map.tileWidth * options.scale.x);
|
auto targetTileWidth = cast(int) (map.tileWidth * options.scale.x);
|
||||||
auto targetTileHeight = cast(int) (map.tileHeight * options.scale.y);
|
auto targetTileHeight = cast(int) (map.tileHeight * options.scale.y);
|
||||||
auto cameraArea = camera.area;
|
auto colRow1 = map.firstGridPosition(camera.topLeftPoint, options);
|
||||||
auto colRow1 = map.firstMapPosition(cameraArea.topLeftPoint, options);
|
auto colRow2 = map.lastGridPosition(camera.bottomRightPoint, options);
|
||||||
auto colRow2 = map.lastMapPosition(cameraArea.bottomRightPoint, options);
|
|
||||||
if (colRow1.x == colRow2.x || colRow1.y == colRow2.y) return;
|
if (colRow1.x == colRow2.x || colRow1.y == colRow2.y) return;
|
||||||
|
|
||||||
foreach (row; colRow1.y .. colRow2.y) {
|
foreach (row; colRow1.y .. colRow2.y) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ module parin.timer;
|
||||||
|
|
||||||
import joka.math;
|
import joka.math;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
float time = 1.0f;
|
float time = 1.0f;
|
||||||
|
@ -22,7 +22,7 @@ struct Timer {
|
||||||
bool isPaused;
|
bool isPaused;
|
||||||
bool canRepeat;
|
bool canRepeat;
|
||||||
|
|
||||||
@safe:
|
@safe @nogc nothrow:
|
||||||
|
|
||||||
this(float duration, bool canRepeat = false) {
|
this(float duration, bool canRepeat = false) {
|
||||||
this.time = duration;
|
this.time = duration;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue