Physics I guess

This commit is contained in:
2025-09-15 19:37:01 -05:00
parent 07ab2b4b02
commit f799690d3c
25 changed files with 315 additions and 13 deletions

View File

@@ -35,6 +35,7 @@ add_subdirectory(engine)
add_subdirectory(error) add_subdirectory(error)
add_subdirectory(input) add_subdirectory(input)
# add_subdirectory(locale) # add_subdirectory(locale)
add_subdirectory(physics)
add_subdirectory(rpg) add_subdirectory(rpg)
add_subdirectory(thread) add_subdirectory(thread)
add_subdirectory(time) add_subdirectory(time)

View File

@@ -70,6 +70,23 @@ void cameraPushMatrix(camera_t *camera) {
view view
); );
break; break;
case CAMERA_VIEW_TYPE_2D:
glm_mat4_identity(view);
glm_translate(view, (vec3){
-camera->_2d.position[0],
-camera->_2d.position[1],
0.0f
});
glm_scale(view, (vec3){
camera->_2d.zoom,
camera->_2d.zoom,
1.0f
});
break;
default:
assertUnreachable("Invalid camera view type");
} }
#if DISPLAY_SDL2 #if DISPLAY_SDL2

View File

@@ -18,7 +18,8 @@ typedef enum {
typedef enum { typedef enum {
CAMERA_VIEW_TYPE_MATRIX, CAMERA_VIEW_TYPE_MATRIX,
CAMERA_VIEW_TYPE_LOOKAT CAMERA_VIEW_TYPE_LOOKAT,
CAMERA_VIEW_TYPE_2D
} cameraviewtype_t; } cameraviewtype_t;
typedef struct { typedef struct {
@@ -27,11 +28,17 @@ typedef struct {
union { union {
mat4 view; mat4 view;
struct { struct {
float_t position[3]; float_t position[3];
float_t target[3]; float_t target[3];
float_t up[3]; float_t up[3];
} lookat; } lookat;
struct {
float_t position[2];
float_t zoom;
} _2d;
}; };
union { union {

View File

@@ -10,4 +10,5 @@ target_sources(${DUSK_TARGET_NAME}
) )
# Subdirs # Subdirs
add_subdirectory(overworld) add_subdirectory(overworld)
add_subdirectory(test)

View File

@@ -93,9 +93,9 @@ void sceneOverworldRenderEntity(const entity_t *entity) {
// For now, just draw a placeholder quad. // For now, just draw a placeholder quad.
spriteBatchPush( spriteBatchPush(
&testAsset->paletteImage.texture, &testAsset->paletteImage.texture,
entity->x, entity->y, entity->position[0], entity->position[1],
entity->x + TILESET_ENTITIES.tileWidth, entity->position[0] + TILESET_ENTITIES.tileWidth,
entity->y + TILESET_ENTITIES.tileHeight, entity->position[1] + TILESET_ENTITIES.tileHeight,
COLOR_WHITE, COLOR_WHITE,
uv[0], uv[1], uv[2], uv[3] uv[0], uv[1], uv[2], uv[3]
); );

View File

@@ -25,6 +25,7 @@ typedef struct {
typedef enum { typedef enum {
SCENE_TYPE_LOGO, SCENE_TYPE_LOGO,
SCENE_TYPE_TEST,
SCENE_TYPE_OVERWORLD, SCENE_TYPE_OVERWORLD,
SCENE_TYPE_COUNT SCENE_TYPE_COUNT

View File

@@ -8,12 +8,20 @@
#include "scenemanager.h" #include "scenemanager.h"
#include "display/scene/overworld/sceneoverworld.h" #include "display/scene/overworld/sceneoverworld.h"
#include "display/scene/test/scenetest.h"
scenemanager_t SCENE_MANAGER; scenemanager_t SCENE_MANAGER;
scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT] = { scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT] = {
[SCENE_TYPE_LOGO] = { 0 }, [SCENE_TYPE_LOGO] = { 0 },
[SCENE_TYPE_TEST] = {
.init = sceneTestInit,
.update = sceneTestUpdate,
.render = sceneTestRender,
.dispose = sceneTestDispose
},
[SCENE_TYPE_OVERWORLD] = { [SCENE_TYPE_OVERWORLD] = {
.init = sceneOverworldInit, .init = sceneOverworldInit,
.update = sceneOverworldUpdate, .update = sceneOverworldUpdate,

View File

@@ -15,7 +15,22 @@ typedef struct {
extern scenemanager_t SCENE_MANAGER; extern scenemanager_t SCENE_MANAGER;
extern scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT]; extern scene_t SCENE_MANAGER_SCENES[SCENE_TYPE_COUNT];
/**
* Initializes the scene manager and the initial scene.
*/
errorret_t sceneManagerInit(void); errorret_t sceneManagerInit(void);
/**
* Updates all active scenes.
*/
void sceneManagerUpdate(void); void sceneManagerUpdate(void);
/**
* Renders all visible scenes.
*/
void sceneManagerRender(void); void sceneManagerRender(void);
/**
* Disposes of all scenes.
*/
void sceneManagerDispose(void); void sceneManagerDispose(void);

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
scenetest.c
)

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scenetest.h"
#include "display/scene/scenemanager.h"
#include "display/spritebatch/spritebatch.h"
scenetest_t SCENE_TEST;
errorret_t sceneTestInit(void) {
cameraInit(&SCENE_TEST.camera);
SCENE_TEST.camera.projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC;
SCENE_TEST.camera.nearClip = -1.0f;
SCENE_TEST.camera.farClip = 2.0f;
SCENE_TEST.camera.viewType = CAMERA_VIEW_TYPE_2D;
SCENE_TEST.camera._2d.zoom = 2.0f;
SCENE_TEST.camera._2d.position[0] = -150.0f;
SCENE_TEST.camera._2d.position[1] = -50.0f;
scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_TEST];
scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE;
errorOk();
}
void sceneTestUpdate(void) {
}
void sceneTestRender(void) {
SCENE_TEST.camera.orthographic.left = 0.0f;
SCENE_TEST.camera.orthographic.right = frameBufferGetWidth(FRAMEBUFFER_BOUND);
SCENE_TEST.camera.orthographic.top = frameBufferGetHeight(FRAMEBUFFER_BOUND);
SCENE_TEST.camera.orthographic.bottom = 0.0f;
cameraPushMatrix(&SCENE_TEST.camera);
spriteBatchClear();
spriteBatchFlush();
cameraPopMatrix();
}
void sceneTestDispose(void) {
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/camera.h"
#include "error/error.h"
typedef struct {
camera_t camera;
} scenetest_t;
extern scenetest_t SCENE_TEST;
/**
* Initialize the test scene.
*/
errorret_t sceneTestInit(void);
/**
* Update the test scene.
*/
void sceneTestUpdate(void);
/**
* Render the test scene.
*/
void sceneTestRender(void);
/**
* Dispose of the test scene.
*/
void sceneTestDispose(void);

View File

@@ -16,8 +16,10 @@
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <float.h> #include <float.h>
#include <cglm/cglm.h> #include <cglm/cglm.h>
#include <cglm/types.h> #include <cglm/types.h>
#include <cglm/vec2.h>
#if PSP #if PSP
#include <pspkernel.h> #include <pspkernel.h>

View File

@@ -71,7 +71,7 @@ errorret_t errorChainImpl(
) { ) {
if (retval.code == ERROR_OK) return retval; if (retval.code == ERROR_OK) return retval;
assertNotNull(retval.state, "Error state cannot be NULL"); assertNotNull(retval.state, "Error state NULL (Likely missing errorOk)");
assertNotNull(retval.state->message, "Message cannot be NULL"); assertNotNull(retval.state->message, "Message cannot be NULL");
// Create a new line string. // Create a new line string.

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
physicscircle.c
)

9
src/physics/physics.h Normal file
View File

@@ -0,0 +1,9 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "physicscircle.h"

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "physicscircle.h"
void physicsCircleCheckCircle(
const physicscircle_t a,
const physicscircle_t b,
physicscirclecircleresult_t *out
) {
vec2 delta;
glm_vec2_sub(b.position, a.position, delta);
float_t distSq = glm_vec2_dot(delta, delta);
float_t radiusSum = a.radius + b.radius;
float_t radiusSumSq = radiusSum * radiusSum;
if(distSq < radiusSumSq) {
out->hit = true;
if (distSq != 0.0f) {
glm_vec2_normalize_to(delta, out->normal);
} else {
out->normal[0] = 1.0f;
out->normal[1] = 0.0f;
}
out->depth = radiusSum - sqrtf(distSq);
} else {
out->hit = false;
}
}

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct physicscircle_s {
vec2 position;
float_t radius;
} physicscircle_t;
typedef struct physicscirclecircleresult_s {
bool_t hit;
vec2 normal;
float_t depth;
} physicscirclecircleresult_t;
/**
* Check for collision between two circles.
*
* @param a The first circle.
* @param b The second circle.
* @param out Pointer to the result structure to populate.
*/
void physicsCircleCheckCircle(
const physicscircle_t a,
const physicscircle_t b,
physicscirclecircleresult_t *out
);

View File

@@ -8,6 +8,7 @@
#include "entity.h" #include "entity.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
#include "display/tileset/tileset_entities.h"
entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = { entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
{ NULL, NULL }, // ENTITY_TYPE_NULL { NULL, NULL }, // ENTITY_TYPE_NULL

View File

@@ -9,6 +9,7 @@
// #include "direction.h" // #include "direction.h"
#include "rpg/entity/player.h" #include "rpg/entity/player.h"
#include "npc.h" #include "npc.h"
#include "physics/physics.h"
typedef struct { typedef struct {
void (*init)(entity_t *entity); void (*init)(entity_t *entity);
@@ -25,10 +26,12 @@ typedef enum {
typedef struct entity_s { typedef struct entity_s {
// uint32_t id;// Completely unique ID for this entity. // uint32_t id;// Completely unique ID for this entity.
float_t x, y;
entitytype_t type; entitytype_t type;
// direction_t dir; // direction_t dir;
vec2 position;
vec2 velocity;
union { union {
player_t player; player_t player;
npc_t npc; npc_t npc;

View File

@@ -11,6 +11,7 @@
#include "input/input.h" #include "input/input.h"
#include "display/scene/overworld/sceneoverworld.h" #include "display/scene/overworld/sceneoverworld.h"
#include "display/tileset/tileset_entities.h"
void playerInit(entity_t *entity) { void playerInit(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL"); assertNotNull(entity, "Entity pointer cannot be NULL");
@@ -26,9 +27,26 @@ void playerUpdate(entity_t *entity) {
inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN) inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN)
}; };
glm_vec2_normalize(dir); glm_vec2_normalize(dir);
entity->x += move * dir[0]; entity->position[0] += move * dir[0];
entity->y -= move * dir[1]; entity->position[1] -= move * dir[1];
SCENE_OVERWORLD.camera.lookat.target[0] = entity->x; SCENE_OVERWORLD.camera.lookat.target[0] = entity->position[0];
SCENE_OVERWORLD.camera.lookat.target[1] = entity->y; SCENE_OVERWORLD.camera.lookat.target[1] = entity->position[1];
// Can we move?
physicscircle_t npc = {
.position = { 32.0f, 32.0f },
.radius = TILESET_ENTITIES.tileWidth / 2.0f
};
physicscircle_t self;
glm_vec2_copy(entity->position, self.position);
self.radius = npc.radius;
physicscirclecircleresult_t result;
physicsCircleCheckCircle(self, npc, &result);
if(result.hit) {
entity->position[0] -= result.normal[0] * result.depth;
entity->position[1] -= result.normal[1] * result.depth;
}
} }

View File

@@ -19,8 +19,8 @@ void rpgInit() {
entity_t *npc = mapEntityAdd(&testMap); entity_t *npc = mapEntityAdd(&testMap);
entityInit(npc, ENTITY_TYPE_NPC); entityInit(npc, ENTITY_TYPE_NPC);
npc->x = 32.0f; npc->position[0] = 32.0f;
npc->y = 32.0f; npc->position[1] = 32.0f;
} }
void rpgUpdate() { void rpgUpdate() {

View File

@@ -10,9 +10,25 @@
#define MAP_ENTITY_COUNT_MAX 32 #define MAP_ENTITY_COUNT_MAX 32
#define MAP_WIDTH_MAX 64
#define MAP_HEIGHT_MAX 64
#define MAP_TILE_COUNT_MAX (MAP_WIDTH_MAX * MAP_HEIGHT_MAX)
typedef struct {
uint8_t id;
} tile_t;
typedef struct {
tile_t tiles[MAP_TILE_COUNT_MAX];
} maplayer_t;
typedef struct { typedef struct {
entity_t entities[MAP_ENTITY_COUNT_MAX]; entity_t entities[MAP_ENTITY_COUNT_MAX];
uint8_t entityCount; uint8_t entityCount;
uint8_t width, height;
maplayer_t base;
maplayer_t overlay;
} map_t; } map_t;
extern map_t testMap; extern map_t testMap;

16
src/rpg/world/tile.h Normal file
View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
typedef enum {
TILE_TYPE_NULL,
} tiletype_t;
typedef struct {
tiletype_t type;
} tile_t;

View File

@@ -21,6 +21,9 @@ void timeInit(void) {
// Set these to something non-zero. // Set these to something non-zero.
TIME.time = TIME_STEP; TIME.time = TIME_STEP;
TIME.delta = TIME_STEP; TIME.delta = TIME_STEP;
TIME.fixedDelta = TIME_STEP;
TIME.fixedTime = TIME_STEP;
} }
void timeUpdate(void) { void timeUpdate(void) {
@@ -36,4 +39,14 @@ void timeUpdate(void) {
TIME.delta = delta; TIME.delta = delta;
assertTrue(TIME.delta >= 0.0f, "Time delta is negative"); assertTrue(TIME.delta >= 0.0f, "Time delta is negative");
TIME.time += TIME.delta; TIME.time += TIME.delta;
// Perform a fixed time step.
if(TIME.time - TIME.fixedTime >= TIME_STEP) {
TIME.fixedUpdate = true;
TIME.fixedDelta = TIME_STEP;
TIME.fixedTime += TIME_STEP;
} else {
TIME.fixedDelta = 0.0f;
TIME.fixedUpdate = false;
}
} }

View File

@@ -11,6 +11,10 @@
typedef struct { typedef struct {
float_t delta; float_t delta;
float_t time; float_t time;
bool_t fixedUpdate;
float_t fixedDelta;
float_t fixedTime;
} dusktime_t; } dusktime_t;
extern dusktime_t TIME; extern dusktime_t TIME;