Test
This commit is contained in:
@@ -22,3 +22,6 @@ X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL, NULL)
|
|||||||
X(RENDERABLE, entityrenderable_t, renderable,
|
X(RENDERABLE, entityrenderable_t, renderable,
|
||||||
entityRenderableInit, entityRenderableDispose, NULL)
|
entityRenderableInit, entityRenderableDispose, NULL)
|
||||||
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, NULL, NULL)
|
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, NULL, NULL)
|
||||||
|
|
||||||
|
// Game-specific components
|
||||||
|
#include "entity/gamecomponentlist.h"
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(entity)
|
||||||
add_subdirectory(game)
|
add_subdirectory(game)
|
||||||
add_subdirectory(input)
|
add_subdirectory(input)
|
||||||
add_subdirectory(item)
|
add_subdirectory(item)
|
||||||
|
add_subdirectory(scene)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Header-only: gamecomponentlist.h is an X-macro list, no implementation.
|
||||||
|
|
||||||
|
add_subdirectory(component)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
add_subdirectory(overworld)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
entityplayer.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entityplayer.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/physics/entityphysics.h"
|
||||||
|
#include "entity/component/display/entitycamera.h"
|
||||||
|
#include "input/input.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
|
#define ENTITY_PLAYER_MOVE_SPEED_DEFAULT 4.0f
|
||||||
|
#define ENTITY_PLAYER_JUMP_IMPULSE_DEFAULT 6.0f
|
||||||
|
|
||||||
|
void entityPlayerInit(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityplayer_t *player = entityPlayerGet(mgr, entityId, componentId);
|
||||||
|
|
||||||
|
memoryZero(player, sizeof(entityplayer_t));
|
||||||
|
|
||||||
|
player->moveSpeed = ENTITY_PLAYER_MOVE_SPEED_DEFAULT;
|
||||||
|
player->jumpImpulse = ENTITY_PLAYER_JUMP_IMPULSE_DEFAULT;
|
||||||
|
|
||||||
|
entityUpdateAdd(mgr, entityId, entityPlayerUpdate, componentId, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
entityplayer_t *entityPlayerGet(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
return componentGetData(mgr, entityId, componentId, COMPONENT_TYPE_PLAYER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityPlayerUpdate(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
componentid_t physComp = entityGetComponent(
|
||||||
|
mgr, entityId, COMPONENT_TYPE_PHYSICS
|
||||||
|
);
|
||||||
|
if(physComp == COMPONENT_ID_INVALID) return;
|
||||||
|
|
||||||
|
entityplayer_t *player = entityPlayerGet(mgr, entityId, componentId);
|
||||||
|
|
||||||
|
vec2 moveInput;
|
||||||
|
inputAxis2D(
|
||||||
|
INPUT_BIND_LEFT, INPUT_BIND_RIGHT,
|
||||||
|
INPUT_BIND_DOWN, INPUT_BIND_UP,
|
||||||
|
moveInput
|
||||||
|
);
|
||||||
|
|
||||||
|
// Move relative to the current camera's horizontal facing, not fixed
|
||||||
|
// world axes, so "up" always means "away from the camera".
|
||||||
|
vec2 forward = { 0.0f, -1.0f };
|
||||||
|
vec2 right = { 1.0f, 0.0f };
|
||||||
|
entityid_t camEntity = entityCameraGetCurrent(mgr);
|
||||||
|
if(camEntity != ENTITY_ID_INVALID) {
|
||||||
|
entityCameraGetForward(mgr, camEntity, forward);
|
||||||
|
entityCameraGetRight(mgr, camEntity, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 moveDir = {
|
||||||
|
right[0] * moveInput[0] + forward[0] * moveInput[1],
|
||||||
|
right[1] * moveInput[0] + forward[1] * moveInput[1]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Clamp to unit length so diagonal input isn't faster than cardinal.
|
||||||
|
float_t mag = sqrtf(moveDir[0] * moveDir[0] + moveDir[1] * moveDir[1]);
|
||||||
|
if(mag > 1.0f) {
|
||||||
|
moveDir[0] /= mag;
|
||||||
|
moveDir[1] /= mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 velocity;
|
||||||
|
entityPhysicsGetVelocity(mgr, entityId, physComp, velocity);
|
||||||
|
velocity[0] = moveDir[0] * player->moveSpeed;
|
||||||
|
velocity[2] = moveDir[1] * player->moveSpeed;
|
||||||
|
entityPhysicsSetVelocity(mgr, entityId, physComp, velocity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "entity/entitybase.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float_t moveSpeed;
|
||||||
|
float_t jumpImpulse;
|
||||||
|
} entityplayer_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the player component: sets default move speed and jump
|
||||||
|
* impulse.
|
||||||
|
*
|
||||||
|
* @param mgr The entity manager that owns the entity.
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
*/
|
||||||
|
void entityPlayerInit(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlying player structure (temporarily) for the given entity.
|
||||||
|
* This is really just intended for doing operations faster than using the
|
||||||
|
* getters and setters, but it is preferred that you use those.
|
||||||
|
*
|
||||||
|
* @param mgr The entity manager that owns the entity.
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @return The player component data for the given entity and component ID.
|
||||||
|
*/
|
||||||
|
entityplayer_t *entityPlayerGet(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-tick update for the player component: reads the movement input axes
|
||||||
|
* and drives the entity's physics velocity, relative to the current
|
||||||
|
* camera's horizontal facing (so "up" always moves away from the camera
|
||||||
|
* and "left"/"right" strafe relative to its view), rather than fixed world
|
||||||
|
* axes. No-op if the entity has no physics component. Registered
|
||||||
|
* automatically as an update callback by entityPlayerInit.
|
||||||
|
*
|
||||||
|
* @param mgr The entity manager that owns the entity.
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @param user Unused.
|
||||||
|
*/
|
||||||
|
void entityPlayerUpdate(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Game-specific component types, appended after the engine's inbuilt
|
||||||
|
// components in entity/componentlist.h.
|
||||||
|
#include "entity/component/overworld/entityplayer.h"
|
||||||
|
|
||||||
|
// Name (Uppercase)
|
||||||
|
// Structure
|
||||||
|
// Field name (lowercase)
|
||||||
|
// Init function (optional)
|
||||||
|
// Dispose function (optional)
|
||||||
|
// Render function (optional)
|
||||||
|
|
||||||
|
X(PLAYER, entityplayer_t, player, entityPlayerInit, NULL, NULL)
|
||||||
@@ -6,8 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "game/game.h"
|
#include "game/game.h"
|
||||||
|
#include "scene/scene.h"
|
||||||
|
#include "scene/overworldscene.h"
|
||||||
|
|
||||||
errorret_t gameInit(void) {
|
errorret_t gameInit(void) {
|
||||||
|
sceneSetActive(overworldSceneCreate());
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
overworldscene.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "overworldscene.h"
|
||||||
|
#include "scene/scene.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/display/entityposition.h"
|
||||||
|
#include "entity/component/display/entitycamera.h"
|
||||||
|
#include "entity/component/display/entityrenderable.h"
|
||||||
|
#include "entity/component/physics/entityphysics.h"
|
||||||
|
#include "display/mesh/plane.h"
|
||||||
|
#include "display/mesh/capsule.h"
|
||||||
|
#include "display/color.h"
|
||||||
|
#include "time/time.h"
|
||||||
|
|
||||||
|
#define OVERWORLD_SCENE_CAMERA_ORBIT_RADIUS 8.0f
|
||||||
|
#define OVERWORLD_SCENE_CAMERA_ORBIT_HEIGHT 5.0f
|
||||||
|
#define OVERWORLD_SCENE_CAMERA_ORBIT_SPEED 0.5f
|
||||||
|
|
||||||
|
static overworldcameraorbit_t OVERWORLD_SCENE_CAMERA_ORBIT;
|
||||||
|
|
||||||
|
sceneid_t overworldSceneCreate(void) {
|
||||||
|
sceneid_t sceneId = sceneCreate();
|
||||||
|
entitymanager_t *mgr = sceneGetEntities(sceneId);
|
||||||
|
|
||||||
|
// Camera, orbiting the origin (see overworldSceneCameraOrbitUpdate).
|
||||||
|
entityid_t camEntity = entityManagerAdd(mgr);
|
||||||
|
componentid_t camPosition = entityAddComponent(
|
||||||
|
mgr, camEntity, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
entityAddComponent(mgr, camEntity, COMPONENT_TYPE_CAMERA);
|
||||||
|
|
||||||
|
OVERWORLD_SCENE_CAMERA_ORBIT = (overworldcameraorbit_t){
|
||||||
|
.angle = 0.0f,
|
||||||
|
.radius = OVERWORLD_SCENE_CAMERA_ORBIT_RADIUS,
|
||||||
|
.height = OVERWORLD_SCENE_CAMERA_ORBIT_HEIGHT,
|
||||||
|
.speed = OVERWORLD_SCENE_CAMERA_ORBIT_SPEED
|
||||||
|
};
|
||||||
|
entityUpdateAdd(
|
||||||
|
mgr, camEntity, overworldSceneCameraOrbitUpdate, camPosition,
|
||||||
|
&OVERWORLD_SCENE_CAMERA_ORBIT
|
||||||
|
);
|
||||||
|
// Position it correctly for the very first rendered frame, rather than
|
||||||
|
// waiting for the first fixed tick to run.
|
||||||
|
overworldSceneCameraOrbitUpdate(
|
||||||
|
mgr, camEntity, camPosition, &OVERWORLD_SCENE_CAMERA_ORBIT
|
||||||
|
);
|
||||||
|
|
||||||
|
// Static ground plane. Physics ignores the entity's position component --
|
||||||
|
// the shape's own normal/distance fully define the plane in world space.
|
||||||
|
entityid_t planeEntity = entityManagerAdd(mgr);
|
||||||
|
componentid_t planePosition = entityAddComponent(
|
||||||
|
mgr, planeEntity, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
entityPositionSetLocalPosition(
|
||||||
|
mgr, planeEntity, planePosition, (vec3){ -10.0f, 0.0f, -10.0f }
|
||||||
|
);
|
||||||
|
entityPositionSetLocalScale(
|
||||||
|
mgr, planeEntity, planePosition, (vec3){ 20.0f, 1.0f, 20.0f }
|
||||||
|
);
|
||||||
|
componentid_t planePhysics = entityAddComponent(
|
||||||
|
mgr, planeEntity, COMPONENT_TYPE_PHYSICS
|
||||||
|
);
|
||||||
|
entityPhysicsSetBodyType(
|
||||||
|
mgr, planeEntity, planePhysics, PHYSICS_BODY_STATIC
|
||||||
|
);
|
||||||
|
entityPhysicsSetShape(mgr, planeEntity, planePhysics, (physicsshape_t){
|
||||||
|
.type = PHYSICS_SHAPE_PLANE,
|
||||||
|
.data.plane = { .normal = { 0.0f, 1.0f, 0.0f }, .distance = 0.0f }
|
||||||
|
});
|
||||||
|
componentid_t planeRenderable = entityAddComponent(
|
||||||
|
mgr, planeEntity, COMPONENT_TYPE_RENDERABLE
|
||||||
|
);
|
||||||
|
entityrenderable_t *planeR = componentGetData(
|
||||||
|
mgr, planeEntity, planeRenderable, COMPONENT_TYPE_RENDERABLE
|
||||||
|
);
|
||||||
|
planeR->data.material.meshes[0] = &PLANE_MESH_SIMPLE;
|
||||||
|
entityRenderableSetColor(mgr, planeEntity, planeRenderable, COLOR_GRAY);
|
||||||
|
|
||||||
|
// Player: dynamic capsule body, moved relative to the camera by
|
||||||
|
// COMPONENT_TYPE_PLAYER's own update callback (see entityplayer.c).
|
||||||
|
entityid_t playerEntity = entityManagerAdd(mgr);
|
||||||
|
componentid_t playerPosition = entityAddComponent(
|
||||||
|
mgr, playerEntity, COMPONENT_TYPE_POSITION
|
||||||
|
);
|
||||||
|
entityPositionSetLocalPosition(
|
||||||
|
mgr, playerEntity, playerPosition, (vec3){ 0.0f, 2.0f, 0.0f }
|
||||||
|
);
|
||||||
|
componentid_t playerPhysics = entityAddComponent(
|
||||||
|
mgr, playerEntity, COMPONENT_TYPE_PHYSICS
|
||||||
|
);
|
||||||
|
entityPhysicsSetShape(mgr, playerEntity, playerPhysics, (physicsshape_t){
|
||||||
|
.type = PHYSICS_SHAPE_CAPSULE,
|
||||||
|
.data.capsule = { .radius = 0.5f, .halfHeight = 0.5f }
|
||||||
|
});
|
||||||
|
componentid_t playerRenderable = entityAddComponent(
|
||||||
|
mgr, playerEntity, COMPONENT_TYPE_RENDERABLE
|
||||||
|
);
|
||||||
|
entityrenderable_t *playerR = componentGetData(
|
||||||
|
mgr, playerEntity, playerRenderable, COMPONENT_TYPE_RENDERABLE
|
||||||
|
);
|
||||||
|
playerR->data.material.meshes[0] = &CAPSULE_MESH_SIMPLE;
|
||||||
|
entityRenderableSetColor(mgr, playerEntity, playerRenderable, COLOR_BLUE);
|
||||||
|
entityAddComponent(mgr, playerEntity, COMPONENT_TYPE_PLAYER);
|
||||||
|
|
||||||
|
return sceneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void overworldSceneCameraOrbitUpdate(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
overworldcameraorbit_t *orbit = (overworldcameraorbit_t *)user;
|
||||||
|
orbit->angle += TIME.delta * orbit->speed;
|
||||||
|
|
||||||
|
vec3 eye = {
|
||||||
|
cosf(orbit->angle) * orbit->radius,
|
||||||
|
orbit->height,
|
||||||
|
sinf(orbit->angle) * orbit->radius
|
||||||
|
};
|
||||||
|
entityPositionLookAt(
|
||||||
|
mgr, entityId, componentId,
|
||||||
|
eye,
|
||||||
|
(vec3){ 0.0f, 0.0f, 0.0f },
|
||||||
|
(vec3){ 0.0f, 1.0f, 0.0f }
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "scene/scenebase.h"
|
||||||
|
#include "entity/entitybase.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float_t angle;
|
||||||
|
float_t radius;
|
||||||
|
float_t height;
|
||||||
|
float_t speed;
|
||||||
|
} overworldcameraorbit_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the overworld scene: a static ground plane, a player entity
|
||||||
|
* (dynamic capsule body, moved relative to the camera by
|
||||||
|
* COMPONENT_TYPE_PLAYER's own update callback), and a camera orbiting the
|
||||||
|
* origin (see overworldSceneCameraOrbitUpdate). Does not make the scene
|
||||||
|
* active -- call sceneSetActive with the returned ID.
|
||||||
|
*
|
||||||
|
* @return The ID of the newly created scene.
|
||||||
|
*/
|
||||||
|
sceneid_t overworldSceneCreate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-tick update for the test camera: orbits it around the world origin
|
||||||
|
* at a fixed radius/height/speed, always looking back at the origin.
|
||||||
|
* Registered automatically by overworldSceneCreate.
|
||||||
|
*
|
||||||
|
* @param mgr The entity manager that owns the entity.
|
||||||
|
* @param entityId The camera entity ID.
|
||||||
|
* @param componentId The camera's position component ID.
|
||||||
|
* @param user Pointer to this camera's overworldcameraorbit_t state.
|
||||||
|
*/
|
||||||
|
void overworldSceneCameraOrbitUpdate(
|
||||||
|
entitymanager_t *mgr,
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user