Add follow camera

This commit is contained in:
Miloslav Ciz 2024-09-06 00:58:32 +02:00
parent 46c8a4eade
commit e3d0b3219f
4 changed files with 164 additions and 27 deletions

22
game.h
View file

@ -2,6 +2,28 @@
game: this file implements the backend of a complete, actually playable game: this file implements the backend of a complete, actually playable
game, and is meant to be included and used by specific frontends (which game, and is meant to be included and used by specific frontends (which
will handle each platform's hardware details and I/O). will handle each platform's hardware details and I/O).
TODO: more documentation
UNITS: There are various kinds of units used to ensure independence of the
game modules. Here is a summary:
- LCR_GameUnit: data type, abstract unit of the game (racing module). One map
square is LCR_GAME_UNITs long, a full angle is also LCR_GAME_UNITs.
- LCR_GAME_UNIT: Size of one game square and full angle in LCR_GameUnits.
- S3L_Unit: data type, small3dlib's unit. May change with renderer change.
- S3L_FRACTIONS_PER_UNIT: small3dlib's value representing 1.0.
- LCR_RENDERER_UNIT: for the renderer one map square is this many S3L_Units.
- TPE_Unit: tinyphysicsengine's unit. May change with phys. engine change.
- TPE_FRACTIONS_PER_UNIT: tinyphysicsengine's value representing value 1.0.
- LCR_PHYSICS_UNIT: for the phys. eng. one map square is this many TPE_Units.
COORDINATE SYSTEM AND ROTATIONS: The game itself (racing module) is
independent of rendering and physics libraries, but out of convenient adopts
their coordinate system (X right, Y up, Z forward) and rotations (Euler
angles, by Z, then by X, then Y).
*/ */
#ifndef _LCR_GAME_H #ifndef _LCR_GAME_H

View file

@ -5,29 +5,29 @@
#ifndef _LCR_RACING_H #ifndef _LCR_RACING_H
#define _LCR_RACING_H #define _LCR_RACING_H
typedef int32_t LCR_GameUnit; ///< game spatial units typedef int32_t LCR_GameUnit; ///< abstract game unit
#define LCR_GAME_UNIT 1024 ///< length of map square in game units #define LCR_GAME_UNIT 1024 ///< length of map square in LCR_GameUnits
#define LCR_RACING_INPUT_FORW 0x01 #define LCR_RACING_INPUT_FORW 0x01
#define LCR_RACING_INPUT_RIGHT 0x02 #define LCR_RACING_INPUT_RIGHT 0x02
#define LCR_RACING_INPUT_BACK 0x04 #define LCR_RACING_INPUT_BACK 0x04
#define LCR_RACING_INPUT_LEFT 0x08 #define LCR_RACING_INPUT_LEFT 0x08
#define LCR_PHYSICS_UNIT 512 ///< length of map square for physics engine #define LCR_PHYSICS_UNIT 1024 ///< length of map square for physics engine
#include "map.h" #include "map.h"
#include "tinyphysicsengine.h" #include "tinyphysicsengine.h"
#define LCR_CAR_JOINTS 5 #define LCR_CAR_JOINTS 5
#define LCR_CAR_CONNECTIONS 8 #define LCR_CAR_CONNECTIONS 10
struct struct
{ {
TPE_World physicsWorld; TPE_World physicsWorld;
TPE_Body carBody; TPE_Body carBody;
TPE_Joint carJoints[5]; TPE_Joint carJoints[LCR_CAR_JOINTS];
TPE_Connection carConnections[8]; TPE_Connection carConnections[LCR_CAR_CONNECTIONS];
} LCR_racing; } LCR_racing;
TPE_Vec3 LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist) TPE_Vec3 LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
@ -43,13 +43,13 @@ void LCR_racingInit(void)
LCR_log("initializing racing engine"); LCR_log("initializing racing engine");
// make the car body: // make the car body:
TPE_makeCenterRect(LCR_racing.carJoints, TPE_makeCenterRectFull(LCR_racing.carJoints,
LCR_racing.carConnections, LCR_racing.carConnections,
LCR_GAME_UNIT / 3, LCR_PHYSICS_UNIT / 2,
(LCR_GAME_UNIT) / 2, (LCR_PHYSICS_UNIT * 3) / 4,
LCR_GAME_UNIT / 8); LCR_PHYSICS_UNIT / 8);
LCR_racing.carJoints[4].position.y += LCR_PHYSICS_UNIT / 3; LCR_racing.carJoints[4].position.y += LCR_PHYSICS_UNIT / 8;
LCR_racing.carJoints[4].sizeDivided *= 3; LCR_racing.carJoints[4].sizeDivided *= 3;
LCR_racing.carJoints[4].sizeDivided /= 2; LCR_racing.carJoints[4].sizeDivided /= 2;
@ -60,6 +60,8 @@ void LCR_racingInit(void)
TPE_worldInit(&(LCR_racing.physicsWorld), TPE_worldInit(&(LCR_racing.physicsWorld),
&(LCR_racing.carBody),1,LCR_racingEnvironmentFunction); &(LCR_racing.carBody),1,LCR_racingEnvironmentFunction);
TPE_bodyDeactivate(&(LCR_racing.carBody));
} }
void LCR_racingGetCarTransform(LCR_GameUnit position[3], void LCR_racingGetCarTransform(LCR_GameUnit position[3],
@ -77,6 +79,12 @@ void LCR_racingGetCarTransform(LCR_GameUnit position[3],
position[1] = AVERAGE(y); position[1] = AVERAGE(y);
position[2] = AVERAGE(z); position[2] = AVERAGE(z);
#undef AVERAGE #undef AVERAGE
TPE_Vec3 rot = TPE_bodyGetRotation(&(LCR_racing.carBody),0,2,1);
rotation[0] = (rot.x * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT;
rotation[1] = (rot.y * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT;
rotation[2] = (rot.z * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT;
} }
void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color) void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color)
@ -100,20 +108,24 @@ void LCR_racingStep(unsigned int input)
if (input) if (input)
{ {
if (input & LCR_RACING_INPUT_FORW) if (input & LCR_RACING_INPUT_FORW)
vel.z = LCR_GAME_UNIT / 32; vel.z = LCR_PHYSICS_UNIT / 32;
if (input & LCR_RACING_INPUT_BACK) if (input & LCR_RACING_INPUT_BACK)
vel.y = LCR_GAME_UNIT / 32; vel.y = LCR_PHYSICS_UNIT / 32;
if (input & LCR_RACING_INPUT_RIGHT) if (input & LCR_RACING_INPUT_RIGHT)
vel.x = LCR_GAME_UNIT / 32; vel.x = LCR_PHYSICS_UNIT / 32;
if (input & LCR_RACING_INPUT_LEFT) if (input & LCR_RACING_INPUT_LEFT)
vel.x = -1 * LCR_GAME_UNIT / 32; vel.x = -1 * LCR_PHYSICS_UNIT / 32;
TPE_bodyAccelerate(&(LCR_racing.carBody),vel); TPE_bodyAccelerate(&(LCR_racing.carBody),vel);
} }
TPE_bodyApplyGravity(&(LCR_racing.carBody),
TPE_FRACTIONS_PER_UNIT / 32
);
TPE_worldStep(&(LCR_racing.physicsWorld)); TPE_worldStep(&(LCR_racing.physicsWorld));
} }

