Thanks Richard, yeah I'm a fan of the old RPGs from that era
So, after adding more dialogue content and getting a better feel for how it reads through, I've decided to discard the old school 'typed in' effect as well as the scrolling. Initially you would see 2 or 3 lines of dialogue at any given time and it would scroll up as the oldest line expired. This seemed cool at first, but ultimately just didn't prove to feel very comfortable.
I've now moved to a more standard 'sub titles' style which only displays a single line at a time and helps keep things a bit more steady as you are trying to read it.
I'll add a dialogue speed control to the options menu at some point but I would like to establish a comfortable 'normal' rate to start with.
Here is a quick look at some of the opening scene dialogue (Type 4, cutscene/scripted) that I would like to get some feedback from you all on. I've not yet set up the camera shots or much of the rest of the scene, but right now I'm focusing on the text display.
I'd like impressions on things like readability and speed of the dialogue. Is it clear who is speaking and what they are discussing? That sort of thing.
And a little bonus, here is a look at the database table which drives the scripting:
onSceneLoad actions are queried and executed at the end of the World module scene loader, the current scene and progress into that scene is isolated by the sceneName and waypoint.
You can see here that for the current scene, camera control is disabled and two of the characters (Ledelle and Roccio via their character GUIDs) are put into an acting state when the scene is loaded.
Next, when the intro letter is closed, onHideSplash is triggered which begins an ambient speech chain.
As Ledelle makes her first reply, she is also directed to move from the outside door to come over and talk to Roccio (it turns out I did need that Y float value discussed earlier, but as a facing / Y axis angle rather than as a location coordinate. When a character moves to a target x/z point, they probably will not end up facing the desired direction just by chance)
Lastly, when the last line of speech is finished, the NPCs are taken back out of acting mode and allowed to resume normal AI behaviors.
It's all pretty simple and straight forward, and the flexibility of the events and callbacks makes for a powerful system without a lot of specialized code.
For instance, the UI controller function which handles updating the ambient speech panel only needs to know that when a line of speech expires, it should query for events that trigger on the completion of speech, using the current record, and execute any callback it finds. It doesn't know or care what those callbacks are or do, and they can be pretty much anything.
(this function is in a bit of a messy state due to initially using an array for the multiple line scroll system, then being converted to only one line at a time, it needs some house keeping, but you get the idea)
function UI_controller_gameHUD_updateSpeech()
<?System_log("gameHUD.dbx", 1, "event", "Begin gameHUD_updateSpeech")?>
if array index valid(gameHUD_speechList[0]) = FALSE
exitfunction
endif
<?System_log("gameHUD.dbx", 1, "event", " > dialog in list, proceed")?>
GCcount = 0
GCindex = -1
tElementIndex = _UI_getElementById("gameHUD-speechPanel")
_UI_elements[tElementIndex].value = "" //NEWLINE
if _UI_elements[tElementIndex].style.display = "hidden"
<?System_log("gameHUD.dbx", 1, "event", " panel is hidden, set visible and transition in")?>
UI_element_setStyleProp(tElementIndex, "display", "visible")
array insert at bottom _UI_transitions[]
_UI_transitions[].elementIndex = tElementIndex
_UI_transitions[].prop = "height"
_UI_transitions[].initVal = "40px"
_UI_transitions[].targetVal = "150px"
_UI_transitions[].start = System.timing.timer
_UI_transitions[].duration = 800
_UI_transitions[].callback = ""
endif
<?System_log("gameHUD.dbx", 1, "event", " >> " + gameHUD_speechList[0].dialog)?>
tLen = fast len(gameHUD_speechList[0].dialog)
if fast left$(gameHUD_speechList[0].dialog, 1) = "*"
//emote italics
UI_element_setStyleProp(tElementIndex, "d3d-font", "6")
else
//regular
UI_element_setStyleProp(tElementIndex, "d3d-font", "1")
endif
if gameHUD_speechList[0].char < tLen
if System.timing.timer - gameHUD_speechList[0].mark > 20 //60 //TODO: user pref text speed
gameHUD_speechList[0].mark = System.timing.timer
inc gameHUD_speechList[0].char
endif
//_UI_elements[tElementIndex].value = _UI_elements[tElementIndex].value + fast left$(tDialog$, gameHUD_speechList[i].char)
_UI_elements[tElementIndex].value = _UI_elements[tElementIndex].value + gameHUD_speechList[0].dialog
else
_UI_elements[tElementIndex].value = _UI_elements[tElementIndex].value + gameHUD_speechList[0].dialog
if /*i = 0 and*/ System.timing.timer - gameHUD_speechList[i].mark > 800 + (tLen * 50)
gameHUD_speechList[0].dialog = "GC_THIS"
inc GCcount
GCindex = 0
//onSpeech complete event:
dbWorld = Sqlite_getConnection("resource/data/world.db")
qry$ = "select * from events where event = 'onSpeech" + gameHUD_speechList[0].record + "' and sceneName = '" + World.scene.sceneName + "' and waypoint = '" + str$(World.scene.waypointRecord) + "'"
<?System_log("gameHUD.dbx", 1, "event", " speech complete, check for next: " + qry$)?>
res = sqlite begin sql query(dbWorld, qry$)
while sqlite next record row(dbWorld) > 0
<?System_log("gameHUD.dbx", 1, "event", " got next speech: " + sqlite record row string by column name$(dbWorld, "args"))?>
App_callFunction(sqlite record row string by column name$(dbWorld, "callback"), sqlite record row string by column name$(dbWorld, "args"))
endwhile
res = sqlite finish sql query(dbWorld)
Sqlite_restConnection(dbWorld)
endif
endif
//next i
if GCcount > 0
if GCcount > 1
for c = 1 to GCcount
for i = 0 to array count(gameHUD_speechList[])
if gameHUD_speechList[i].dialog = "GC_THIS"
array delete element gameHUD_speechList[], i
exit
endif
next i
next c
else
array delete element gameHUD_speechList[], GCindex
endif
endif
if array index valid(gameHUD_speechList[0]) = FALSE
if _UI_elements[tElementIndex].style.display = "visible"
<?System_log("gameHUD.dbx", 1, "event", " dialog list is now empty, panel is showing. transition out and hide it")?>
_UI_elements[tElementIndex].value = ""
array insert at bottom _UI_transitions[]
_UI_transitions[].elementIndex = tElementIndex
_UI_transitions[].prop = "height"
_UI_transitions[].initVal = _UI_elements[tElementIndex].style.height //150px
_UI_transitions[].targetVal = "0px"
_UI_transitions[].start = System.timing.timer
_UI_transitions[].duration = 800
_UI_transitions[].callback = "UI_element_hide"
endif
endif
endfunction
http://games.joshkirklin.com/sulium
A single player RPG featuring a branching, player driven storyline of meaningful choices and multiple endings alongside challenging active combat and intelligent AI.