Initial commit
This commit is contained in:
commit
da7a4011f8
|
@ -0,0 +1 @@
|
|||
*.png filter=lfs diff=lfs merge=lfs -text
|
|
@ -0,0 +1,2 @@
|
|||
output/
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/../output/quadrants",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/../output",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}],
|
||||
"preLaunchTask": "Build"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build",
|
||||
"type": "shell",
|
||||
"command": "${workspaceFolder}/build.sh",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": "$gcc",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "silent",
|
||||
"focus": false,
|
||||
"panel": "shared",
|
||||
"showReuseMessage": true,
|
||||
"clear": false,
|
||||
"revealProblems": "onProblem"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
module_files=(
|
||||
"core/core.cpp"
|
||||
"main.cpp"
|
||||
)
|
||||
|
||||
object_files=""
|
||||
|
||||
# Module to object compilation stage.
|
||||
for i in "${module_files[@]}"
|
||||
do
|
||||
module_file=$(dirname "${i}")
|
||||
object_file="../output/${module_file//\//.}.o"
|
||||
echo "Compiling module: \"${i}\""
|
||||
c++ ../source/${i} -c -o ${object_file} -g -Wshadow
|
||||
object_files="$object_files $object_file"
|
||||
done
|
||||
|
||||
# Object to executable linkage stage.
|
||||
c++ -o ../output/quadrants ${object_files} -g -lraylib -lm
|
||||
rm ${object_files}
|
||||
cp -a ../assets/. ../output
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "./source"
|
||||
},
|
||||
{
|
||||
"path": "./assets"
|
||||
},
|
||||
{
|
||||
"path": "./output"
|
||||
},
|
||||
{
|
||||
"path": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"*.h": "c",
|
||||
"limits": "c"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#include <raylib.h>
|
||||
|
||||
#define HALF_PI (PI / 2)
|
||||
|
||||
#define TAU (PI * 2)
|
||||
|
||||
#define V2_ZERO (Vector2){0.0f, 0.0f}
|
||||
|
||||
#define LENGTH_OF(a) ((sizeof(a) / sizeof(*(a))) / (size_t)(!(sizeof(a) % sizeof(*(a)))))
|
||||
|
||||
#define MAX(a, b) ((a > b) ? a : b)
|
||||
|
||||
#define MIN(a, b) ((a < b) ? a : b)
|
||||
|
||||
#define CLAMP(value, min, max) MIN(max, MAX(min, value))
|
||||
|
||||
#define SIGN(value) ((0 < value) - (value < 0))
|
||||
|
||||
typedef long unsigned Seed;
|
||||
|
||||
struct XorShifter {
|
||||
Seed seed;
|
||||
};
|
||||
|
||||
template<typename T> T const wrap(T const value, T const min, T const max) {
|
||||
return ((value < min) ? max : (value > max) ? min : value);
|
||||
}
|
||||
|
||||
Vector2 operator +(Vector2, Vector2);
|
||||
|
||||
Vector2 operator +=(Vector2&, Vector2);
|
||||
|
||||
Vector2 operator -(Vector2, Vector2);
|
||||
|
||||
Vector2 operator -=(Vector2&, Vector2);
|
||||
|
||||
Vector2 operator *(Vector2, Vector2);
|
||||
|
||||
Vector2 operator *=(Vector2&, Vector2);
|
||||
|
||||
Vector2 operator *(Vector2, float const);
|
||||
|
||||
Vector2 operator /(Vector2, Vector2);
|
||||
|
||||
Vector2 operator /=(Vector2&, Vector2);
|
||||
|
||||
Vector2 operator /(Vector2, float const);
|
||||
|
||||
bool operator <(Vector2, Vector2);
|
||||
|
||||
bool operator >(Vector2, Vector2);
|
||||
|
||||
float Vector2Distance(Vector2, Vector2);
|
||||
|
||||
float const LengthDirectionX(float const, float const);
|
||||
|
||||
float const LengthDirectionY(float const, float const);
|
||||
|
||||
Vector2 const LengthDirection(Vector2 const, float const);
|
||||
|
||||
float const AngleToPoint(Vector2 const, Vector2 const);
|
||||
|
||||
float const WrapAngle(float const);
|
||||
|
||||
float const AngleDifference(float const, float const);
|
||||
|
||||
XorShifter CreateXorShifter(Seed const);
|
||||
|
||||
long const GetXorShifterValue(XorShifter* const, long const, long const);
|
|
@ -0,0 +1,2 @@
|
|||
#include "math.cpp"
|
||||
#include "random.cpp"
|
|
@ -0,0 +1,118 @@
|
|||
#include <math.h>
|
||||
#include <raylib.h>
|
||||
|
||||
Vector2 operator +(Vector2 vectorA, Vector2 vectorB) {
|
||||
return (Vector2){(vectorA.x + vectorB.x), (vectorA.y + vectorB.y)};
|
||||
}
|
||||
|
||||
Vector2 operator +=(Vector2& vectorA, Vector2 vectorB) {
|
||||
vectorA.x += vectorB.x;
|
||||
vectorA.y += vectorB.y;
|
||||
|
||||
return vectorA;
|
||||
}
|
||||
|
||||
Vector2 operator -(Vector2 vectorA, float const value) {
|
||||
return (Vector2){(vectorA.x - value), (vectorA.y - value)};
|
||||
}
|
||||
|
||||
Vector2 operator -(Vector2 vectorA, Vector2 vectorB) {
|
||||
return (Vector2){(vectorA.x - vectorB.x), (vectorA.y - vectorB.y)};
|
||||
}
|
||||
|
||||
Vector2 operator -=(Vector2& vectorA, Vector2 vectorB) {
|
||||
vectorA.x -= vectorB.x;
|
||||
vectorA.y -= vectorB.y;
|
||||
|
||||
return vectorA;
|
||||
}
|
||||
|
||||
Vector2 operator *(Vector2 vectorA, float const value) {
|
||||
return (Vector2){(vectorA.x * value), (vectorA.y * value)};
|
||||
}
|
||||
|
||||
Vector2 operator *(Vector2 vectorA, Vector2 vectorB) {
|
||||
return (Vector2){(vectorA.x * vectorB.x), (vectorA.y * vectorB.y)};
|
||||
}
|
||||
|
||||
Vector2 operator *=(Vector2& vectorA, Vector2 vectorB) {
|
||||
vectorA.x *= vectorB.x;
|
||||
vectorA.y *= vectorB.y;
|
||||
|
||||
return vectorA;
|
||||
}
|
||||
|
||||
Vector2 operator /(Vector2 vectorA, float const value) {
|
||||
return (Vector2){(vectorA.x / value), (vectorA.y / value)};
|
||||
}
|
||||
|
||||
Vector2 operator /(Vector2 vectorA, Vector2 vectorB) {
|
||||
return (Vector2){(vectorA.x / vectorB.x), (vectorA.y / vectorB.y)};
|
||||
}
|
||||
|
||||
Vector2 operator /=(Vector2& vectorA, Vector2 vectorB) {
|
||||
vectorA.x /= vectorB.x;
|
||||
vectorA.y /= vectorB.y;
|
||||
|
||||
return vectorA;
|
||||
}
|
||||
|
||||
float Vector2Distance(Vector2 vectorA, Vector2 vectorB) {
|
||||
float const xDifference = (vectorB.x - vectorA.x);
|
||||
float const yDifference = (vectorB.y - vectorA.y);
|
||||
|
||||
return sqrt((xDifference * xDifference) + (yDifference * yDifference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the X component of a point translation given its `magnitude` and radian
|
||||
* `angle`.
|
||||
*/
|
||||
float const LengthDirectionX(float const magnitude, float const angle) {
|
||||
return (magnitude * -cos(angle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the Y component of a point translation given its `magnitude` and radian
|
||||
* `angle`.
|
||||
*/
|
||||
float const LengthDirectionY(float const magnitude, float const angle) {
|
||||
return (magnitude * -sin(angle));
|
||||
}
|
||||
|
||||
Vector2 const LengthDirection(Vector2 const lengths, float const direction) {
|
||||
return (Vector2){
|
||||
LengthDirectionX(lengths.x, direction),
|
||||
LengthDirectionY(lengths.y, direction)
|
||||
};
|
||||
}
|
||||
|
||||
float const AngleToPoint(Vector2 const originPoint, Vector2 const targetPoint) {
|
||||
return atan2((originPoint.y - targetPoint.y), (originPoint.x - targetPoint.x));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a radian `angle` by its bounds, with any value less than `-PI` returning `PI` and any
|
||||
* value greater than `PI` returning `-PI`.
|
||||
*/
|
||||
float const WrapAngle(float const angle) {
|
||||
if (angle > PI) {
|
||||
return -PI;
|
||||
} else if (angle < -PI) {
|
||||
return PI;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the linear interpolation between `angleStart` to `angleTo` with the given
|
||||
* `magnitude`, which is expected to be a normalized value representing a percentage of the
|
||||
* transformation, with `0.0f` being pure `angleStart` and `1.0f` being a very close aproximation
|
||||
* of `angleTo`.
|
||||
*/
|
||||
float const AngleDifference(float const angleStart, float const angleTo) {
|
||||
float const difference = (angleTo - angleStart);
|
||||
|
||||
return atan2(sin(difference), cos(difference));
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Raw memory type used for representing the maximum random size of a value.
|
||||
*/
|
||||
typedef long unsigned Seed;
|
||||
|
||||
/**
|
||||
* State machine for an instance of XOR shift-based pseudo-random number generation.
|
||||
*/
|
||||
typedef struct XorShifter {
|
||||
/**
|
||||
* Initial seed state iniailized when creating the pseudo-random number generator, set by
|
||||
* either manually arranging the memory or by calling [CreateXorShifter(seed_t const)]. Every
|
||||
* time a new random number is generated, usually by calling
|
||||
* [GetXorShifterValue(XorShifter* const, long const, long const)], this value will be mutated
|
||||
* with the new iteration value.
|
||||
*/
|
||||
Seed seed;
|
||||
} XorShifter;
|
||||
|
||||
/**
|
||||
* Creates a [XorShifter] with the given `seed` as initial entropy. Note that like all pseudo-
|
||||
* random number generators, the initial seed makes all sequential operations deterministic to the
|
||||
* value. I.e. running the same program twice with the same seed will yield the same results. To
|
||||
* get more entropic values either pass in the current UNIX timestamp value of the device or poll
|
||||
* the device's system-dependant entropy device for a new seed each run.
|
||||
*/
|
||||
XorShifter CreateXorShifter(Seed const seed) {
|
||||
return (XorShifter){seed};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next pseudo-random iteration in the `xorShifter`'s seeded sequence, reduced down a
|
||||
* range between `min` and `max`, provided the `xorShifter`'s seed is greater than `0`.
|
||||
*/
|
||||
long const GetXorShifterValue(XorShifter* const xorShifter, long const min, long const max) {
|
||||
if (xorShifter->seed) {
|
||||
Seed value = xorShifter->seed;
|
||||
value ^= value << 13;
|
||||
value ^= value >> 17;
|
||||
value ^= value << 5;
|
||||
|
||||
return labs((long)(xorShifter->seed = value)) % (labs(max - min) + 1) + min;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#include "core.hpp"
|
||||
|
||||
struct QuadrantCoords {
|
||||
long x;
|
||||
long y;
|
||||
};
|
||||
|
||||
struct Entity {
|
||||
float orientation;
|
||||
Vector2 speed;
|
||||
Vector2 localPosition;
|
||||
QuadrantCoords quadrantPosition;
|
||||
};
|
||||
|
||||
struct SpaceshipEntity {
|
||||
Entity entity;
|
||||
float delayedOrientation;
|
||||
Texture fusilageTexture;
|
||||
Texture enginesTexture;
|
||||
};
|
||||
|
||||
Vector2 const AddEntityForce(Entity& entity, float const direction, float const magnitude) {
|
||||
constexpr float MAGNITUDE_MAX = 0.1f;
|
||||
Vector2 const appliedForce = LengthDirection(Vector2{magnitude, magnitude}, direction);
|
||||
entity.speed = (entity.speed + appliedForce);
|
||||
|
||||
return appliedForce;
|
||||
}
|
||||
|
||||
void RemoveEntityForce(Entity& entity, float const magnitude) {
|
||||
constexpr float MIN_DRIFT = 0.001f;
|
||||
// As LengthDirection deals in vector math, the magnitude will have to be converted from a one-
|
||||
// dimensional value into a two-dimensional one. Additionally, this magnitude vector needs its
|
||||
// x and y flipping according to the relative x and y values of the subject Entity.
|
||||
Vector2 const relativeMagnitude = {
|
||||
(magnitude * (SIGN(entity.speed.x) * -1)),
|
||||
(magnitude * (SIGN(entity.speed.y) * -1))
|
||||
};
|
||||
|
||||
// Only deduct the maximum possible deductable speed before the value would inverse on itself.
|
||||
entity.speed = (entity.speed + Vector2{
|
||||
(entity.speed.x < 0.0f) ? MAX(relativeMagnitude.x, entity.speed.x) :
|
||||
MIN(relativeMagnitude.x, entity.speed.x),
|
||||
|
||||
(entity.speed.y < 0.0f) ? MAX(relativeMagnitude.y, entity.speed.y) :
|
||||
MIN(relativeMagnitude.y, entity.speed.y)
|
||||
});
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "world.cpp"
|
||||
|
||||
Texture SpaceshipFusilageTexture;
|
||||
|
||||
Texture SpaceshipEnginesTexture;
|
||||
|
||||
Texture AsteroidTexture;
|
||||
|
||||
void LoadAssets() {
|
||||
SpaceshipFusilageTexture = LoadTexture("./spaceshipFusilage.png");
|
||||
SpaceshipEnginesTexture = LoadTexture("./spaceshipEngines.png");
|
||||
}
|
||||
|
||||
int main(int argc, char const** argv) {
|
||||
int const viewportWidth = 640;
|
||||
int const viewportHeight = 360;
|
||||
Vector2 const viewportOrigin = Vector2{(viewportWidth / 2), (viewportHeight / 2)};
|
||||
int unsigned const windowFlags = 0;
|
||||
int unsigned const rendererFlags = 0;
|
||||
|
||||
InitWindow(viewportWidth, viewportHeight, "Quadrants");
|
||||
HideCursor();
|
||||
LoadAssets();
|
||||
|
||||
Texture nebulaTexture = LoadTexture("./nebula.png");
|
||||
Texture sunTexture = LoadTexture("./sun.png");
|
||||
Texture moonTexture = LoadTexture("./moon.png");
|
||||
Texture asteroidTexture = LoadTexture("./asteroid01.png");
|
||||
Worldspace world = CreateWorldspace(10);
|
||||
Camera2D camera = {0};
|
||||
camera.target = viewportOrigin;
|
||||
camera.zoom = 1.0f;
|
||||
|
||||
GenerateWorldspace(world);
|
||||
SetTargetFPS(60);
|
||||
|
||||
while (!WindowShouldClose()) {
|
||||
float const scale = (1.0f + (1.0f - camera.zoom));
|
||||
Vector2 const mousePos = GetMousePosition();
|
||||
int const mouseWheel = GetMouseWheelMove();
|
||||
float const lookAtEngageDistance = 32.0f;
|
||||
float const accel = 0.005f;
|
||||
|
||||
// Relative position checks.
|
||||
if (Vector2Distance(mousePos, viewportOrigin) > lookAtEngageDistance) {
|
||||
float const lerpStep =
|
||||
AngleDifference(world.player.entity.orientation, AngleToPoint(viewportOrigin, mousePos));
|
||||
|
||||
world.player.delayedOrientation = WrapAngle(world.player.entity.orientation + (lerpStep * 0.0005f));
|
||||
world.player.entity.orientation = WrapAngle(world.player.entity.orientation + (lerpStep * 0.2f));
|
||||
}
|
||||
|
||||
if (IsKeyDown(KEY_W)) {
|
||||
AddEntityForce(world.player.entity, world.player.entity.orientation, accel);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KEY_A)) {
|
||||
AddEntityForce(world.player.entity, (world.player.entity.orientation - HALF_PI), accel);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KEY_S)) {
|
||||
AddEntityForce(world.player.entity, (world.player.entity.orientation + PI), accel);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KEY_D)) {
|
||||
AddEntityForce(world.player.entity, (world.player.entity.orientation + HALF_PI), accel);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KEY_SPACE)) {
|
||||
RemoveEntityForce(world.player.entity, accel);
|
||||
}
|
||||
|
||||
camera.target = Vector2{-mousePos.x, -mousePos.y};
|
||||
|
||||
if (mouseWheel) {
|
||||
camera.zoom = CLAMP(camera.zoom - (((float)mouseWheel) * 0.05f), 0.5f, 1.5f);
|
||||
}
|
||||
|
||||
EntityUpdateInfo const updateInfo = UpdateEntity(world.player.entity);
|
||||
|
||||
if (updateInfo.hasMoved) {
|
||||
Vector2 const nebulaParallaxIncrement = (world.nebulaParallaxScroll + (world.player.entity.speed * 0.005f));
|
||||
world.nebulaParallaxScroll.x = wrap(nebulaParallaxIncrement.x, 0.0f, ((float)nebulaTexture.width));
|
||||
world.nebulaParallaxScroll.y = wrap(nebulaParallaxIncrement.y, 0.0f, ((float)nebulaTexture.height));
|
||||
|
||||
if (updateInfo.hasPassedQuadrant) {
|
||||
GenerateWorldspace(world);
|
||||
}
|
||||
}
|
||||
|
||||
BeginDrawing();
|
||||
{
|
||||
ClearBackground(BLACK);
|
||||
BeginMode2D(camera);
|
||||
{
|
||||
Vector2 const quadrantOffsets[] = {
|
||||
{-QUADRANT_SIZE, -QUADRANT_SIZE},
|
||||
{0.0f, -QUADRANT_SIZE},
|
||||
{QUADRANT_SIZE, -QUADRANT_SIZE},
|
||||
{-QUADRANT_SIZE, 0.0f},
|
||||
{0.0f, 0.0f},
|
||||
{QUADRANT_SIZE, 0.0f},
|
||||
{-QUADRANT_SIZE, QUADRANT_SIZE},
|
||||
{0.0f, QUADRANT_SIZE},
|
||||
{QUADRANT_SIZE, QUADRANT_SIZE}
|
||||
};
|
||||
|
||||
// DrawTextureQuad(nebulaTexture, Vector2{1, 1}, world.nebulaParallaxScroll, Rectangle{0, 0, viewportWidth, viewportHeight}, RED);
|
||||
|
||||
for (size_t i = 0; i < 9; i += 1) {
|
||||
Worldspace::Quadrant const* quadrant = (&world.loadedQuadrantMap[i]);
|
||||
Vector2 const quadrantOffset = (viewportOrigin + quadrantOffsets[i]);
|
||||
|
||||
for (size_t j = 0; j < quadrant->starCount; j += 1) {
|
||||
DrawCircleV(((quadrantOffset + quadrant->stars[j]) - world.player.entity.localPosition), 1.0f, WHITE);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < quadrant->orbitalCount; j += 1) {
|
||||
Worldspace::Orbital const quadrantOrbital = quadrant->orbitals[j];
|
||||
|
||||
DrawTextureEx(
|
||||
asteroidTexture,
|
||||
((quadrantOffset + quadrantOrbital.localPosition) - world.player.entity.localPosition),
|
||||
(quadrantOrbital.orientation * RAD2DEG),
|
||||
quadrantOrbital.scale,
|
||||
WHITE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw player.
|
||||
DrawTexturePro(
|
||||
SpaceshipEnginesTexture,
|
||||
(Rectangle){0, 0, ((float)SpaceshipEnginesTexture.width), ((float)SpaceshipEnginesTexture.height)},
|
||||
(Rectangle){viewportOrigin.x, viewportOrigin.y, ((float)SpaceshipEnginesTexture.width), ((float)SpaceshipEnginesTexture.height)},
|
||||
(Vector2){(float)(SpaceshipEnginesTexture.width / 2), (float)(SpaceshipEnginesTexture.height / 2)},
|
||||
(world.player.delayedOrientation * RAD2DEG),
|
||||
WHITE
|
||||
);
|
||||
|
||||
DrawTexturePro(
|
||||
SpaceshipFusilageTexture,
|
||||
(Rectangle){0, 0, (float)(SpaceshipFusilageTexture.width), (float)(SpaceshipFusilageTexture.height)},
|
||||
(Rectangle){viewportOrigin.x, viewportOrigin.y, ((float)SpaceshipFusilageTexture.width), ((float)SpaceshipFusilageTexture.height)},
|
||||
(Vector2){(float)(SpaceshipFusilageTexture.width / 2), (float)(SpaceshipFusilageTexture.height / 2)},
|
||||
(world.player.entity.orientation * RAD2DEG),
|
||||
WHITE
|
||||
);
|
||||
}
|
||||
EndMode2D();
|
||||
// Draw UI.
|
||||
DrawCircleLines(((int)mousePos.x), ((int)mousePos.y), 10.0f, WHITE);
|
||||
DrawText(TextFormat("Scale: %f", scale), 0, 0, 22, WHITE);
|
||||
}
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
#include "entity.cpp"
|
||||
#include <string.h>
|
||||
|
||||
constexpr struct {
|
||||
size_t min;
|
||||
size_t max;
|
||||
} QUADRANT_STARS = {100, 300};
|
||||
|
||||
constexpr struct {
|
||||
size_t min;
|
||||
size_t max;
|
||||
} QUADRANT_ORBITALS = {0, 7};
|
||||
|
||||
constexpr auto QUADRANT_RANGE = 512;
|
||||
|
||||
constexpr auto QUADRANT_SIZE = (QUADRANT_RANGE * 2);
|
||||
|
||||
struct EntityUpdateInfo {
|
||||
bool hasPassedQuadrant;
|
||||
|
||||
bool hasMoved;
|
||||
};
|
||||
|
||||
struct Worldspace {
|
||||
enum struct OrbitalType {
|
||||
SUN,
|
||||
MOON
|
||||
};
|
||||
|
||||
struct Orbital {
|
||||
OrbitalType type;
|
||||
Vector2 localPosition;
|
||||
float orientation;
|
||||
float scale;
|
||||
};
|
||||
|
||||
struct Quadrant {
|
||||
QuadrantCoords id;
|
||||
size_t starCount;
|
||||
size_t orbitalCount;
|
||||
Vector2 stars[QUADRANT_STARS.max];
|
||||
Orbital orbitals[QUADRANT_ORBITALS.max];
|
||||
};
|
||||
|
||||
Seed seed;
|
||||
SpaceshipEntity player;
|
||||
Vector2 nebulaParallaxScroll;
|
||||
Quadrant loadedQuadrantMap[9];
|
||||
};
|
||||
|
||||
Worldspace const CreateWorldspace(Seed const seed) {
|
||||
Worldspace world = {0};
|
||||
world.seed = seed;
|
||||
world.player.entity.localPosition = Vector2{0, 0};
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
void GenerateWorldspace(Worldspace& world) {
|
||||
QuadrantCoords offset = {-1, -1};
|
||||
|
||||
memset(((void*)world.loadedQuadrantMap), 0, (sizeof(Worldspace::Quadrant) * 9));
|
||||
|
||||
for (size_t i = 0; i < 3; i += 1) {
|
||||
for (size_t j = 0; j < 3; j += 1) {
|
||||
Worldspace::Quadrant* quadrant = (&world.loadedQuadrantMap[j + (i * 3)]);
|
||||
|
||||
QuadrantCoords const quadrantId = {
|
||||
(world.player.entity.quadrantPosition.x + offset.x),
|
||||
(world.player.entity.quadrantPosition.y + offset.y)
|
||||
};
|
||||
|
||||
quadrant->id = quadrantId;
|
||||
|
||||
XorShifter seededGenerator = CreateXorShifter(
|
||||
(QUADRANT_SIZE - (quadrantId.x + quadrantId.y)) * world.seed);
|
||||
|
||||
quadrant->starCount =
|
||||
(size_t const)GetXorShifterValue(&seededGenerator, QUADRANT_STARS.min, QUADRANT_STARS.max);
|
||||
|
||||
quadrant->orbitalCount = (size_t const)GetXorShifterValue(
|
||||
&seededGenerator, QUADRANT_ORBITALS.min, QUADRANT_ORBITALS.max);
|
||||
|
||||
for (size_t k = 0; k < quadrant->starCount; k += 1) {
|
||||
quadrant->stars[k] = (Vector2){
|
||||
(float const)GetXorShifterValue(&seededGenerator, -QUADRANT_RANGE, QUADRANT_RANGE),
|
||||
(float const)GetXorShifterValue(&seededGenerator, -QUADRANT_RANGE, QUADRANT_RANGE)
|
||||
};
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < quadrant->orbitalCount; k += 1) {
|
||||
quadrant->orbitals[k] = (Worldspace::Orbital){
|
||||
(Worldspace::OrbitalType)GetXorShifterValue(&seededGenerator, 0, 1),
|
||||
(Vector2){
|
||||
(float const)GetXorShifterValue(&seededGenerator, -QUADRANT_RANGE, QUADRANT_RANGE),
|
||||
(float const)GetXorShifterValue(&seededGenerator, -QUADRANT_RANGE, QUADRANT_RANGE)
|
||||
},
|
||||
(float const)GetXorShifterValue(&seededGenerator, -PI, PI),
|
||||
(((float const)GetXorShifterValue(&seededGenerator, 10, 100)) / 100.0f)
|
||||
};
|
||||
}
|
||||
|
||||
offset.x += 1;
|
||||
}
|
||||
|
||||
offset.x = -1;
|
||||
offset.y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool const CheckEntityQuadrantBounds(Entity& entity, int* const xBounds, int* const yBounds) {
|
||||
int const x = ((entity.localPosition.x > QUADRANT_RANGE) ?
|
||||
1 : ((entity.localPosition.x < -QUADRANT_RANGE) ? -1 : 0));
|
||||
|
||||
int const y = ((entity.localPosition.y > QUADRANT_RANGE) ?
|
||||
1 : ((entity.localPosition.y < -QUADRANT_RANGE) ? -1 : 0));
|
||||
|
||||
if (xBounds) {
|
||||
*xBounds = x;
|
||||
}
|
||||
|
||||
if (yBounds) {
|
||||
*yBounds = y;
|
||||
}
|
||||
|
||||
return !(x || y);
|
||||
}
|
||||
|
||||
EntityUpdateInfo const UpdateEntity(Entity& entity) {
|
||||
int quadrantBoundsCheckX;
|
||||
int quadrantBoundsCheckY;
|
||||
EntityUpdateInfo info = {0};
|
||||
|
||||
if (CheckEntityQuadrantBounds(entity, &quadrantBoundsCheckX, &quadrantBoundsCheckY)) {
|
||||
entity.localPosition += entity.speed;
|
||||
info.hasMoved = true;
|
||||
} else {
|
||||
if (quadrantBoundsCheckX) {
|
||||
entity.localPosition.x = ((QUADRANT_RANGE * -quadrantBoundsCheckX) + entity.speed.x);
|
||||
entity.quadrantPosition.x += quadrantBoundsCheckX;
|
||||
}
|
||||
|
||||
if (quadrantBoundsCheckY) {
|
||||
entity.localPosition.y = ((QUADRANT_RANGE * -quadrantBoundsCheckY) + entity.speed.y);
|
||||
entity.quadrantPosition.y += quadrantBoundsCheckY;
|
||||
}
|
||||
|
||||
info.hasPassedQuadrant = true;
|
||||
info.hasMoved = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
Loading…
Reference in New Issue