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 :
http://www3.telus.net/alexander_russell/course/introduction.htm



