REX Adventure
From SpelWiki
Contents |
Postmortem för REX/Adventure
| Spel: | REX/Adventure |
| Programmerare: | Simon Kågström |
| Grafik: | Simon Kågström |
| Plattform: | REX 6000 |
| Mjukvara: | Debian GNU/Linux, GCC, z88dk |
| Implementeringstid: | 2002-2003, sporadiskt |
| Systemkrav: | REX 6000, z80, 4KB minne |
Jag har tidigare varit ganska förtjust i äventyrsspel i stil med Simon the Sourceror eller Monkey Island, och ville därför skapa något liknande själv. Eftersom jag under denna period programmerade mycket för REX 6000 så blev det att jag satsade på att implementera ett äventyrsspel för den. Eftersom REXen har så begränsat med minne var det omöjligt att göra ett "från sidan"-spel, utan jag valde istället att göra ett tilemap-baserat spel "uppifrån", grafiskt ungefär som ett Zelda men med Monkey Island-känsla.
Spelaren styr genom att peka på en position på pekskärmen, vilket gör att spelaren går till den positionen. Till höger finns ikoner för att göra olika saker. I nedre högra hörnet finns de objekt spelaren har. Man kan utföra olika handlingar genom att välja "Use"-ikonen, till exempel "Use rope on tree" genom att klicka på Use, repet i hörnet och trädet på spelplanen, eller "Open door" genom att klicka på use och därefter dörren.
För att komma runt begränsningen på 8KB stora "addins" som man hade till REX så delade jag upp spelet i en biblioteksdel (spelmotor) som en addin och en speldel som en andra, vilken anropade biblioteksaddinen med "long jumps". På det sättet går det att skriva relativt stora äventyrsspel även till den mycket begränsade REX'en. I slutändan skrev jag bara ett exempelspel som "proof of concept" (går ut på att få bort ett troll från en sten), men spelmotorn är färdig frånsett prestandaoptimering. Jag är i stort sett mycket nöjd med implementationen, förmodligen det bäst implementerade spel jag gjort.
Fem saker som gick bra i REX/Adventure
- Hela spelmotorn frånsett delar av spelloopen fick plats i en 8KB-addin, så nästan 8KB blir över till spellogik och grafik
- Det händelseorienterade APIet blev ganska lättanvänt och tämligen flexibelt - det går att göra relativt komplicerade saker som att kombinera två objekt för att få ett tredje
- Banorna laddas från textfiler, formatet hämtades i stort sett från REX/Arkanoid och fungerade bra här också
- Gränssnittet känns också ganska logiskt
Fem saker som gick dåligt i REX/Adventure
- Grafikutritningen är för långsam. Spelet fungerar, men är i praktiken ospelbart utom i SDL-miljön. Jag har påbörjat en assemblyimplementation av fe_draw_bitmap-rutinen, vilken borde avhjälpa detta problem eftersom z88dk producerar ganska dålig maskinkod från C. Assemblyrutinen är dock buggig och låser hårdvaran, så än måste spelet spelas med den långsamma C-implementationen.
- Spelaren kan max hålla 16 objekt, och dessa måste ligga på fasta platser i objektrutan (krävdes för att spara plats)
- Med flera rörliga objekt blir spelet antagligen för långsamt.
- Spelet som implementerats är ganska tråkigt. Bara ett par skärmar stort och enkelt att klara: klättra upp i trädet med repet för att ta nyckeln, hämta de dammiga pengarna i trädgården, gå in i huset och ta "Mr Proper"-flaskan. Polera därefter pengarna med flaskan och ge de skinande mynten till trollet. Enkelt!
- Grafiken är ful, även för att vara svart-vit och ritad av mig. Spelaren ser ut som ett spöke och trollet ser ut som jag-vet-inte-vad.
Godbitar ur koden
Nedan visas koden från exempelspelet som hanterar objekthändelser för alla skärmar, och visar (förhoppningsvis) att det är ganska enkelt att koda saker som "Use bottle on coins". Denna funktion kan överlagras av hanteraren för den specifika skärmen.
static void handle_objects(advg_game_t *p_game, advg_event_t event)
{
/* The player pressed one of the items. The things here might be
* overridden by the scene-handlers. A typical example would be
* dropping: This should be allowed in some scenes, but not in
* others.
*/
switch(p_game->action)
{
case ADVG_ACTION_LOOK:
/* Print how the object looks. The first 16 messages are
* object-description. Note that the object events are numbered
* from 1 to 16, whereas the messages are numbered from 0 to 15.
*/
advg_display_message(p_game, event-1, 1);
break;
case ADVG_ACTION_USE:
if (p_game->action == ADVG_ACTION_USE &&
p_game->obj_use == OBJ_BOTTLE &&
event == OBJ_DIRTY_COINS)
{
advg_display_message(p_game, EV_USE_BOTTLE_ON_COINS, 2);
advg_add_object(p_game, OBJ_SHINING_COINS);
advg_remove_object(p_game, OBJ_DIRTY_COINS);
advg_remove_object(p_game, OBJ_BOTTLE);
advg_draw_objects(p_game);
break;
}
/* Fall-through - using these two objects makes no sense */
case ADVG_ACTION_TAKE_OBJECT: /* You cannot take something you already have */
advg_display_message(p_game, WHY_DO_THAT, 1);
default:
break;
}
}
En del av assemblyrutinen för att rita bitmappar (Z80-assembly):
ld B, (HL) ; B = byte_w ;; Calculate A = (h << byte_w) + (i>>3) .l2 sla A djnz l2 ld B, E ; B = i sra B sra B sra B ; B = i >> 3 add A, B ; A = (h << byte_w) + (i>>3)
Mer information samt källkoden för REX/Adventure finns på http://www.ipd.bth.se/ska/sim_home/rex_adventure.html
