Pembuatan Game : Pembuatan Game pada DOS secara Garis Besar

 



Sekarang gw akan mempost’kan tentang pembuatan game pada DOS. Game DOS pada masanya merupakan game yang sangat terkenal. Sekarang gw akan membahas tentang pembuatan game DOS ini (walaupun pada garis besarnya saja). Seperti yang dipostkan oleh Alexander Russell di SINI.


Kita akan membuat game ini pada bahasa C, karena bahasa C ini adalah bahasa yang sering dipakai oleh orang-orang dalam membangun game di DOS. Game memakan banyak sekali memori, dan banyak dari itu diakses dengan menggunakan pointer. Pointer adalah sebuah pointer yang menyimpan alamat dari suatu item data.
char *t1;
ini mendeklarasikan kararkter ke dalam sebuah pointer dan tidak mendefenisikan di mana keberadaaannya. Kita tidak dapat mendeklarasikan seperti ini
char *t1;
strcpy(t1, “hello world”);
karena akan mengakibatkan crash pada komputer, apabila kita menuliskannya seperti ini :
char *t1;
t1=malloc(100);
strcpy(t1, “hello world”);
maka akan dapat dilaksanakan, karena kita sudah mendeklarasikan variabel t1 untuk karakter, kemudian kita tambahkan range’nya dengan perintah malloc , maka kita akan menempatkan ”hello world” di t1.
Lalu, kita akan memakai mode 13h. Mode 13h memiliki 256 buah warna palet, setiap bagian didefinisikan 6 bit oleh warna merah, biru dan hijau. Kode untuk masuk ke mode 13h sebagai berikut : Grafik Primitives
int old_mode;

void enter_mode13h(void)
{
 union REGS in, out;

 // get old video mode
 in.h.ah=0xf;
 int86(0x10, &in, &out);
 old_mode=out.h.al;

 // enter mode 13h
 in.h.ah=0;
 in.h.al=0x13;
 int86(0x10, &in, &out);
}

void leave_mode13h(void)
{
 union REGS in, out;

 // change to the video mode we were in before we switched to mode 13h
 in.h.ah=0;
 in.h.al=old_mode;
 int86(0x10, &in, &out);
}
lalu kita akan masuk ke grafik primitives. Di sini kita membahasa pixel. Sebenarnya sangat jarang membut sebuah pixel pada game. Kode yang akan kita masukkan ke screen buffer (yang tidak akan ditampilkan) lalu sebuah fungsi yang dibuat terpisah akan mengcopy dari screen buffer ke memori sehingga membuat hasilnya terlihat. Kodenya adalah seperti ini :
unsigned char far *screen;  // pointer to the VGA video memory
unsigned char far *off_screen; // pointer to our off screen buffer
int screen_width, screen_height;
unsigned int screen_size;
Lalu kita kan menginisialisasikan mode 13h dengan menggunakan kode di bawah ini :
int init_video_mode(void)
{
 off_screen=farmalloc(64000u); 

 if ( off_screen )
  {
  screen=MK_FP(0xa000, 0);
  screen_width=320;
  screen_height=200;
  screen_size=64000u;
  enter_mode13h();
  _fmemset(offscreen, 0, screensize);
  return 0;
  }
 else
  {
  // no mem! Return error code!
  leave_mode13h();
  printf("Out of mem!\n");
  return 1;
  }
}

#define INPUT_STATUS_0 0x3da

// copy the off screen buffer to video memory
void update_buffer(void)
{
 // wait for vertical re-trace
 while ( inportb(INPUT_STATUS_0) & 8 )
  ;
 while ( !(inportb(INPUT_STATUS_0) & 8 ) )
  ;

 // copy everything to video memory
 _fmemcpy(screen, off_screen, screen_size);
}
Untuk garis horizontal, kita dapat memasukkan code seperti ini :
void horz_line(int x, int y, int len, int colour)
{
 unsigned char far *p;

 p=off_screen + y*screen_width +x;  // make p point to the start of the line
 _fmemset(p, colour, len);     // fill in the line
}
untuk garis vertikal kita dapat memasukkan kode seperti di bawah ini :
void vert_line(int x, int y, int len, int colour)
{
 unsigned char far *p;

 p=off_screen + y*screen_width +x;  // make p point to the start of the line
 while ( len--)   // repeat for entire line length
  {
  *p=colour;  // set one pixel
  p+=screen_width; // move down one row
  }
}
Oke, mungkin untuk pembuatan objek, dicukupkan sampai di sini saja, karena dapat dibuka lebih lanjut pada referensi yang diberikan di link bagian atas. Sekarang kita akan lanjutkan ke bagian animasi. Pada animasi, bagimana kita memindahkan objek ? kita tinggal mengatur nilai x dan y nya. Kode simpelnya seperti ini :
int x;

For ( x=10; x < 200; x++ )
 draw_pixel(x, 100, 5);