View file

@ -31,6 +31,8 @@
#define LCR_RENDERER_MODEL_COUNT 9 #define LCR_RENDERER_MODEL_COUNT 9
#define LCR_RENDERER_CAR_SCALE (LCR_RENDERER_UNIT / 4)
struct struct
{ {
S3L_Scene scene; S3L_Scene scene;
@ -91,6 +93,13 @@ void LCR_rendererSetCarTransform(LCR_GameUnit position[3],
(position[1] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT; (position[1] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT;
LCR_renderer.carModel->transform.translation.z = LCR_renderer.carModel->transform.translation.z =
(position[2] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT; (position[2] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT;
LCR_renderer.carModel->transform.rotation.x = S3L_wrap((rotation[0] *
S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT,S3L_FRACTIONS_PER_UNIT);
LCR_renderer.carModel->transform.rotation.y = S3L_wrap((rotation[1] *
S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT,S3L_FRACTIONS_PER_UNIT);
LCR_renderer.carModel->transform.rotation.z = S3L_wrap((rotation[2] *
S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT,S3L_FRACTIONS_PER_UNIT);
} }
void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel) void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel)
@ -790,15 +799,9 @@ uint8_t LCR_rendererInit(void)
LCR_renderer.wheelTurn = 0; LCR_renderer.wheelTurn = 0;
#endif #endif
LCR_renderer.carModel->transform.translation.x -= 2 * LCR_RENDERER_UNIT; LCR_renderer.carModel->transform.scale.x = LCR_RENDERER_CAR_SCALE;
LCR_renderer.carModel->transform.scale.x = LCR_RENDERER_UNIT / 3; LCR_renderer.carModel->transform.scale.y = LCR_RENDERER_CAR_SCALE;
LCR_renderer.carModel->transform.scale.z = LCR_RENDERER_CAR_SCALE;
LCR_renderer.carModel->transform.scale.y =
LCR_renderer.carModel->transform.scale.x;
LCR_renderer.carModel->transform.scale.z =
LCR_renderer.carModel->transform.scale.x;
S3L_sceneInit( S3L_sceneInit(
LCR_renderer.models,LCR_RENDERER_MODEL_COUNT,&LCR_renderer.scene); LCR_renderer.models,LCR_RENDERER_MODEL_COUNT,&LCR_renderer.scene);
@ -1291,6 +1294,88 @@ void _LCR_rendererAnimateCar(void)
} }
#endif #endif
void LCR_rendererCameraFollow(void)
{
/*
LCR_renderer.scene.camera.transform.translation.y =
LCR_renderer.carModel->transform.translation.y + LCR_RENDERER_UNIT;
*/
/*
TPE_Vec3 cPos = TPE_vec3KeepWithinDistanceBand(
TPE_vec3(
s3l_scene.camera.transform.translation.x,
s3l_scene.camera.transform.translation.y,
s3l_scene.camera.transform.translation.z
),carBody->joints[4].position,4 * TPE_F,6 * TPE_F);
s3l_scene.camera.transform.translation.x = cPos.x;
s3l_scene.camera.transform.translation.y = cPos.y;
s3l_scene.camera.transform.translation.z = cPos.z;
*/
/*
S3L_Unit tmp =
LCR_renderer.scene.camera.transform.translation.y -
LCR_renderer.carModel->transform.translation.y;
tmp -= S3L_clamp(tmp,
(LCR_SETTING_CAMERA_HEIGHT -
LCR_SETTING_CAMERA_HEIGHT_BAND) * LCR_GAME_UNIT / 8,
(LCR_SETTING_CAMERA_HEIGHT +
LCR_SETTING_CAMERA_HEIGHT_BAND) * LCR_GAME_UNIT / 8);
LCR_renderer.scene.camera.transform.translation.y -= tmp;
*/
LCR_renderer.scene.camera.transform.translation.y =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.y,
LCR_renderer.carModel->transform.translation.y +
(LCR_SETTING_CAMERA_HEIGHT - LCR_SETTING_CAMERA_HEIGHT_BAND) *
LCR_GAME_UNIT / 8,
LCR_renderer.carModel->transform.translation.y +
(LCR_SETTING_CAMERA_HEIGHT + LCR_SETTING_CAMERA_HEIGHT_BAND) *
LCR_GAME_UNIT / 8);
LCR_renderer.scene.camera.transform.translation.x =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.x,
LCR_renderer.carModel->transform.translation.x -
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4,
LCR_renderer.carModel->transform.translation.x +
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4);
LCR_renderer.scene.camera.transform.translation.z =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.z,
LCR_renderer.carModel->transform.translation.z -
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4,
LCR_renderer.carModel->transform.translation.z +
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4);
S3L_lookAt(LCR_renderer.carModel->transform.translation,
&(LCR_renderer.scene.camera.transform));
/*
TPE_Unit angleDiff = s3l_scene.camera.transform.rotation.y -
(TPE_vec2Angle(toCar.x,toCar.z) - 128);
s3l_scene.camera.transform.rotation.y -=
(angleDiff < 100 && angleDiff > -100) ? angleDiff / 2 : angleDiff;
*/
}
void LCR_rendererDraw(void) void LCR_rendererDraw(void)
{ {
LCR_renderer.previousTriID = -1; LCR_renderer.previousTriID = -1;
@ -1309,6 +1394,8 @@ LCR_renderer.wheelTurn = S3L_sin(LCR_renderer.frame * 4);
_LCR_rendererAnimateCar(); _LCR_rendererAnimateCar();
#endif #endif
LCR_rendererCameraFollow();
LCR_drawLevelFloor(); LCR_drawLevelFloor();
LCR_rendererDrawLOD(); LCR_rendererDrawLOD();

View file

@ -94,10 +94,26 @@
#ifndef LCR_SETTING_CAR_ANIMATION_SUBDIVIDE #ifndef LCR_SETTING_CAR_ANIMATION_SUBDIVIDE
/** How many frames will be used to complete whole animation of the car model. /** How many frames will be used to complete whole animation of the car model.
0 turns off car animation completely (may be faster and smaller), 1 turns 0 turns off car animation completely (may be faster and smaller), 1 turns on
on highest quality animation, higher values lower animation quality and highest quality animation, higher values lower animation quality and may
may increase performance. */ increase performance. */
#define LCR_SETTING_CAR_ANIMATION_SUBDIVIDE 4 #define LCR_SETTING_CAR_ANIMATION_SUBDIVIDE 4
#endif #endif
#ifndef LCR_SETTING_CAMERA_HEIGHT
/** Base height of the car follow camera, in 4ths of map block height. */
#define LCR_SETTING_CAMERA_HEIGHT 2
#endif
#ifndef LCR_SETTING_CAMERA_HEIGHT_BAND
/** Size of height band of the follow camera, in same units as base height. */
#define LCR_SETTING_CAMERA_HEIGHT_BAND 1
#endif
#ifndef LCR_SETTING_CAMERA_MAX_DISTANCE
/** Maximum horizontal distance of the car follow camera, in 4ths of map block
width. */
#define LCR_SETTING_CAMERA_MAX_DISTANCE 2
#endif
#endif // guard #endif // guard