Textbox example.
This commit is contained in:
@@ -8,6 +8,7 @@ target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
rpg.c
|
||||
rpgcamera.c
|
||||
rpgtextbox.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
switch(item->type) {
|
||||
case CUTSCENE_ITEM_TYPE_TEXT: {
|
||||
strncpy(data->text.buffer, item->text, CUTSCENE_TEXT_BUFFER);
|
||||
data->text.length = strlen(data->text.buffer);
|
||||
rpgTextboxShow(
|
||||
item->text.position,
|
||||
item->text.text
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -36,6 +38,11 @@ void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
|
||||
void cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
switch(item->type) {
|
||||
case CUTSCENE_ITEM_TYPE_TEXT:
|
||||
if(rpgTextboxIsVisible()) return;
|
||||
cutsceneSystemNext();
|
||||
break;
|
||||
|
||||
case CUTSCENE_ITEM_TYPE_WAIT:
|
||||
data->wait -= TIME.fixedDelta;
|
||||
if(data->wait <= 0) cutsceneSystemNext();
|
||||
|
||||
@@ -27,12 +27,11 @@ typedef struct cutsceneitem_s {
|
||||
cutscenetext_t text;
|
||||
cutscenecallback_t callback;
|
||||
cutscenewait_t wait;
|
||||
cutscenecutscene_t cutscene;
|
||||
const cutscenecutscene_t cutscene;
|
||||
};
|
||||
} cutsceneitem_t;
|
||||
|
||||
typedef union {
|
||||
cutscenetextdata_t text;
|
||||
cutscenewaitdata_t wait;
|
||||
} cutsceneitemdata_t;
|
||||
|
||||
|
||||
@@ -6,14 +6,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/rpgtextbox.h"
|
||||
|
||||
#define CUTSCENE_TEXT_BUFFER 256
|
||||
|
||||
typedef const char_t *cutscenetext_t;
|
||||
|
||||
typedef struct cutscenetextdata_s {
|
||||
char_t buffer[CUTSCENE_TEXT_BUFFER];
|
||||
uint8_t length;
|
||||
uint8_t scroll;
|
||||
} cutscenetextdata_t;
|
||||
typedef struct {
|
||||
char_t text[RPG_TEXTBOX_MAX_CHARS];
|
||||
rpgtextboxpos_t position;
|
||||
} cutscenetext_t;
|
||||
@@ -9,9 +9,9 @@
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
|
||||
static const cutsceneitem_t TEST_CUTSCENE_ONE_ITEMS[] = {
|
||||
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = "This is a test cutscene." },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "This is a test cutscene.", .position = RPG_TEXTBOX_POS_BOTTOM } },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 2.0f },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = "It has multiple lines of text.\nAnd waits in between." },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "It has multiple lines of text.\nAnd waits in between.", .position = RPG_TEXTBOX_POS_TOP } },
|
||||
};
|
||||
|
||||
static const cutscene_t TEST_CUTSCENE_ONE = {
|
||||
@@ -21,7 +21,7 @@ static const cutscene_t TEST_CUTSCENE_ONE = {
|
||||
|
||||
static const cutsceneitem_t TEST_CUTSCENE_TWO_ITEMS[] = {
|
||||
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 1.0f },
|
||||
// { .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = &TEST_CUTSCENE_ONE },
|
||||
{ .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = &TEST_CUTSCENE_ONE },
|
||||
};
|
||||
|
||||
static const cutscene_t TEST_CUTSCENE = {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "assert/assert.h"
|
||||
|
||||
#include "rpg/cutscene/scene/testcutscene.h"
|
||||
#include "rpg/rpgtextbox.h"
|
||||
|
||||
void npcInit(entity_t *entity) {
|
||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||
@@ -23,6 +24,8 @@ bool_t npcInteract(entity_t *player, entity_t *npc) {
|
||||
assertNotNull(npc, "NPC entity pointer cannot be NULL");
|
||||
|
||||
cutsceneSystemStartCutscene(&TEST_CUTSCENE);
|
||||
|
||||
// rpgTextboxShow(RPG_TEXTBOX_POS_BOTTOM, "Hello World!");
|
||||
|
||||
return false;
|
||||
};
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "time/time.h"
|
||||
#include "rpgcamera.h"
|
||||
#include "rpgtextbox.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
errorret_t rpgInit(void) {
|
||||
@@ -22,8 +23,8 @@ errorret_t rpgInit(void) {
|
||||
// Init the world.
|
||||
worldInit();
|
||||
|
||||
// Initialize the camera
|
||||
rpgCameraInit();
|
||||
rpgTextboxInit();
|
||||
|
||||
// TEST: Create some entities.
|
||||
entity_t *ent;
|
||||
|
||||
39
src/rpg/rpgtextbox.c
Normal file
39
src/rpg/rpgtextbox.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "rpgtextbox.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
rpgtextbox_t RPG_TEXTBOX;
|
||||
|
||||
void rpgTextboxInit() {
|
||||
memoryZero(&RPG_TEXTBOX, sizeof(rpgtextbox_t));
|
||||
}
|
||||
|
||||
void rpgTextboxShow(
|
||||
const rpgtextboxpos_t position,
|
||||
const char_t *text
|
||||
) {
|
||||
RPG_TEXTBOX.position = position;
|
||||
RPG_TEXTBOX.visible = true;
|
||||
|
||||
stringCopy(
|
||||
RPG_TEXTBOX.text,
|
||||
text,
|
||||
RPG_TEXTBOX_MAX_CHARS
|
||||
);
|
||||
}
|
||||
|
||||
void rpgTextboxHide() {
|
||||
RPG_TEXTBOX.visible = false;
|
||||
}
|
||||
|
||||
bool_t rpgTextboxIsVisible() {
|
||||
return RPG_TEXTBOX.visible;
|
||||
}
|
||||
52
src/rpg/rpgtextbox.h
Normal file
52
src/rpg/rpgtextbox.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define RPG_TEXTBOX_MAX_CHARS 256
|
||||
|
||||
typedef enum {
|
||||
RPG_TEXTBOX_POS_TOP,
|
||||
RPG_TEXTBOX_POS_BOTTOM,
|
||||
} rpgtextboxpos_t;
|
||||
|
||||
typedef struct {
|
||||
rpgtextboxpos_t position;
|
||||
bool_t visible;
|
||||
char_t text[RPG_TEXTBOX_MAX_CHARS];
|
||||
} rpgtextbox_t;
|
||||
|
||||
extern rpgtextbox_t RPG_TEXTBOX;
|
||||
|
||||
/**
|
||||
* Initializes the RPG textbox.
|
||||
*/
|
||||
void rpgTextboxInit();
|
||||
|
||||
/**
|
||||
* Shows the RPG textbox at a specified position.
|
||||
*
|
||||
* @param position The position to show the textbox at.
|
||||
* @param text The text to display in the textbox (copied).
|
||||
*/
|
||||
void rpgTextboxShow(
|
||||
const rpgtextboxpos_t position,
|
||||
const char_t *text
|
||||
);
|
||||
|
||||
/**
|
||||
* Hides the RPG textbox.
|
||||
*/
|
||||
void rpgTextboxHide();
|
||||
|
||||
/**
|
||||
* Checks if the RPG textbox is currently visible.
|
||||
*
|
||||
* @return true if the textbox is visible, false otherwise.
|
||||
*/
|
||||
bool_t rpgTextboxIsVisible();
|
||||
@@ -10,4 +10,5 @@ target_sources(${DUSK_TARGET_NAME}
|
||||
uitext.c
|
||||
uifps.c
|
||||
uiframe.c
|
||||
uitextbox.c
|
||||
)
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "util/memory.h"
|
||||
#include "display/tileset/tileset_minogram.h"
|
||||
#include "display/screen.h"
|
||||
#include "ui/uitextbox.h"
|
||||
|
||||
ui_t UI;
|
||||
|
||||
@@ -31,6 +32,8 @@ void uiUpdate(void) {
|
||||
UI.camera.orthographic.right = SCREEN.width;
|
||||
UI.camera.orthographic.top = 0;
|
||||
UI.camera.orthographic.bottom = SCREEN.height;
|
||||
|
||||
uiTextboxUpdate();
|
||||
}
|
||||
|
||||
void uiRender(void) {
|
||||
@@ -39,6 +42,7 @@ void uiRender(void) {
|
||||
// Render UI elements here
|
||||
if(UI.fontTexture.width > 0) {
|
||||
uiFPSRender(UI.fontTileset, &UI.fontTexture);
|
||||
uiTextboxRender();
|
||||
}
|
||||
|
||||
cameraPopMatrix();
|
||||
|
||||
45
src/ui/uitextbox.c
Normal file
45
src/ui/uitextbox.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uitextbox.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/uitext.h"
|
||||
#include "rpg/rpgtextbox.h"
|
||||
#include "display/screen.h"
|
||||
#include "display/spritebatch.h"
|
||||
#include "input/input.h"
|
||||
|
||||
void uiTextboxUpdate() {
|
||||
if(!rpgTextboxIsVisible()) return;
|
||||
|
||||
if(inputPressed(INPUT_ACTION_ACCEPT)) {
|
||||
rpgTextboxHide();
|
||||
}
|
||||
}
|
||||
|
||||
void uiTextboxRender() {
|
||||
if(!rpgTextboxIsVisible()) return;
|
||||
|
||||
const char_t *text = RPG_TEXTBOX.text;
|
||||
int32_t textWidth, textHeight;
|
||||
|
||||
uiTextMeasure(text, UI.fontTileset, &textWidth, &textHeight);
|
||||
|
||||
float_t y = 0;
|
||||
if(RPG_TEXTBOX.position == RPG_TEXTBOX_POS_BOTTOM) {
|
||||
y = SCREEN.height - (float_t)textHeight;
|
||||
}
|
||||
|
||||
spriteBatchPush(
|
||||
NULL,
|
||||
0.0f, y,
|
||||
(float_t)SCREEN.width, (float_t)(y + textHeight),
|
||||
COLOR_BLACK,
|
||||
0.0f, 0.0f, 1.0f, 1.0f
|
||||
);
|
||||
uiTextDraw(0, y, text, COLOR_RED, UI.fontTileset, &UI.fontTexture);
|
||||
}
|
||||
19
src/ui/uitextbox.h
Normal file
19
src/ui/uitextbox.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
/**
|
||||
* Updates the RPG textbox state.
|
||||
*/
|
||||
void uiTextboxUpdate();
|
||||
|
||||
/**
|
||||
* Draws the RPG textbox if it is visible.
|
||||
*/
|
||||
void uiTextboxRender();
|
||||
Reference in New Issue
Block a user