19 April 2021, 15:32 | #1 |
Registered User
Join Date: Aug 2018
Location: Untergrund/Germany
Posts: 408
|
Wrong Way Driver - Tech
Some people wanted to hear more about how Wrong Way Driver was created.
Here are some details: The game is written for OCS A500 + 512kb (tho with some extra work it would fit into 512kb only). C++20 The game was born out of an experiment if it would be possible to code a fast Amiga 500 game using C++20 with Coroutines and Lambdas. Bartmans "Amiga C/C++ Compile, Debug & Profile" which i used has support for them. I guess this is the very first C++20 program written on any Amiga computer Coroutines Coroutines let you 'pause' or 'yield' your code and continue later at the same point. The context for them is not stored on the stack but on a heap. Here is a pseudo example how i used them in the title screen to move the logo, print some text and wait for the fire button in parallel by launching another coroutine. Code:
coroutineHandler.add([&]() -> coro { //move in the logo for(int x=-160;x<160;x++) { showLogo(x); co_yield 0; //wait for next frame } co_yield 50; //wait 50 frames //add another coroutine to wait for fire button in parallel coroutineHandler.add([=]() -> coro { while(1) { if(fireButtonPressed()) gGame.setState(Game::State::intro); co_yield 0; } } //show blinking text while(1) { auto text=printText("Press Fire!); co_yield 20; clearText(text); co_yield 20; } } If i change the gameState then the coroutineHandler gets deleted. So i don't have to care about dangling coroutines. Memory Managment For this game i used again no dynamic memory managment (so no 'new' and 'delete', but only placement 'new'). I used preallocated Frame- and Poolheaps. I described such heaps already for Tinyus Tech. Sprites Sprites are used for the "WRONG WAY DRIVER" and "ABYSS" logo and all HUD elements like the coin/gas counter and score display. On the title screen i use 3 color sprites, and when playing the game i use attached 15 color sprites. A single 128x224 sized area, with two bitplanes, is used for all sprites. A software driver sorts, splits, blits and multiplexes them into this area each frame as needed. Writing an optimal sprite driver is a madmans task. The city skyline The city area uses dual playfield for parallax scrolling. Various copper splits are used to make it look like more then two playfields. Also sprites are displayed above to make it look like 4 parallax layers are there. The pseudo 3D street The street is created with 5 parallaxed stripes. Each uses 16 frames of animation (3kb altogether packed). They are blitted into the backbuffer and into the restorebuffer each frame. The different cars, coins and gas symbols are just one image each. On startup i precalc 11 zoom images for each of them. The street area runs in 4 bitplanes. I used two coppersplits to parallax animate the front and back side of the street. Bobs I use 16 and 32 pixel wide bobs for all zooming objects. Each bob can have a variable height. For optimal performance i blit all of those after waiting for the last displayed line. Audio All insturments+fx take 34kb, and are precalced on startup (Pretracker!). Channel 4 is used mainly for delay sounds and can be interrupted by SoundFx. Game size The game was crunched with Shrinkler from 135kb to to 61kb. The large size is mainly because of the used GCC optimizations (lto,-Ofast). Without GCC optimizations the game is only half as big. By sprinkling #pragmas over non time critical code the size could be further reduced. Thanks for reading. Last edited by pink^abyss; 20 April 2021 at 15:02. |
19 April 2021, 15:46 | #2 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 387
|
Very interesting to see co-routines in use on Amiga. I haven't used them myself in other projects but I've seen the concept used in games at least as far back as 1998.
What is the overhead like for yielding and continuing on the Amiga? Is the optimizer able to inline everything to such an extent that it only needs to save a partial context? |
19 April 2021, 16:33 | #3 | |
Registered User
Join Date: Aug 2018
Location: Untergrund/Germany
Posts: 408
|
Quote:
The code for iterating over and jumping into the coroutines adds also a little bit of extra work, but compared to just calling an array of function pointers and context its not much slower (at least when each of this functions also actually do some work). Coroutines allow shorter, easier and much better readable code, for very little extra performance impact. Especially for typical 'throw away' game code that only happens once in your game without much structure. |
|
19 April 2021, 21:28 | #4 |
This cat is no more
Join Date: Dec 2004
Location: FRANCE
Age: 52
Posts: 8,162
|
Bagman was probably the first amiga game to use C++11, you broke that record with C++ 20. I'm jealous.
|
19 April 2021, 22:53 | #5 |
Lemon. / Core Design
Join Date: Mar 2016
Location: Tier 5
Posts: 1,211
|
Coroutines are banned where I work
Invoke too... |
19 April 2021, 23:15 | #6 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 387
|
Please make them add the spaceship operator to that list!
|
19 April 2021, 23:45 | #7 |
This cat is no more
Join Date: Dec 2004
Location: FRANCE
Age: 52
Posts: 8,162
|
spaceship operator what a joke, this is just useless...
|
21 April 2021, 16:40 | #8 | |
Registered User
Join Date: Aug 2018
Location: Untergrund/Germany
Posts: 408
|
Quote:
A jumptable call is used as indirection on each resume (if you have more then one co_yield). So the overhead compared to a normal function call is negligible (at least compared with a function that would need to save/restore all registers). Another feature i didn't talk about was the use of lambdas in Wrong Way Driver. Those imposed no performance penalty and helped a lot to shorten the code and make it more readabale. Lambdas are great for callbacks or short 'throw away' code snippets that you don't need in a function. |
|
21 April 2021, 17:06 | #9 |
Registered User
Join Date: Jun 2020
Location: Druidia
Posts: 387
|
It's really interesting to hear these features can work effectively on a 68000.
I'm not sure how I would feel about opening this can of worms on a large project. But since most Amiga projects are tiny teams or just an individual it seems perfectly fine. Certainly seems like it could simplify a lot of the high level sequencing code for a demo or game. |
21 April 2021, 19:50 | #10 | |
Registered User
Join Date: Aug 2018
Location: Untergrund/Germany
Posts: 408
|
Quote:
I see your point (and i'm certainly not an advocate for modern C++ stuff). I used these things on Amiga 500 because i used them successfully already many years in my real world coding job.There we don't use coroutines in the game engine code, but we use lambdas a lot (we see them just as 'local' function calls). For our game scripting code (that drives the whole game) it's very different. There we use coroutines and lambdas (our own, not the C++ ones) all over the place. That made us writing games much faster and safer. We already shipped four games with them and are very happy with the results. The trick is to pack coroutines into hierachical objects and only operate on their own data. That makes it easy and safe to reason about them and their lifetime. The development time savings of using them in our games were mind-blowing. |
|
22 April 2021, 13:30 | #11 |
Registered User
Join Date: Feb 2019
Location: Munich, Germany
Posts: 63
|
Here's an example of the generated assembly code from a trivial C++20 coroutine. Feel free to play around: Brown++ Compiler Explorer
|
23 April 2021, 14:19 | #12 | |
Registered User
Join Date: Apr 2017
Location: Cambridge
Posts: 136
|
Thanks so much for this write-up!
I was expecting to read about graphical hijinx and assembly prowess, so C++20 and coroutines was a complete shock! Quote:
|
|
27 April 2021, 13:21 | #13 | |
Registered User
Join Date: Aug 2018
Location: Untergrund/Germany
Posts: 408
|
Quote:
My comment was about our work environment, where we don't use C++ for scripting. With 'safe' & 'lifetime' i don't mean it in a strict way like Rust guarantees it, but simply how it behaves in our console game projects. |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Wrong Way Driver - New Amiga OCS Game by aBYSs | pink^abyss | News | 75 | 18 December 2022 10:31 |
Tinyus Tech | pink^abyss | Coders. Asm / Hardware | 84 | 06 April 2021 06:30 |
Trackmo tech | paraj | Coders. Asm / Hardware | 4 | 30 March 2017 20:57 |
AmigaWorld Tech Journal | Shadowfire | AMR news | 7 | 26 April 2009 19:14 |
LN2 tech demo | gimbal | project.Amiga Game Factory | 63 | 02 October 2008 20:22 |
|
|