A Full-Screen Slide in Mid-Game: Difference between revisions
→An Actual Example: Renamed, improved |
m Change category tag to {{GUI}}, that includes Editing |
||
(14 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
Suppose you want to briefly show some text on-screen, but the existing TDM message gui’s don’t quite do what you want. Here’s how you can easily modify them. | Suppose you want to briefly show some text on-screen, but the existing TDM message gui’s don’t quite do what you want. Here’s how you can easily modify them. | ||
Start by creating an atdm:gui_message entity in your map. Then, in the Entity Inspector, alter these 2 lines: | Start by creating an atdm:gui_message entity in your map. Then, in the Entity Inspector, rename it to atdm_gui_message_slide, and alter these 2 lines to: | ||
gui guis/my_slide.gui | gui guis/my_slide.gui | ||
show <number of seconds you want slide to appear> | show <number of seconds you want slide to appear> | ||
Unlike the unaltered case, for what we're doing here, the values of this entity's spawnargs "lines" and "text" will be ignored. Also, the slide will disappear abruptly at "show" time, not fade out. | Unlike the unaltered case, for what we're doing here, the values of this entity's spawnargs "lines" and "text" will be ignored. Also, the slide will disappear abruptly at "show" time, not fade out. | ||
Arrange for your player to trigger this entity. Finally, we will customize my_slide.gui. In particular, we will make it possible for the user to terminate the slide early, by clicking the LMB on it. The text we will display will be hardcoded into the .gui, not passed as a spawnarg or (as would be the case with | Arrange for your player to trigger this entity. Finally, we will create and customize my_slide.gui. In particular, we will make it possible for the user to terminate the slide early, by clicking the LMB on it. The text we will display will be hardcoded into the .gui, not passed as a spawnarg or (as would be the case with readables) retrieved from an .xd file. | ||
The Doom GUI language is not a thing of beauty. Some places require semi-colons at line ends; some places forbid them. Sometimes you need quotes; sometimes not. Persevere. | |||
==Case 1 – Transparent Background, White Letters== | ==Case 1 – Transparent Background, White Letters== | ||
In your FM’s “guis” folder, create my_slide.gui with content: | In your FM’s “guis” folder, create my_slide.gui with content: | ||
Line 16: | Line 19: | ||
rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner. | rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner. | ||
onAction { | onAction { | ||
set "MySlide::visible" "0"; | |||
} | } | ||
windowDef Text1 { | windowDef Text1 { | ||
Line 29: | Line 32: | ||
The text will be word-wrapped and left-justified. You can add "textalign 1" to center it (Sometimes with "textalign 1", the first line stays left-justified; ugh. If so, stick in some leading spaces). | The text will be word-wrapped and left-justified. You can add "textalign 1" to center it (Sometimes with "textalign 1", the first line stays left-justified; ugh. If so, stick in some leading spaces). | ||
This is not very different than the standard atdm:gui_message treatment with the "...no_art" gui. However, if you want to have titles and paragraphs with different fonts, sizes, locations, or margins, you can just add additional windowDefs. Another usage would be to tweak the margins to provide a subtitle, instead of full-screen text. | This is not very different than the standard atdm:gui_message treatment with the "...no_art" gui. However, if you want to have titles and paragraphs with different fonts, sizes, locations, or margins, you can just add additional windowDefs. More about that below. Another usage would be to tweak the margins to provide a subtitle, instead of full-screen text. | ||
==Case 2 – Opaque Black Background, White Letters== | ==Case 2 – Opaque Black Background, White Letters== | ||
Here, we have a slide in the style of old-time silent movie captions. | Here, we have a slide in the style of old-time silent movie captions. | ||
Line 48: | Line 52: | ||
{ | { | ||
sys.trigger($atdm_gui_message_slide); // show the slide | sys.trigger($atdm_gui_message_slide); // show the slide | ||
// Optionally add code here to move player to blue room. | |||
// We’ll need to get the gui’s overlay handle, from the attached default scriptobject, which is “tdm_gui_message”. | |||
// By casting, we get access to it here. | |||
tdm_gui_message e = $atdm_gui_message_slide; | tdm_gui_message e = $atdm_gui_message_slide; | ||
// Can take a while for the overlay handle to be created and for e.gui to be non-zero. | // Can take a while for the overlay handle to be created and for e.gui to be non-zero. | ||
Line 83: | Line 87: | ||
set "MySlide::visible" "0"; | set "MySlide::visible" "0"; | ||
set "gui::MySlideDone" "1"; | set "gui::MySlideDone" "1"; | ||
} | |||
windowDef Text1 { | |||
rect 10, 10, 620, 460 // x, y (relative to parent origin), w, h | |||
text " ...same text as Case 1... " | |||
forecolor 1, 1, 1, 1 // Black opaque font | |||
textscale 1 | |||
font "fonts/popsies" | |||
} | |||
} | } | ||
===Variants=== | ===Variants=== | ||
Line 96: | Line 100: | ||
As an alternative, you could just burn the text into the background image. But translators will be unhappy unless you also provide them with the corresponding text-free image. | As an alternative, you could just burn the text into the background image. But translators will be unhappy unless you also provide them with the corresponding text-free image. | ||
==Case 4 – Two-Level Image Background, Black Letters== | ==Case 4 – Two-Level Image Background, Black Letters== | ||
There are a number of pre-existing TDM "parchment" and "scroll" backgrounds that have wide transparent perimeters. You | There are a number of pre-existing TDM "parchment" and "scroll" backgrounds that have wide transparent perimeters. You could substitute one of these directly, in the style of Case 3, so you see the game world around the edges. Instead, we use "backcolor" to set an opaque black background (as in Case 2), and define the scroll atop it within a child windowDef: | ||
windowDef MySlide | windowDef MySlide | ||
Line 121: | Line 126: | ||
[[File:Away0 if skip first cutscene.jpg|thumb|center|A more-complex example of an actual slide. Click to expand.]] | [[File:Away0 if skip first cutscene.jpg|thumb|center|A more-complex example of an actual slide. Click to expand.]] | ||
The "Continue" text provides a mental target for the cursor, but the gamer can really click anywhere. The custom .gui in this case uses multiple windowDefs with | The "Continue" text provides a mental target for the cursor, but the gamer can really click anywhere. The custom .gui in this case uses multiple windowDefs with different margins, font colors, and font sizes to position text blocks atop the scroll. | ||
windowDef CutSceneReplacementSlide | windowDef CutSceneReplacementSlide | ||
Line 138: | Line 143: | ||
} | } | ||
windowDef Text1 { | windowDef Text1 { | ||
rect 10, 30, 620, 460 // x, y, w, h. Margins enlarged to keep text on opaque portion of Scroll1 | rect 10, 30, 620, 460 // x, y, w, h. Margins enlarged to keep text on opaque upper portion of Scroll1 | ||
text "What Emily Will Say in Her Diary" | text "What Emily Will Say in Her Diary" | ||
forecolor 1, 1, 1, 1 // White opaque font | forecolor 1, 1, 1, 1 // White opaque font | ||
Line 146: | Line 151: | ||
} | } | ||
windowDef Text2 { | windowDef Text2 { | ||
rect 100, 70, 440, 250 // x, y, w, h. Margins enlarged to keep text on opaque portion of Scroll1 | rect 100, 70, 440, 250 // x, y, w, h. Margins enlarged to keep text on opaque middle portion of Scroll1 | ||
text "I startled from my prayers. There he was in my room, & he brought what we need! I snatched the key from him & flung open the long-locked door, the night air so sweet. My passion arose, and he responded ." | text "I startled from my prayers. There he was in my room, & he brought what we need! I snatched the key from him & flung open the long-locked door, the night air so sweet. My passion arose, and he responded ." | ||
forecolor 0, 0, 0, 1 // Black opaque font | forecolor 0, 0, 0, 1 // Black opaque font | ||
Line 153: | Line 158: | ||
} | } | ||
windowDef Text3 { | windowDef Text3 { | ||
rect 100, 280, 440, 250 // x, y, w, h. Margins enlarged to keep text on opaque portion of Scroll1 | rect 100, 280, 440, 250 // x, y, w, h. Margins enlarged to keep text on opaque middle portion of Scroll1 | ||
text "But horrors! I heard Bleda's gait, his footsteps approach. He would kill us! I bolted out the door, shouting ' Follow Me'!" | text "But horrors! I heard Bleda's gait, his footsteps approach. He would kill us! I bolted out the door, shouting ' Follow Me'!" | ||
forecolor 0, 0, 0, 1 // Black opaque font | forecolor 0, 0, 0, 1 // Black opaque font | ||
Line 160: | Line 165: | ||
} | } | ||
windowDef Text4 { | windowDef Text4 { | ||
rect 10, 420, 590, 40 // x, y, w, h. Margins enlarged to keep text on opaque portion of Scroll1 | rect 10, 420, 590, 40 // x, y, w, h. Margins enlarged to keep text on opaque lower portion of Scroll1 | ||
text "Continue" | text "Continue" | ||
forecolor 1, 1, 1, 1 // White opaque font | forecolor 1, 1, 1, 1 // White opaque font | ||
textscale 0.5 | textscale 0.5 | ||
textalign 1 | textalign 1 // Centered | ||
font "fonts/carleton" | font "fonts/carleton" | ||
} | } | ||
} | } | ||
The corresponding script function (in emily_related.script) is far more complicated than what was discussed earlier, because it handles | The corresponding script function (in emily_related.script) is far more complicated than what was discussed earlier, because it handles the video, sound, and additional FM-specific chores for story continuity. | ||
==For More== | ==For More== | ||
The information here draws on 2004-vintage GUI tutorials by Doom creator John | The information here draws on 2004-vintage GUI tutorials by Doom creator John Carmack, but adapted to TDM and the context here. | ||
[[Mission Title Screen while Loading]] has more about the Doom3 GUI layout language with further examples. | |||
You should use a text editor for GUI files. The vintage built-in GUI editor (console command "editGUIs") has become unusable. | |||
[[Full-Screen Video Cutscenes]] has more about deploying "skippable" video cutscenes. | |||
{{GUI|sort=Full-Screen Slide}} | |||
[[Category:Video and cutscenes]] | |||
[[Category:Scripting]] | |||
[[Category:Fonts]] |
Latest revision as of 18:06, 4 November 2022
by Geep, 2021
Overview
Suppose you want to briefly show some text on-screen, but the existing TDM message gui’s don’t quite do what you want. Here’s how you can easily modify them.
Start by creating an atdm:gui_message entity in your map. Then, in the Entity Inspector, rename it to atdm_gui_message_slide, and alter these 2 lines to:
gui guis/my_slide.gui show <number of seconds you want slide to appear>
Unlike the unaltered case, for what we're doing here, the values of this entity's spawnargs "lines" and "text" will be ignored. Also, the slide will disappear abruptly at "show" time, not fade out.
Arrange for your player to trigger this entity. Finally, we will create and customize my_slide.gui. In particular, we will make it possible for the user to terminate the slide early, by clicking the LMB on it. The text we will display will be hardcoded into the .gui, not passed as a spawnarg or (as would be the case with readables) retrieved from an .xd file.
The Doom GUI language is not a thing of beauty. Some places require semi-colons at line ends; some places forbid them. Sometimes you need quotes; sometimes not. Persevere.
Case 1 – Transparent Background, White Letters
In your FM’s “guis” folder, create my_slide.gui with content:
windowDef MySlide { visible 1 rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner. onAction { set "MySlide::visible" "0"; } windowDef Text1 { rect 10, 10, 620, 460 // x, y (relative to parent origin), w, h. Adjust to control margins. text "Let's try word wrapping. This box is within screen bounds. Sometimes, with word wrapping, you can use a box that slightly exceeds screen width." textscale 1 font "fonts/popsies" } }
Almost always, you use “rect 0,0,640,480” in the parent windowDef to establish a logical coordinate system stretched over the screen dimensions. By default, a TDM menu cursor will appear, to remind the user that they can exit early by clicking... really anywhere. You can suppress this cursor with "nocursor 1". Choose the font from the standard TDM ones (e.g., carleton is used for briefings). Adjust the font size with float "textscale", but 1 or less is best.
The text will be word-wrapped and left-justified. You can add "textalign 1" to center it (Sometimes with "textalign 1", the first line stays left-justified; ugh. If so, stick in some leading spaces).
This is not very different than the standard atdm:gui_message treatment with the "...no_art" gui. However, if you want to have titles and paragraphs with different fonts, sizes, locations, or margins, you can just add additional windowDefs. More about that below. Another usage would be to tweak the margins to provide a subtitle, instead of full-screen text.
Case 2 – Opaque Black Background, White Letters
Here, we have a slide in the style of old-time silent movie captions.
windowDef MySlide { visible 1 rect 0,0,640,480 backcolor 0, 0, 0, 1 // Black background onAction { set "MySlide::visible" "0"; set "gui::MySlideDone" "1"; } windowDef Text1 { ... same as previous example ... } }
With an opaque full-screen background, it's often necessary for the rest of the game to know when the slide is done, particularly if it’s up more than a few seconds. So onAction sets a variable, that can then be polled for in a script, shown next.
Sample Script Code to Put Up a Slide then Wait
void full_screen_slide() { sys.trigger($atdm_gui_message_slide); // show the slide // Optionally add code here to move player to blue room. // We’ll need to get the gui’s overlay handle, from the attached default scriptobject, which is “tdm_gui_message”. // By casting, we get access to it here. tdm_gui_message e = $atdm_gui_message_slide; // Can take a while for the overlay handle to be created and for e.gui to be non-zero. // If spawnarg "delay" is zero, the default, a 0.1 second delay is imposed. float handlenum = 0; while(handlenum == 0) { handlenum = e.gui; sys.wait(0.1); } float maxtime = $atdm_gui_message_slide.getFloatKey("show"); float slide_done == 0; while(maxtime > 0) { slide_done = $player1.getGuiFloat(handlenum, "MySlideDone"); if(slide_done == 1) // user did gui's onAction, with LMB break; maxtime -= 0.1; sys.wait(0.1); } // Optionally add code here to move player from blue room. $player1.setGuiFloat(handlenum, "MySlideDone", 0); // reset just in case }
Case 3 – Opaque Image Background, Black Letters
windowDef MySlide { visible 1 rect 0,0,640,480 background "models/darkmod/props/textures/parchment_freshpaper" onAction { set "MySlide::visible" "0"; set "gui::MySlideDone" "1"; } windowDef Text1 { rect 10, 10, 620, 460 // x, y (relative to parent origin), w, h text " ...same text as Case 1... " forecolor 1, 1, 1, 1 // Black opaque font textscale 1 font "fonts/popsies" } }
Variants
We’re using a stock TDM background here, but you can have your FM include a custom .jpg, .tga, or .dds image as background. As is usual with TDM, "background" assumes the filepath from the FM’s root, and does not want the file extension to be stated here.
As an alternative, you could just burn the text into the background image. But translators will be unhappy unless you also provide them with the corresponding text-free image.
Case 4 – Two-Level Image Background, Black Letters
There are a number of pre-existing TDM "parchment" and "scroll" backgrounds that have wide transparent perimeters. You could substitute one of these directly, in the style of Case 3, so you see the game world around the edges. Instead, we use "backcolor" to set an opaque black background (as in Case 2), and define the scroll atop it within a child windowDef:
windowDef MySlide { visible 1 rect 0,0,640,480 backcolor 0, 0, 0, 1 // Black background onAction { set "MySlide::visible" "0"; set "gui::MySlideDone" "1"; } windowDef Scroll1{ visible 1 rect 0,0,640,480 // x, y, w, h. This can be bigger than the parent if you want to reduce transparent perimeter background "guis/assets/readables/scroll" } windowDef Text1 { ... same as previous example ... } }
An Actual Example
An outgrown of Case 4 can be found in FM "Away 0: Stolen Heart". There comes a point where the player can ask to skip an upcoming video cutscene, typically because they've already seen it. In that case, when the player gets to where the video cutscene would play, a plausible full-screen slide is shown instead. Information on the slide summarizes, in re-imagined form, what the cutscene would show.
The "Continue" text provides a mental target for the cursor, but the gamer can really click anywhere. The custom .gui in this case uses multiple windowDefs with different margins, font colors, and font sizes to position text blocks atop the scroll.
windowDef CutSceneReplacementSlide { visible 1 rect 0,0,640,480 // x, y, w, h. Origin upper-left backcolor 0, 0, 0, 1 onAction { set "CutSceneReplacementSlide::visible" "0"; set "gui::FirstCutsceneReplacementSlideDone" "1"; } windowDef Scroll1 { visible 1 rect 0,0,640,480 // x, y, w, h. This can be bigger than the parent if you want to reduce transparent perimeter background "guis/assets/readables/scroll" } windowDef Text1 { rect 10, 30, 620, 460 // x, y, w, h. Margins enlarged to keep text on opaque upper portion of Scroll1 text "What Emily Will Say in Her Diary" forecolor 1, 1, 1, 1 // White opaque font textscale 0.5 textalign 1 // Centered font "fonts/carleton" } windowDef Text2 { rect 100, 70, 440, 250 // x, y, w, h. Margins enlarged to keep text on opaque middle portion of Scroll1 text "I startled from my prayers. There he was in my room, & he brought what we need! I snatched the key from him & flung open the long-locked door, the night air so sweet. My passion arose, and he responded ." forecolor 0, 0, 0, 1 // Black opaque font textscale 0.4 font "fonts/popsies" } windowDef Text3 { rect 100, 280, 440, 250 // x, y, w, h. Margins enlarged to keep text on opaque middle portion of Scroll1 text "But horrors! I heard Bleda's gait, his footsteps approach. He would kill us! I bolted out the door, shouting ' Follow Me'!" forecolor 0, 0, 0, 1 // Black opaque font textscale 0.4 font "fonts/popsies" } windowDef Text4 { rect 10, 420, 590, 40 // x, y, w, h. Margins enlarged to keep text on opaque lower portion of Scroll1 text "Continue" forecolor 1, 1, 1, 1 // White opaque font textscale 0.5 textalign 1 // Centered font "fonts/carleton" } }
The corresponding script function (in emily_related.script) is far more complicated than what was discussed earlier, because it handles the video, sound, and additional FM-specific chores for story continuity.
For More
The information here draws on 2004-vintage GUI tutorials by Doom creator John Carmack, but adapted to TDM and the context here.
Mission Title Screen while Loading has more about the Doom3 GUI layout language with further examples.
You should use a text editor for GUI files. The vintage built-in GUI editor (console command "editGUIs") has become unusable.
Full-Screen Video Cutscenes has more about deploying "skippable" video cutscenes.