Kode yang sama dapat digunakan pula untuk menggerakkan sprites. Sekarang kita akan masuk ke bagian input’an untuk kontrol. Untuk :
1. Keyboard : kita harus menggunakan int9 (hardware untuk menginterupsi keyboard) ISR (Interrupt Service Routine) untuk menggantikan fungsi BIOS keyboard secara keseluruhan, karena pada keyboard dengan BIOS biasa tidak diperbolehkan penggunaan multikey secara bersamaan. Untuk codenya dapat ditulis seperti ini
#define BYTE unsigned char
#define NUM_SCAN_QUE 256     // this MUST be 256, using BYTE roll-over for
                             // q code

// the interrupt keyword causes the compiler to save all the registers before the
function is called, and restore them on exit. It also makes the function return via a
IRET.

static void interrupt (far *oldkb)(void);   /* BIOS keyboard handler */

// Q code
BYTE gb_scan;
BYTE gb_scan_q[NUM_SCAN_QUE];
BYTE gb_scan_head;
BYTE gb_scan_tail;

/*
   invoked by the hardware keyboard interupt
   ques up the raw scan codes
    stuff raw scan codes into the array gb_scan_q[]
*/
/* ---------------------- get_scan() --------------------- April 17,1993 */
void interrupt get_scan(void)
{

   /* read the raw scan code from the keyboard */
   asm   cli

   asm   {

         in    al, 060h       /* read scan code */
         mov   gb_scan, al
         in    al, 061h       /* read keyboard status */
         mov   bl, al
         or    al, 080h
         out   061h, al       /* set bit 7 and write */
         mov   al, bl
         out   061h, al       /* write again, bit 7 clear */

         mov   al, 020h       /* reset PIC */
         out   020h, al

         /* end of re-set code */

         sti
         }

// save the raw scan code in a 256 byte buffer
   *(gb_scan_q+gb_scan_tail)=gb_scan;
   ++gb_scan_tail;
}

/*

save the old int9 ISR vector, and install our own
*/
/* ---------------------- init_keyboard() ---------------- April 17,1993 */
void init_keyboard(void)
{
   BYTE far *bios_key_state;

   /* save old BIOS key board handler */
   oldkb=getvect(9);

   // turn off num-lock via BIOS
   bios_key_state=MK_FP(0x040, 0x017);
   *bios_key_state&=(~(32 | 64));     // toggle off caps lock and
                                      // num lock bits in the BIOS variable
   oldkb();      // call BIOS key handler to change keyboard lights

   gb_scan_head=0;
   gb_scan_tail=0;
   gb_scan=0;

   /* install our own handler */
   setvect(9, get_scan);

}

/* restore the bios keyboard handler */
/* ---------------------- deinit_keyboard() -------------- April 17,1993 */
void deinit_keyboard(void)
{
   setvect(9, oldkb);
}
2. Mouse : Sebenarnya penggunaan mouse biasa dapat dilakukan, tetapi lebih 'enak' lagi jika kita menggunakan ISR
 
;***************************************************************
;*                                                             *
;* File: cmousea.asm                                           *
;*                                                             *
;* Assembly language hook for CMOUSE library event handler     *
;* Assemble with /Ml switch                                    *
;*                                                             *
;***************************************************************
; real code for real men
; adjust for proper memory model
.MODEL SMALL,C

.CODE
      PUBLIC mouse_event_func,mouse_int

mouse_event_func DD ?

mouse_int PROC FAR
          PUSHF
          CALL CS:[mouse_event_func]
          RET
mouse_int ENDP

END
fungsi ASM ini yang dipanggil oleh int33h driver.
Ini adalah kode C untuk menggunakan mouse.
#define ESC 27

short mouse_x, mouse_y;
short mouse_present;
short mouse_hidden=0;
short button_stat=0;
unsigned short flags;

extern void far *far mouse_event_func;
void mouse_int(void);

typedef struct
 {
 unsigned int flags, x, y, button_flag;
 }
mouse_info_t;

#define MAX_MOUSE_EVENTS 10

#define MOUSE_MOVE   1
#define MOUSE_L_DN   2
#define MOUSE_L_UP   4
#define MOUSE_R_DN   8
#define MOUSE_R_UP   16

#define EVENT_MASK   31   /* the logical OR of the 5 above vars */

mouse_info_t mouse_info[MAX_MOUSE_EVENTS];
int head=0;
int tail=0;

/* the low level interrupt handler calls this */
/* ---------------------- mouse_handler() ----------------- April 1,1993 */
void far interrupt mouse_handler(void)
{

   /* save info returned by mouse device driver */
   asm   {
         mov   flags,   ax
         mov   mouse_x, cx
         mov   mouse_y, dx
         mov   button_stat, bx
         }

 // place the mouse information in a circular queue
 mouse_info[tail].x=mouse_x;
 mouse_info[tail].y=mouse_y;
 mouse_info[tail].button_flag=button_stat;
 mouse_info[tail].flags=flags;

 tail++;
 if ( tail == MAX_MOUSE_EVENTS )
  tail=0;
   if ( tail == head )
      {
      head++;
      if ( head == MAX_MOUSE_EVENTS )
         head=0;
      }

}

