{"id":941,"date":"2025-05-05T18:47:00","date_gmt":"2025-05-05T22:47:00","guid":{"rendered":"https:\/\/willkolb.com\/?p=941"},"modified":"2025-05-05T18:47:00","modified_gmt":"2025-05-05T22:47:00","slug":"terminal-time","status":"publish","type":"post","link":"https:\/\/willkolb.com\/?p=941","title":{"rendered":"Terminal Time"},"content":{"rendered":"\n<p>A while back I made a terminal model that looked meh but was designed to serve as a stand in for some kind of computer interaction:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"702\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-1024x702.png\" alt=\"\" class=\"wp-image-942\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-1024x702.png 1024w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-300x206.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-768x526.png 768w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-438x300.png 438w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image.png 1264w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>I started out wanted to make a command line interface, but then I changed my mind and wanted a Doom 3 style interface: <\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-imgur wp-block-embed-imgur\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"imgur-embed-pub\" lang=\"en\" data-id=\"xBvIpiQ\"><a href=\"https:\/\/imgur.com\/xBvIpiQ\">View post on imgur.com<\/a><\/blockquote><script async src=\"\/\/s.imgur.com\/min\/embed.js\" charset=\"utf-8\"><\/script>\n<\/div><figcaption class=\"wp-element-caption\">Example was pulled from here: <a href=\"https:\/\/www.reddit.com\/r\/Unity3D\/comments\/4nkvj9\/ingame_gui_like_doom_3\/\">https:\/\/www.reddit.com\/r\/Unity3D\/comments\/4nkvj9\/ingame_gui_like_doom_3\/<\/a> <\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up the actors<\/h2>\n\n\n\n<p>To accomplish this I found that unreal has a whole system for defining this procedure called a &#8220;widget interaction component&#8221; (see <a href=\"https:\/\/dev.epicgames.com\/documentation\/en-us\/unreal-engine\/umg-widget-interaction-components-in-unreal-engine\">https:\/\/dev.epicgames.com\/documentation\/en-us\/unreal-engine\/umg-widget-interaction-components-in-unreal-engine<\/a>) which is great! However if you&#8217;re not only trying to push buttons its a real pain to get everything setup to map properly. <\/p>\n\n\n\n<p>The component works by doing a ray trace every frame so many meters in front of you, if that trace hits a widget component (the container class for UI components, see: <a href=\"https:\/\/dev.epicgames.com\/documentation\/en-us\/unreal-engine\/building-your-ui-in-unreal-engine\">https:\/\/dev.epicgames.com\/documentation\/en-us\/unreal-engine\/building-your-ui-in-unreal-engine<\/a>)  then the widget component will receive events as if the widget component was the 2d UI that is used for basic UI development. In other-words: Unreal makes a virtual screen, then I add the &#8220;virtual screen user&#8221; component to the player character and then it should be the same UI development process I would use for menus, huds etc.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"486\" height=\"269\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-1.png\" alt=\"\" class=\"wp-image-943\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-1.png 486w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-1-300x166.png 300w\" sizes=\"auto, (max-width: 486px) 100vw, 486px\" \/><figcaption class=\"wp-element-caption\">the &#8220;virtual screen user class&#8221;<\/figcaption><\/figure>\n\n\n\n<p>To show the UI in game I made a quick actor that held my terminal and my UI widget<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"543\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-2-1024x543.png\" alt=\"\" class=\"wp-image-944\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-2-1024x543.png 1024w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-2-300x159.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-2-768x407.png 768w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-2-500x265.png 500w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-2.png 1358w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>My initial UI widget is just a white box cursor and a translucent green background<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"588\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-3-1024x588.png\" alt=\"\" class=\"wp-image-945\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-3-1024x588.png 1024w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-3-300x172.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-3-768x441.png 768w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-3-500x287.png 500w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-3.png 1393w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>So ideally I would just use my Widget Interaction UI and do 100% of the development on the widget side. HOWEVER, I found out there isn&#8217;t a good &#8220;get What the Widget thinks the cursor position is&#8221; within the widget (The widget that holds the UI design also has its own execution path if you didn&#8217;t know that). But the issue came from that the only way to get the cursor position was the ACTUAL cursor position, which wont work here because it will always be centered on the screen during gameplay.<\/p>\n\n\n\n<p>Sooooo, to fix this I had to make a &#8220;Set cursor position&#8221; public function that can update the location of the white square:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"985\" height=\"481\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-4.png\" alt=\"\" class=\"wp-image-946\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-4.png 985w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-4-300x146.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-4-768x375.png 768w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-4-500x244.png 500w\" sizes=\"auto, (max-width: 985px) 100vw, 985px\" \/><\/figure>\n\n\n\n<p>Then I had to add yet ANOTHER tick function to my main character to handle terminals:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"550\" height=\"256\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-5.png\" alt=\"\" class=\"wp-image-947\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-5.png 550w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-5-300x140.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-5-500x233.png 500w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/figure>\n\n\n\n<p>So here&#8217;s the order of events:<\/p>\n\n\n\n<p>1.) The widget interaction component detects its hitting a widget in the world here:<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"656\" height=\"246\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-7.png\" alt=\"\" class=\"wp-image-949\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-7.png 656w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-7-300x113.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-7-500x188.png 500w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/figure>\n\n\n\n<p>I then grab that widget and hold it in memory<\/p>\n\n\n\n<p>2.) The tick function executes on the next tick<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"725\" height=\"298\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-6.png\" alt=\"\" class=\"wp-image-948\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-6.png 725w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-6-300x123.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-6-500x206.png 500w\" sizes=\"auto, (max-width: 725px) 100vw, 725px\" \/><\/figure>\n\n\n\n<p>Which sets the position of the white square.<\/p>\n\n\n\n<p>The result:<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video height=\"596\" style=\"aspect-ratio: 1060 \/ 596;\" width=\"1060\" controls src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/20250505-1458-08.6857908.mp4\"><\/video><\/figure>\n\n\n\n<p>Seems decent enough, I just gotta mess with the sizing a bit more and disable debug to start really working at it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Making a simple UI<\/h2>\n\n\n\n<p>To make a quick cursor (if you ever need this information)<\/p>\n\n\n\n<p>1.) Select all<\/p>\n\n\n\n<p>2.) Scale down to 1\/4 of the screen<\/p>\n\n\n\n<p>3) Fill black<\/p>\n\n\n\n<p>4.) Rotate your selection 45 degrees<\/p>\n\n\n\n<p>5.) Remove the corner<\/p>\n\n\n\n<p>6.) undo that because that would never work<\/p>\n\n\n\n<p>7.) Invert your selection and fill white<\/p>\n\n\n\n<p>8.) Undo that because that makes no sense<\/p>\n\n\n\n<p>9.) Select all<\/p>\n\n\n\n<p>10.) Shrink by 50<\/p>\n\n\n\n<p>11.) Rotate your selection 45<\/p>\n\n\n\n<p>12.) Undo that and select all again<\/p>\n\n\n\n<p>13.) Shrink by 25<\/p>\n\n\n\n<p>14.) Rotate by 45<\/p>\n\n\n\n<p>15.) Erase everything in your selection<\/p>\n\n\n\n<p>16.) Select all<\/p>\n\n\n\n<p>17.) Shrink by 50<\/p>\n\n\n\n<p>18.) Scale horizontal by 50, increase vertical to 125<\/p>\n\n\n\n<p>19.) Rotate by 45<\/p>\n\n\n\n<p>20.) Undo and rotate by -45<\/p>\n\n\n\n<p>21.) Be sad that you didn&#8217;t scale large enough on step 18<\/p>\n\n\n\n<p>22.) Undo the last 4 steps and increase vertical size to 150<\/p>\n\n\n\n<p>23.) Do steps 19-22 again and resize to 175<\/p>\n\n\n\n<p>24.) Select all black, and realize you have weird artifacts from rotating<\/p>\n\n\n\n<p>25.) Mess with the levels to remove all of the artifacts<\/p>\n\n\n\n<p>25.) Make a boarder around the black selection and fill white<\/p>\n\n\n\n<p>26.) Invert the colors because you realize most cursors are white not black<\/p>\n\n\n\n<p>27.) Gaussian blur to make sure no-one can see your horrible brush strokes<\/p>\n\n\n\n<p>28.) profit?<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"619\" height=\"624\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-8.png\" alt=\"\" class=\"wp-image-953\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-8.png 619w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-8-298x300.png 298w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-8-150x150.png 150w\" sizes=\"auto, (max-width: 619px) 100vw, 619px\" \/><\/figure>\n\n\n\n<p>Now with that squared I can imported everything into unreal and made a quick ui with a few buttons:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"365\" height=\"331\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-9.png\" alt=\"\" class=\"wp-image-954\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-9.png 365w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-9-300x272.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-9-331x300.png 331w\" sizes=\"auto, (max-width: 365px) 100vw, 365px\" \/><\/figure>\n\n\n\n<p>Then I threw in some logic to make the weapon lower when you&#8217;re looking at a terminal, and that the &#8220;fire&#8221;event will left click the simulated UI:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"798\" height=\"529\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-10.png\" alt=\"\" class=\"wp-image-955\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-10.png 798w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-10-300x199.png 300w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-10-768x509.png 768w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-10-453x300.png 453w\" sizes=\"auto, (max-width: 798px) 100vw, 798px\" \/><\/figure>\n\n\n\n<p><br>The final result:<br><\/p>\n\n\n\n<figure class=\"wp-block-video\"><video height=\"580\" style=\"aspect-ratio: 1064 \/ 580;\" width=\"1064\" controls src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/20250505-1835-02.8745816.mp4\"><\/video><\/figure>\n\n\n\n<p>Still not sure why the cursor is so blurry when moving around a bunch, probably because of some of the motion blur I have on. But generally the goal is to have one of these on each assembler and I should be able to use it as a capture point kinda process to gain control over the assembler to create minions to go capture more assemblers etc. Which I think is now my basic &#8220;game loop&#8221;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"506\" height=\"775\" src=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-11.png\" alt=\"\" class=\"wp-image-957\" srcset=\"https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-11.png 506w, https:\/\/willkolb.com\/wp-content\/uploads\/2025\/05\/image-11-196x300.png 196w\" sizes=\"auto, (max-width: 506px) 100vw, 506px\" \/><\/figure>\n\n\n\n<p><br>So now I think I know what the game is, I&#8217;m thinking one map, 4-5 assemblers, one &#8220;Hub&#8221; boss area, I&#8217;ll probably package in my survival game mode because it&#8217;s kinda already done. Essentially this will be a single player MOBA against an over-world AI<\/p>\n\n\n\n<p>So that means I need:<\/p>\n\n\n\n<p>1.) An overview map UI element<\/p>\n\n\n\n<p>2.) Region based spawning for the assemblers<\/p>\n\n\n\n<p>3.) A &#8220;Boss hub&#8221; whatever that means<\/p>\n\n\n\n<p>4.) Some kind of stationary turrets like which will essentially be a moba<\/p>\n\n\n\n<p>5.) Some kind of countdown that adds an element of urgency to the player<\/p>\n\n\n\n<p>So I added 5 tasks while removing one&#8230;not a great ratio (see <a href=\"https:\/\/trello.com\/b\/dmIooAod\/blacklaceworking-board\">https:\/\/trello.com\/b\/dmIooAod\/blacklaceworking-board<\/a> ) but knowledge is progress.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A while back I made a terminal model that looked meh but was designed to serve as a stand in for some kind of computer interaction: I started out wanted to make a command line interface, but then I changed my mind and wanted a Doom 3 style interface: Setting up the actors To accomplish [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":955,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,29,9],"tags":[],"class_list":["post-941","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-gamedev","category-gimp","category-unreal"],"_links":{"self":[{"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/posts\/941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/willkolb.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=941"}],"version-history":[{"count":3,"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/posts\/941\/revisions"}],"predecessor-version":[{"id":958,"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/posts\/941\/revisions\/958"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/willkolb.com\/index.php?rest_route=\/wp\/v2\/media\/955"}],"wp:attachment":[{"href":"https:\/\/willkolb.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=941"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/willkolb.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=941"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/willkolb.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}