Eric Lafortune Posted August 29 Share Posted August 29 While playing Farcry and Watchdogs on my Linux system, it occurred to me that we don't have any open-world, motion-captured, 3D rendered games for our beloved TI. Like back in the days, that meant I had to write one myself. So I started work on a new game, Stealth Runner. Given the constrained computational resources, and lacking a development team of a few hundred people, I did need to check my goals... Stealth Runner is a third-person open-world action game with the following features: Pre-rendered graphics. Smooth motion-captured animation (30 fps). Pixel-precise omni-directional scrolling. Sound and speech. Entirely written in TMS-9900 assembly code. The game tries to push the envelope of what is achievable on the TI, with the help of freely available modern-day resources. The motion-captured models come from Mixamo. The rendering is done with Blender. The graphics, sound, and speech are processed with ImageMagick, ffmpeg, and my own Video Tools . The build process is tied together with python/bash/java scripts and programs . The game engine builds on my experiences with streaming graphics, sound, and speech in my Bad Apple demo, only this time interactively. The excellent xas99 assembler helped keeping the code readable with nifty features like macros, and extensive comments. This is version 0.1. It mainly shows the game engine in a single, simple level. It has a few rough edges, e.g. the speech is occasionally garbled, for some unknown reason. The speech snippets are placeholders; I'm hoping to add epic humming choir vocals (Mozart's Lacrimosa?) and better grunts. The level is not very exciting yet. You can find the source code and technical details and the compiled binaries on Github. The cartridge ROM is 1.5 MB -- I've only tested it in Mame. The source code notably contains include files that can be generally useful for writing assembly code for games. The game engine is mainly driven by the internals of the CPU/VDP/sound/speech, but comments and ideas are welcome. Enjoy! 36 2 Quote Link to comment Share on other sites More sharing options...
Cheung Posted August 30 Share Posted August 30 Wow 2 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted August 30 Share Posted August 30 Prince of Persia, eat your heart out. 2 Quote Link to comment Share on other sites More sharing options...
TheMole Posted August 30 Share Posted August 30 VERY nice! 2 Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted August 30 Share Posted August 30 Nice, a cartridge that actully needs the 2M Yellow boards for physical versions. . .and it is an outstanding effort even at this early stage! 3 Quote Link to comment Share on other sites More sharing options...
Nick99 Posted August 30 Share Posted August 30 Wow, I did not expect this! 1 Quote Link to comment Share on other sites More sharing options...
Tator Posted August 30 Share Posted August 30 Awesome!!! 2 Quote Link to comment Share on other sites More sharing options...
virios Posted August 30 Share Posted August 30 It's really fantastic and with a fluidity of movement never seen before, extraordinary🤪 3 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted August 30 Share Posted August 30 The humming in the introduction kills me. 3 Quote Link to comment Share on other sites More sharing options...
HOME AUTOMATION Posted August 30 Share Posted August 30 🚬 🌊 ...🎆 Quote Link to comment Share on other sites More sharing options...
+eebuckeye Posted August 30 Share Posted August 30 Holy crap!?! 2 Quote Link to comment Share on other sites More sharing options...
broettger Posted August 30 Share Posted August 30 Impressive! I would never have expected something like this actually being possible on the TI.. 2 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted August 30 Share Posted August 30 Very cool. The speech is garbled in my emulator (JS99er), so now I have something to fix. 🙂 6 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted August 30 Share Posted August 30 Important for MAME usage: You have to use the 60 Hz console (ti99_4a), not the European 50 Hz (ti99_4ae). The latter will garble the speech. 4 Quote Link to comment Share on other sites More sharing options...
jrhodes Posted August 30 Share Posted August 30 3 hours ago, eebuckeye said: Holy crap!?! Ditto. Quote Link to comment Share on other sites More sharing options...
Eric Lafortune Posted August 30 Author Share Posted August 30 Thanks everyone! 😃 3 hours ago, Asmusr said: Very cool. The speech is garbled in my emulator (JS99er), so now I have something to fix. 🙂 The speech is occasionally garbled in Mame too. I haven't figured it out yet -- let me know if you find something. The speech code checks that the synthesizer is not talking, then sends the SPEAK_EXTERNAL command and 16 bytes of speech. Then, theoretically 60 times per second, it checks if the speech buffer is low and sends 9 additional bytes of speech. This should even be sufficient in 50Hz PAL (unless the drawing code can't keep up with the vsync rate), so I should delve into it again. 4 Quote Link to comment Share on other sites More sharing options...
GDMike Posted August 30 Share Posted August 30 That's uh...uhh...uh..outta breath...uhhhh Nice job . Awesome 1 Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted August 30 Share Posted August 30 For whatever reason, the intro humming made me think of the old Cheesy Software game MegaPede intro. Very cool to see the smooth action in motion together with the other effects. Well done! 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted August 30 Share Posted August 30 3 hours ago, Eric Lafortune said: The speech is occasionally garbled in Mame too. I haven't figured it out yet -- let me know if you find something. The speech code checks that the synthesizer is not talking, then sends the SPEAK_EXTERNAL command and 16 bytes of speech. Then, theoretically 60 times per second, it checks if the speech buffer is low and sends 9 additional bytes of speech. This should even be sufficient in 50Hz PAL (unless the drawing code can't keep up with the vsync rate), so I should delve into it again. If you want to debug for yourself, patch src/devices/sound/tms5220.cpp this way. You will see that with the 50Hz consoles you actually run into buffer empty states. --- a/src/devices/sound/tms5220.cpp +++ b/src/devices/sound/tms5220.cpp @@ -399,6 +399,7 @@ emulating the tms5220 in MCU code). Look for a 16-pin chip at U6 labeled #define LOG_RS_WS (1U << 15) //#define VERBOSE (LOG_GENERAL | LOG_DUMP_INPUT_DATA | LOG_FIFO | LOG_PARSE_FRAME_DUMP_HEX | LOG_FRAME_ERRORS | LOG_COMMAND_DUMP | LOG_COMMAND_VERBOSE | LOG_PIN_READS | LOG_GENERATION | LOG_GENERATION_VERBOSE | LOG_LATTICE | LOG_CLIP | LOG_IO_READY | LOG_RS_WS) +#define VERBOSE (LOG_GENERAL) #include "logmacro.h" #define MAX_SAMPLE_CHUNK 512 @@ -708,6 +709,7 @@ void tms5220_device::update_fifo_status_and_ints() // generate an interrupt if necessary; if /BL was inactive and is now active, set int. if (!m_buffer_low) { + LOG("Buffer low\n"); m_buffer_low = true; set_interrupt_state(1); } @@ -723,6 +725,7 @@ void tms5220_device::update_fifo_status_and_ints() // generate an interrupt if necessary; if /BE was inactive and is now active, set int. if (!m_buffer_empty) { + LOG("Buffer empty\n"); m_buffer_empty = true; set_interrupt_state(1); } @@ -881,7 +884,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size) int i, bitout; int32_t this_sample; - LOG("process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); + // LOG("process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); /* loop until the buffer is full or we've stopped speaking */ while (size > 0) 4 1 Quote Link to comment Share on other sites More sharing options...
edweird13 Posted August 31 Share Posted August 31 Wow this is fantastc!!!! 3 Quote Link to comment Share on other sites More sharing options...
Tetlee Posted September 3 Share Posted September 3 Wow indeed, what am I seeing here?!? Amazing work! 1 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted September 3 Share Posted September 3 I want to point out what I think may be an underappreciated aspect of this game: the humming. A while back, @retroclouds experimented with using the Speech Synthesizer for non-speech audio. The fact that Eric uses it for humming is another extraordinary departure from how we traditionally use the SS. 4 Quote Link to comment Share on other sites More sharing options...
Tursi Posted September 4 Share Posted September 4 Just saw this now... very impressive! 1 Quote Link to comment Share on other sites More sharing options...
Artoj Posted September 4 Share Posted September 4 Brilliant!!!!, I am highly impressed. (thinking.... i would love to pixel paint the scenery...mm.. would need more colours...maybe just a careful B/W render.....) Quote Link to comment Share on other sites More sharing options...
Eric Lafortune Posted September 4 Author Share Posted September 4 7 hours ago, Artoj said: Brilliant!!!!, I am highly impressed. (thinking.... i would love to pixel paint the scenery...mm.. would need more colours...maybe just a careful B/W render.....) Thanks! Better scenery would be nice! Adding some trees and shrubs as sprites might help. The landscape of dots seems simple, but it was a big challenge. The simplest approach would have been a rectangular grid of dots, with 1 dot per character. You can then render a screen with two characters: one with a dot and a blank one Every frame, you can smoothly scroll the screen by updating the pattern of the character, and updating the necessary characters on the screen (along the edges of the landscape, depending on the scrolling direction). I've opted for a diagonal grid of dots, with 2 dots per character. You can then render a screen with four characters: one with two dots, two with one dot, and a blank one. Every frame, you then need to update the patterns of three characters, and update a larger number of characters on the screen. The amount of data to transfer increases as the patterns get more complex, and there's already a lot going on with the player avatar and the supersprites. It's one example where the game engine is driven by the internals of the VDP. 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.