/*

   the assembler function mouse_int() calls
   mouse_event_func whenever the mouse moves, or a button
   is pressed, or released. mouse_event_func points to mouse_handler
   which ques up the mouse events, get_event can be used to read these
   events.

*/

/* is there a mouse, install int handlers */
/* ---------------------- init_mouse() -------------------- April 1,1993 */
short init_mouse(void)
{
   unsigned short c_seg, c_off;

   asm   {
         xor   ax, ax
         int   033h

         /* note BX holds number of buttons, but we don't care */
         mov   mouse_present, ax
         }

   if ( mouse_present )
      {
      /* install our own handler */
      mouse_event_func=mouse_handler; /* global func pointer */

      /* install mouse_int as mouse handler, which will call
         mouse_handler */

      c_seg=FP_SEG(mouse_int);
      c_off=FP_OFF(mouse_int);
      asm   {
            mov   ax, c_seg
            mov   es, ax
            mov   dx, c_off
            mov   ax, 0ch
            mov   cx, EVENT_MASK

            int 033h
            }

      /* set mouse x, y limits */
      asm   {
            mov   ax, 7
            mov   cx, 0
            mov   dx, 359

            int 033h

            mov   ax, 8
            mov   cx, 0
            mov   dx, 239

            int 033h

            /* set initial mouse_x, mouse_y */
            mov   ax, 3
            int 033h

            mov   mouse_x, cx
            mov   mouse_y, dx
            }
      }

   return(mouse_present);
}

* ---------------------- deinit_mouse() ------------------ April 1,1993 */
void deinit_mouse(void)
{

   if ( mouse_present )
      {
      /* deinstall our mouse handler by making int 33 never call it */
      asm   {
            mov   ax, 0ch
            xor   cx, cx     /* mask == 0, handler never called */

            int 033h

            /* reset mouse driver */
            xor   ax, ax
            int   033h
            }
      }
}
3. Joystick : Joystick standar sangat sangat lambat dibaca pada DOS. Untuk mencegah agar game juga jadi tidak ‘down’ saat dimainkan, pembacaannya hanya dilakukan pada interval yang regular saja, tombol-tombolnya juga dapat dibaca dengan cepat. Untuk kodenya dapat dituliskan seperti ini :
/* note!!!! buttons are pressed when b0, b1 is zero (0)

   Also, the values returned by this routine will vary widely
   on machines that run at different speeds for joy_x and y

   reads joy1 only
   if joystick is not plugged in the joy_x and joy_y will both
   be 1023

   generally you read the joystick at fixed intervals because
   it is a slow process, and the buttons more frequently.

*/

short joy_x, joy_y;  // stores joystick position
BYTE b0, b1;      // button status flags

/* sets the global vars b1, and b0 */
/* ---------------------- read_joy_buttons() -------------- June 10,1993 */
void read_joy_buttons(void)
{
   asm {

               mov    dx,201h
               xor    ax, ax
               in     al,dx

               mov    bl, al
               and    bl, 010h
               mov    b0, bl

               and    al, 020h
               mov    b1, al
       }
}

/* sets the global vars joy_x, joy_y, b0, b1 - SLOW!!! */
/* this is slow compared to just checking the buttons.
   in many projects I only check the joystick once/(certain time)
   and the buttons more frequently.
*/

/* ---------------------- read_joy() --------------------- March 29,1993 */
void read_joy(void)
{
   asm {
               push   si

               xor    ax,ax
        /* joystick port */
               mov    dx,201h
               mov    cx,ax
               mov    bx,ax
               mov    si, 1024   /* this number may have to be LARGER on
                                  FAST machines */

               cli    /* disable interupts so that our timing loop isn't
                         interupted */

        /* begin digitize, prime joy port */
               out    dx,al
       }
jlp:
   asm {
               dec    si
               jz     abt          /* timeout */
        /* read port */
               in     al,dx
               test   al,1
               jz     nox
        /* increment x counter if bit 0 high */
               inc    bx
       }
nox:
   asm {
               test   al,2
               jz     noy
        /* increment y counter if bit 1 high */
               inc    cx
       }
noy:
   asm {
               test   al,3
        /* keep going until both x and y done */
               jnz    jlp
       }
abt:
   asm {
               sti    /* enable interupts */

        /* store x and y coordinates, and button stats */

               mov    joy_y, cx
               mov    joy_x, bx

               mov    bl, al
               and    bl, 010h
               mov    b0, bl

               and    al, 020h
               mov    b1, al

               pop    si
       }

}
dan lainnya.
Sebenarnya masih banyak sekali postingan yang tidak gw post dari sumbernya, karena itu bagi yang tertarik lebih jauh klik di SINI saja untuk pergi menuju sumber tulisan di blog ini, karena dibahas secara per chapter, dari chapter 1 sampai chapter 6.
Sampai di sini saja post’an gw, bakal lanjut lagi nanti!
untuk cara menginstall game DOS pada windows XP dan Vista, dapat dilihat di link di bawah ini:


Referensi :


Muzanuf's

Tidak ada komentar:

Poskan Komentar

Instagram