Improved cutscene system.
This commit is contained in:
@@ -15,6 +15,7 @@ target_sources(microrpg PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(cutscene)
|
||||||
add_subdirectory(entity)
|
add_subdirectory(entity)
|
||||||
add_subdirectory(scene)
|
add_subdirectory(scene)
|
||||||
add_subdirectory(platform)
|
add_subdirectory(platform)
|
||||||
|
|||||||
11
src/cutscene/CMakeLists.txt
Executable file
11
src/cutscene/CMakeLists.txt
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
# Copyright (c) 2025 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(microrpg PRIVATE
|
||||||
|
cutscene.c
|
||||||
|
cutsceneitem.c
|
||||||
|
cutscenemode.c
|
||||||
|
)
|
||||||
49
src/cutscene/cutscene.c
Normal file
49
src/cutscene/cutscene.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cutscene.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
void cutsceneInit() {
|
||||||
|
memset(&GAME.cutsceneSystem, 0, sizeof(GAME.cutsceneSystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cutsceneStart(const cutscene_t *cutscene) {
|
||||||
|
GAME.cutsceneSystem.cutscene = cutscene;
|
||||||
|
GAME.cutsceneSystem.mode = CUTSCENE_MODE_INITIAL;
|
||||||
|
GAME.cutsceneSystem.currentItem = 0xFF;// Set to 0xFF so start wraps.
|
||||||
|
cutsceneNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cutsceneTick() {
|
||||||
|
if(GAME.cutsceneSystem.cutscene == NULL) return;
|
||||||
|
|
||||||
|
const cutsceneitem_t *item = (
|
||||||
|
&GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem]
|
||||||
|
);
|
||||||
|
cutsceneItemTick(item, &GAME.cutsceneSystem.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cutsceneNext() {
|
||||||
|
if(GAME.cutsceneSystem.cutscene == NULL) return;
|
||||||
|
|
||||||
|
GAME.cutsceneSystem.currentItem++;
|
||||||
|
|
||||||
|
// End of the cutscene?
|
||||||
|
if(GAME.cutsceneSystem.currentItem >= GAME.cutsceneSystem.cutscene->itemCount) {
|
||||||
|
GAME.cutsceneSystem.cutscene = NULL;
|
||||||
|
GAME.cutsceneSystem.currentItem = 0;
|
||||||
|
GAME.cutsceneSystem.mode = CUTSCENE_MODE_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start item.
|
||||||
|
const cutsceneitem_t *item = (
|
||||||
|
&GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem]
|
||||||
|
);
|
||||||
|
cutsceneItemStart(item, &GAME.cutsceneSystem.data);
|
||||||
|
}
|
||||||
@@ -6,22 +6,41 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "microrpg.h"
|
#include "cutsceneitem.h"
|
||||||
|
#include "cutscenemode.h"
|
||||||
#define CUTSCENE_ITEM_NULL 0
|
|
||||||
#define CUTSCENE_ITEM_TEXTBOX 1
|
|
||||||
#define CUTSCENE_ITEM_CALLBACK 2
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t type;
|
const cutsceneitem_t *items;
|
||||||
|
|
||||||
union {
|
|
||||||
const char *textbox;
|
|
||||||
void (*callback)(void);// TODO: Bring entity data across.
|
|
||||||
};
|
|
||||||
} cutsceneitem_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
cutsceneitem_t *items;
|
|
||||||
uint8_t itemCount;
|
uint8_t itemCount;
|
||||||
} cutscene_t;
|
} cutscene_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const cutscene_t *cutscene;
|
||||||
|
uint8_t currentItem;
|
||||||
|
|
||||||
|
// Data (used by the current item).
|
||||||
|
cutsceneitemdata_t data;
|
||||||
|
cutscenemode_t mode;
|
||||||
|
} cutscenesystem_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the cutscene system.
|
||||||
|
*/
|
||||||
|
void cutsceneInit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a cutscene.
|
||||||
|
*
|
||||||
|
* @param cutscene Pointer to the cutscene to start.
|
||||||
|
*/
|
||||||
|
void cutsceneStart(const cutscene_t *cutscene);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance to the next item in the cutscene.
|
||||||
|
*/
|
||||||
|
void cutsceneNext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the cutscene system for one tick.
|
||||||
|
*/
|
||||||
|
void cutsceneTick();
|
||||||
11
src/cutscene/cutscenecallback.h
Normal file
11
src/cutscene/cutscenecallback.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "microrpg.h"
|
||||||
|
|
||||||
|
typedef void (*cutscenecallback_t)(void);
|
||||||
48
src/cutscene/cutsceneitem.c
Normal file
48
src/cutscene/cutsceneitem.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cutsceneitem.h"
|
||||||
|
#include "cutscene.h"
|
||||||
|
|
||||||
|
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||||
|
switch(item->type) {
|
||||||
|
case CUTSCENE_ITEM_TEXT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CUTSCENE_ITEM_WAIT:
|
||||||
|
data->wait = item->wait;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CUTSCENE_ITEM_CALLBACK:
|
||||||
|
if(item->callback != NULL) item->callback();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cutsceneItemTick(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||||
|
switch(item->type) {
|
||||||
|
case CUTSCENE_ITEM_TEXT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CUTSCENE_ITEM_CALLBACK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CUTSCENE_ITEM_WAIT:
|
||||||
|
data->wait--;
|
||||||
|
if(data->wait <= 0) {
|
||||||
|
// Wait is over, proceed to next item.
|
||||||
|
cutsceneNext();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/cutscene/cutsceneitem.h
Normal file
47
src/cutscene/cutsceneitem.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "cutscenewait.h"
|
||||||
|
#include "cutscenecallback.h"
|
||||||
|
#include "cutscenetext.h"
|
||||||
|
|
||||||
|
#define CUTSCENE_ITEM_NULL 0
|
||||||
|
#define CUTSCENE_ITEM_TEXT 1
|
||||||
|
#define CUTSCENE_ITEM_CALLBACK 2
|
||||||
|
#define CUTSCENE_ITEM_WAIT 3
|
||||||
|
|
||||||
|
typedef struct cutsceneitem_s {
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
// Arguments/Data that will be used when this item is invoked.
|
||||||
|
union {
|
||||||
|
cutscenetext_t text;
|
||||||
|
cutscenecallback_t callback;
|
||||||
|
cutscenewait_t wait;
|
||||||
|
};
|
||||||
|
} cutsceneitem_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
cutscenewaitdata_t wait;
|
||||||
|
} cutsceneitemdata_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the given cutscene item.
|
||||||
|
*
|
||||||
|
* @param item The cutscene item to start.
|
||||||
|
* @param data The cutscene item data storage.
|
||||||
|
*/
|
||||||
|
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick the given cutscene item (one frame).
|
||||||
|
*
|
||||||
|
* @param item The cutscene item to tick.
|
||||||
|
* @param data The cutscene item data storage.
|
||||||
|
*/
|
||||||
|
void cutsceneItemTick(const cutsceneitem_t *item, cutsceneitemdata_t *data);
|
||||||
20
src/cutscene/cutscenemode.c
Normal file
20
src/cutscene/cutscenemode.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cutscenemode.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
bool_t cutsceneModeIsInputAllowed() {
|
||||||
|
switch(GAME.cutsceneSystem.mode) {
|
||||||
|
case CUTSCENE_MODE_FULL_FREEZE:
|
||||||
|
case CUTSCENE_MODE_INPUT_FREEZE:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/cutscene/cutscenemode.h
Normal file
33
src/cutscene/cutscenemode.h
Normal 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 "microrpg.h"
|
||||||
|
|
||||||
|
// Mode 0, Assume no cutscene is active.
|
||||||
|
#define CUTSCENE_MODE_NONE 0
|
||||||
|
|
||||||
|
// Mode 1, assume that the cutscene is controlling all gameplay (full freeze).
|
||||||
|
#define CUTSCENE_MODE_FULL_FREEZE 1
|
||||||
|
|
||||||
|
// Mode 2, assume that the cutscene is simply stopping regular player input.
|
||||||
|
#define CUTSCENE_MODE_INPUT_FREEZE 2
|
||||||
|
|
||||||
|
// Mode 3, assume that the cutscene is not affecting gameplay directly.
|
||||||
|
#define CUTSCENE_MODE_GAMEPLAY 3
|
||||||
|
|
||||||
|
// Default mode for all cutscenes.
|
||||||
|
#define CUTSCENE_MODE_INITIAL CUTSCENE_MODE_INPUT_FREEZE
|
||||||
|
|
||||||
|
typedef uint8_t cutscenemode_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if input is allowed in the current cutscene mode.
|
||||||
|
*
|
||||||
|
* @return true if input is allowed, false otherwise.
|
||||||
|
*/
|
||||||
|
bool_t cutsceneModeIsInputAllowed();
|
||||||
11
src/cutscene/cutscenetext.h
Normal file
11
src/cutscene/cutscenetext.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "microrpg.h"
|
||||||
|
|
||||||
|
typedef const char *cutscenetext_t;
|
||||||
12
src/cutscene/cutscenewait.h
Normal file
12
src/cutscene/cutscenewait.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "microrpg.h"
|
||||||
|
|
||||||
|
typedef uint16_t cutscenewait_t;
|
||||||
|
typedef uint16_t cutscenewaitdata_t;
|
||||||
21
src/cutscene/scene/testcutscene.h
Executable file
21
src/cutscene/scene/testcutscene.h
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "cutscene/cutscene.h"
|
||||||
|
|
||||||
|
static void testCutsceneTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static const cutsceneitem_t TEST_CUTSCENE_ITEMS[] = {
|
||||||
|
{ .type = CUTSCENE_ITEM_WAIT, .wait = 1 * GAME_TIME_TICKS_PER_SECOND }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const cutscene_t TEST_CUTSCENE = {
|
||||||
|
.items = TEST_CUTSCENE_ITEMS,
|
||||||
|
.itemCount = sizeof(TEST_CUTSCENE_ITEMS) / sizeof(cutsceneitem_t)
|
||||||
|
};
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "cutscene.h"
|
|
||||||
|
|
||||||
static void testCutsceneTest() {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
cutsceneitem_t TEST_CUTSCENE_ITEMS[] = {
|
|
||||||
{ .type = CUTSCENE_ITEM_CALLBACK, .callback = testCutsceneTest }
|
|
||||||
};
|
|
||||||
@@ -31,7 +31,7 @@ void entityTick(entity_t *entity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Let entities move (if they do)
|
// Let entities move (if they do)
|
||||||
if(entity->type == ENTITY_TYPE_PLAYER) {
|
if(entity->type == ENTITY_TYPE_PLAYER && cutsceneModeIsInputAllowed()) {
|
||||||
playerTickInput(entity);
|
playerTickInput(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,6 @@
|
|||||||
#include "entity.h"
|
#include "entity.h"
|
||||||
|
|
||||||
void signInteract(entity_t *entity) {
|
void signInteract(entity_t *entity) {
|
||||||
abort();
|
if(entity->sign.cutscene == NULL) return;
|
||||||
|
cutsceneStart(entity->sign.cutscene);
|
||||||
}
|
}
|
||||||
@@ -6,12 +6,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "microrpg.h"
|
#include "cutscene/cutscene.h"
|
||||||
|
|
||||||
typedef struct entity_s entity_t;
|
typedef struct entity_s entity_t;
|
||||||
|
|
||||||
typedef struct sign_s {
|
typedef struct sign_s {
|
||||||
void *nothing;
|
const cutscene_t *cutscene;
|
||||||
} sign_t;
|
} sign_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,22 +6,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
#include "cutscene/cutscene.h"
|
||||||
|
#include "cutscene/scene/testcutscene.h"
|
||||||
|
|
||||||
game_t GAME;
|
game_t GAME;
|
||||||
|
|
||||||
void gameInit() {
|
void gameInit() {
|
||||||
memset(&GAME, 0, sizeof(GAME));
|
memset(&GAME, 0, sizeof(GAME));
|
||||||
|
|
||||||
|
cutsceneInit();
|
||||||
|
|
||||||
entityInit(&GAME.player, ENTITY_TYPE_PLAYER);
|
entityInit(&GAME.player, ENTITY_TYPE_PLAYER);
|
||||||
|
|
||||||
entityInit(&GAME.overworld.map.entities[0], ENTITY_TYPE_SIGN);
|
entityInit(&GAME.overworld.map.entities[0], ENTITY_TYPE_SIGN);
|
||||||
GAME.overworld.map.entities[0].position.x = 5;
|
GAME.overworld.map.entities[0].position.x = 5;
|
||||||
GAME.overworld.map.entities[0].position.y = 5;
|
GAME.overworld.map.entities[0].position.y = 5;
|
||||||
|
GAME.overworld.map.entities[0].sign.cutscene = &TEST_CUTSCENE;
|
||||||
|
|
||||||
GAME.scene = SCENE_OVERWORLD;
|
GAME.scene = SCENE_OVERWORLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameTick() {
|
void gameTick() {
|
||||||
gameTimeTick(&GAME.time);
|
gameTimeTick(&GAME.time);
|
||||||
|
cutsceneTick();
|
||||||
sceneTick();
|
sceneTick();
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "entity/entity.h"
|
#include "entity/entity.h"
|
||||||
#include "world/map.h"
|
#include "world/map.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
#include "cutscene/cutscene.h"
|
||||||
#include "gametime.h"
|
#include "gametime.h"
|
||||||
|
|
||||||
#define GAME_SCENE_INITIAL 0
|
#define GAME_SCENE_INITIAL 0
|
||||||
@@ -18,6 +19,7 @@ typedef struct game_s {
|
|||||||
scene_t scene;
|
scene_t scene;
|
||||||
entity_t player;
|
entity_t player;
|
||||||
gametime_t time;
|
gametime_t time;
|
||||||
|
cutscenesystem_t cutsceneSystem;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ uint8_t platformUpdate() {
|
|||||||
// Update input state.
|
// Update input state.
|
||||||
PLATFORM_RAYLIB.inputPrevious = PLATFORM_RAYLIB.inputCurrent;
|
PLATFORM_RAYLIB.inputPrevious = PLATFORM_RAYLIB.inputCurrent;
|
||||||
PLATFORM_RAYLIB.inputCurrent = 0;
|
PLATFORM_RAYLIB.inputCurrent = 0;
|
||||||
rlkeyboardmap_t *map = RL_KEYBOARD_MAP;
|
const rlkeyboardmap_t *map = RL_KEYBOARD_MAP;
|
||||||
do {
|
do {
|
||||||
if(IsKeyDown(map->raylibKey)) {
|
if(IsKeyDown(map->raylibKey)) {
|
||||||
PLATFORM_RAYLIB.inputCurrent |= map->action;
|
PLATFORM_RAYLIB.inputCurrent |= map->action;
|
||||||
|
|||||||
Reference in New Issue
Block a user