_Your Own 2-D Gaming Engine_ by Mark Seminatore Listing One // compiled.c - This module implements a bitmap compiler. // Copyright (c) 1996 by Mark Seminatore, all rights reserved. #include #include #include "compat32.h" #include "vga.h" #include "pcx.h" #include "sprite.h" #include "globals.h" // #define UNIT_TEST // // []------------------------------------------------------------[] // | | // | | // []------------------------------------------------------------[] // CompiledSprite CompileBitmap(uchar *pBitmap, int width, int height) { uchar *pCompiled, *pTemp; unsigned column, row, TotalBytes=0; // calc bytes required pTemp=pBitmap; for(row=0; row < height; row++) for(column=0; column < width ; column++) if(*pTemp++) TotalBytes++; // far function-call overhead TotalBytes *= 5; TotalBytes += 25; pTemp = pCompiled = malloc(TotalBytes); if(!pTemp) return (CompiledSprite)pTemp; *pTemp++ = 0x55; // push bp *pTemp++ = 0x8b; // mov bp, *pTemp++ = 0xec; // ...sp *pTemp++ = 0x56; // push si *pTemp++ = 0x1e; // push ds *pTemp++ = 0xc5; // lds si,[bp+06] (pBitmap parm) *pTemp++ = 0x76; *pTemp++ = 0x06; *pTemp++ = 0x8b; // mov ax,[bp+12] (y parm) *pTemp++ = 0x46; *pTemp++ = 0x0c; *pTemp++ = 0xbb; // mov bx,320 (screen width) *pTemp++ = 0x40; *pTemp++ = 0x01; *pTemp++ = 0xf7; // mul bx (calc offset) *pTemp++ = 0xe3; *pTemp++ = 0x03; // add ax,[bp+10] (x parm) *pTemp++ = 0x46; *pTemp++ = 0x0a; *pTemp++ = 0x03; // add si,ax *pTemp++ = 0xf0; for(row=0; row < height; row++) for(column=0; column < width ; column++) { if(*pBitmap) { *pTemp++ = 0xc6; // mov [si+off16],xx *pTemp++ = 0x84; // 16-bit offset *(((unsigned*)pTemp)++) = row * 320 + column; // pixel data *pTemp++ = *pBitmap; } pBitmap++; } *pTemp++ = 0x1f; // pop ds *pTemp++ = 0x5e; // pop si *pTemp++ = 0x5d; // pop bp *pTemp = 0xcb; // retf return (CompiledSprite)pCompiled; } #ifdef UNIT_TEST #include uchar *VideoMem; void main(void) { PcxImage pcx; CompiledSprite pfnSprite; int result,i; result=PcxLoadImage("alien1.pcx",&pcx); pfnSprite=(CompiledSprite)CompileBitmap(pcx.pBitmap, pcx.Width, pcx.Height); getch(); VgaSetMode(0x13); for(i=0;i < 199-16; i+=16) pfnSprite(VideoMem,i,i); getch(); VgaSetMode(3); } #endif Listing Two // Main.c: This module contains the event loop code // Copyright (c) 1996 by Mark Seminatore, all rights reserved. #include #include #include #include #include "compat32.h" #include "keys.h" #include "init.h" #include "vga.h" #include "pcx.h" #include "sprite.h" #include "draw.h" #include "palanim.h" #include "globals.h" // []------------------------------------------------------------[] // | This is the main even-loop | // []------------------------------------------------------------[] void EventLoop(void) { // ESC quits the game while(!kbKeyboard[ESC_KEY]) { // fire a player missile if(kbKeyboard[SPACE_BAR]) { // check if re-loading if(!PlayerMissileDelay) { AddMissile(PLAYER_MISSILE, player.x, player.y-MISSILE_H, NONE, UP); // delay for missile re-load PlayerMissileDelay=HALF_SECOND; } } // move player up if(kbKeyboard[UP_ARROW]) { player.y--; if(player.y < 0) player.y=0; } // move player to the left if(kbKeyboard[LEFT_ARROW]) { player.x--; if(player.x < 0) player.x=0; } // move player to the right if(kbKeyboard[RIGHT_ARROW]) { player.x++; if(player.x + PLAYER_W > (SCREEN_WIDTH-1)) player.x=(SCREEN_WIDTH-1) - PLAYER_W; } // move player down if(kbKeyboard[DOWN_ARROW]) { player.y++; if(player.y + PLAYER_H > VIEW_HEIGHT) player.y= VIEW_HEIGHT - PLAYER_H; } // draw the starfield DrawBackground(); // allow missile movement ForEachMissile(MoveMissile); // time to move? if(!AlienMovementDelay) { // allow actor movement ForEachActor(MoveActor); AlienMovementDelay=TWO_TICKS; } // draw the aliens ForEachActor(DrawActor); // show our hero DrawPlayer(); // update double-buffer UpdateScreen(); // check if time to animate palette if(PaletteToggle) { AnimatePalette(); PaletteToggle=0; } // aliens don't think too quickly! if(!AlienStateDelay) { ForEachActor(UpdateActorState); AlienStateDelay=TWO_SECONDS; } // animate aliens if(!AlienAnimationDelay) { AlienBitmap=(AlienBitmap == Alien1Bitmap) ? Alien2Bitmap : Alien1Bitmap; #ifdef PUTBM AlienMask=(AlienMask == Alien1Mask) ? Alien2Mask : Alien1Mask; #endif AlienAnimationDelay=QTR_SECOND; } // you won...this round if(nActors ==0) { player.Level++; UpdateScore(); InitAliens(); } } // end while() } // end EventLoop() // []------------------------------------------------------------[] // | This is the main program entry-point | // []------------------------------------------------------------[] #pragma argsused void main(int argc,char *argv[]) { // Call the various initialization routines StartUp(); // Display player info UpdateScore(); // Jump into the main program loop EventLoop(); // Call the various cleanup routines ShutDown(); } Example 1: unsigned char kbKeyboard[128]; // This is the new Int 09h handler void static _interrupt NewInt9(void) { register unsigned char acode; // read key code from keyboard kbScanCode=inp(0x60); acode=inp(0x61); outp(0x61,(acode | 0x80)); outp(0x61,acode); // send End-Of-Interrupt to 8259 PIC outp(0x20,0x20); // record a keypress kbKeyboard[kbScanCode & 127]=1; if(kbScanCode & 128) // clear a keypress kbKeyboard[kbScanCode & 127]=0; } Example 2: typedef struct tagPlayer { int x,y; unsigned Score,Level,Lives; } Player; typedef struct tagActor { int type; int x,y; int dx,dy; int State,LastState,Momentum; unsigned MissileDelay; struct tagActor *next; } Actor; typedef struct tagMissile { int type; int x,y; int dx,dy; struct tagMissile *next; } Missile; Example 3: (a) ... mov byte ptr [es:di+10],FF mov byte ptr [es:di+11],F0 mov byte ptr [es:di+12],F0 mov byte ptr [es:di+13],FF ... retf (b) ... push ds ... mov byte ptr [si+10],FF mov byte ptr [si+11],F0 mov byte ptr [si+12],F0 mov byte ptr [si+13],FF ... pop ds retf Example 4: uchar StateTable[CHANCES][LAST_STATE]= { // col = current state, row = chance // HOVER SHOOT DIVE {HOVER_STATE, HOVER_STATE, DIVE_STATE}, {HOVER_STATE, HOVER_STATE, DIVE_STATE}, {SHOOT_STATE, HOVER_STATE, DIVE_STATE}, {SHOOT_STATE, HOVER_STATE, DIVE_STATE}, {DIVE_STATE , HOVER_STATE, SHOOT_STATE} };