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