Hola a todos!!!
No me gusta deciros lo que os voy a decir, pero no tengo más remedio que hacerlo
para tener la conciencia tranquila. Me despido de vosotros con mucha tristeza, mi
juego "Asteroids Wars" no se desarrollará en la plataforma MSX, sino que lo hará
en un futuro en PC, os explico: cuando comencé mi primera quinzena de vacaciones,
tenía muchas ganas de hacer cosas, y conseguí desarrollar una mínima parte de mi
futuro juego, y todo en ensamblador mediante "Pasmo". Después volví al trabajo,
y creedme las ganas de hacer cosas cuando trabajas en los meses estivales desapa-
recen. Así que lo dejé bastante de lado, pero después pensé que podría desarrollar-
lo en lenguaje C, utilizando el compilador cruzado Z88dk, y me programé mi propia
librería, de ésta manera no se me haría tan pesado hacer el juego.
Aquí teneis mi librería por si alguno le interesa:
**************************************************
/*
FICHERO: "LIBECALIUS.C"
DESCRIPCIÓN: "Librería básica de programación de juegos para MSX"
AUTOR: Ecalius Software 2011
Fecha: 22-7-2011
*/
// Direcciones de la BIOS ( Entrada: -> , Salida: ->>)
#define CHGMOD 0x084F // Activa un nuevo modo de pantalla -> A=Modo de pantalla (0,1,2,3)
#define MAPXYC 0x15DF // Convierte unas coordenadas gráficas (x,y) en una dirección de la VRAM -> BC=x DE=y ->> FETCHC
#define FETCHC 0x1639 // Devuelve la dirección de la VRAM calculada de MAPXYC en ->> HL=Dirección A=Pixel seleccionado
#define CHGET 0x10CB // Espera hasta que se pulse una tecla ->> A=Caracter leído
#define CLS 0x0848 // Borra la pantalla en cualquier modo -> Flag Z
#define DISSCR 0x0577 // Deshabilita la pantalla para dibujar
#define ENASCR 0x0570 // Habilita la pantalla para dibujar
#define SNSMAT 0x1452 // Devuelve el estado de una fila de una matriz del teclado-> A=Núm. fila del teclado ->> A=Estado de la fila (0 -pulsado)
#define WRTVRM 0x07CD // Escribe un dato en la VRAM -> HL=Dirección A=Dato
#define RDVRM 0x07D7 // Lee un dato de la VRAM -> HL=Dirección ->> A=Dato
#define LDIRMV 0x070F // Transfiere un bloque de bytes a la memoria desde la VRAM-> BC=Cantidad DE=Direc.RAM HL=Direc.VRAM
#define LDIRVM 0x0744 // Transfiere un bloque de bytes a la VRAM desde la memoria-> BC=Cantidad DE=Direc.VRAM HL=Direc.RAM
#define FILVRM 0x0815 // Rellena un bloque de bytes de la VRAM con un dato-> A=Dato BC=Cantidad HL=Direc.VRAM
#define CLRSPR 0x06A8 // Borra todos los sprites
#define CHGCLR 0x07F7 // Coloca los colores del borde, papel y tinta en pantalla
#define BAKCLR 0xF3EA // Variable en la RAM que determina el color del papel en pantalla
#define FORCLR 0xF3E9 // Variable en la RAM que determina el color de la tinta en pantalla
#define BDRCLR 0xF3EB // Variable en la RAM que determina el color del borde en pantalla
#define GICINI 0x04BD // Inicializa el chip PSG de sonido del MSX
#define WRTPSG 0x1102 // Escribe en cualquier registro del PSG-> A=Número de registro(0-15) E=Dato
#define BEEPER 0x1113 // Genera un sonido BEEP
#define PLAY 0x73E5 // Orden PLAY del BASIC MSX-> HL=Apunta a una cadena con el macrolenguaje musical, y ésta debe acabar con un 0
#define GTSTCK 0x11EE // Obtiene el estado del joystick-> A=Conector ID (0,1 o 2) ->> A=Código de posición del joystick (0->
(ID=1 o 2)
// Posiciones en la VRAM en modo 2 (256x192 16 colores)
#define TABPAT 0x0000 // Tabla de patrones (768 celdillas*8 bytes/celdilla-->6144 bytes)
#define TABCOL 0x2000 // Tabla de colores (768 celdillas*8 bytes/celdilla-->6144 bytes)
#define TABATRSPR 0x1B00 // Tabla de atributos de sprites ( Y,X,Modelo,Color ) (Y=209 -> Desaparece)(32 máx(128 bytes)) (4 bytes/sprite)
#define TABPATSPR 0x3800 // Tabla de patrones de sprites ( 256 máximo (8x8) )(256*8 -->2048 bytes)
// Constantes importantes de la librería de Ecalius
#define PCOORDY 0 // Posición de la coordenada Y de un sprite en su tabla de atributos de sprites
#define PCOORDX 1 // Posición de la coordenada X de un sprite en su tabla de atributos de sprites
#define PMODELO 2 // Posición del modelo del sprite en su tabla de atributos de sprites
#define PCOLOR 3 // Posición del color de un sprite en su tabla de atributos de sprites
// Constantes de los colores del MSX
#define TRANSPARENT 0
#define BLACK 1
#define GREEN 2
#define LIGHTGREEN 3
#define DARKBLUE 4
#define LIGHTBLUE 5
#define DARKRED 6
#define CYAN 7
#define RED 8
#define LIGHTRED 9
#define DARKYELLOW 10
#define LIGHTYELLOW 11
#define DARKGREEN 12
#define MAGENTA 13
#define GRAY 14
#define WHITE 15
// Variables globales de la librería de Ecalius
struct sprite {
unsigned char coordY;
unsigned char coordX;
unsigned char modelo;
unsigned char color;
unsigned char estado; // 0-apagado 1-encendido
};
struct velsprite {
unsigned char vector_up;
unsigned char vector_dw;
unsigned char vector_lf;
unsigned char vector_rg;
};
unsigned char mascaradepixel;
// SUBRUTINAS BÁSICAS DE LA LIBRERÍA DE ECALIUS
/*
SETDISPLAYMODE
*/
void SetDisplayMode(unsigned char modo)
{
#asm
ld hl,2
add hl,sp
ld a,(hl) ; A=modo
call CHGMOD
#endasm
}
/*
SETCOLOR
*/
void SetColor(unsigned char tinta, unsigned char papel, unsigned char borde)
{
#asm
ld hl,2
add hl,sp
ld a,(hl) ; borde
ld (BDRCLR),a
inc hl
inc hl
ld a,(hl) ; papel
ld (BAKCLR),a
inc hl
inc hl
ld a,(hl); tinta
ld (FORCLR),a
call CHGCLR
#endasm
}
/*
CALCULDIRXY
*/
int CalculDirXY(unsigned char x, unsigned char y)
{
#asm
ld hl,2
add hl,sp
ld e,(hl)
ld d,0 ; DE=y
inc hl
inc hl ; Ignoramos parte alta ("unsigned char y" se codifica en la pila como un dato de 16 bits)
ld c,(hl)
ld b,0 ; BC=x
call MAPXYC
call FETCHC ; HL=Dirección (A=Máscara del pixel)
ld (_mascaradepixel),a
#endasm
}
/*
GETKEY
*/
unsigned char GetKey(void)
{
#asm
call CHGET
ld l,a
ld h,0 ; HL=Caracter leido
#endasm
}
/*
CLEARSCREEN
*/
void ClearScreen(void)
{
#asm
call CLS
#endasm
}
/*
OFFSCREEN
*/
void OffScreen(void)
{
#asm
call DISSCR
#endasm
}
/*
ONSCREEN
*/
void OnScreen(void)
{
#asm
call ENASCR
#endasm
}
/*
GETKEYROW
*/
unsigned char GetKeyRow(unsigned char numfilateclado)
{
#asm
ld hl,2
add hl,sp
ld a,(hl) ; A=numfilateclado
call SNSMAT
ld l,a
ld h,0 ; HL=Estado de la fila (Bits a 0 -> Tecla pulsada)
#endasm
}
/*
VPOKE
*/
void Vpoke(unsigned int dir, unsigned char dato)
{
#asm
ld hl,2
add hl,sp
ld a,(hl) ; A=dato
inc hl
inc hl
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl ; HL=dir
call WRTVRM
#endasm
}
/*
VPEEK
*/
unsigned char Vpeek(unsigned int dir)
{
#asm
ld hl,2
add hl,sp
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl ; HL=dir
call RDVRM
ld l,a
ld h,0 ; HL=Dato leido
#endasm
}
/*
COPYBLOCKTOVRAM
*/
void CopyBlockToVRAM(unsigned int cantidad, unsigned int dirram, unsigned int dirvram)
{
#asm
ld hl,2
add hl,sp
ld e,(hl)
inc hl
ld d,(hl) ; DE=dirvram
inc hl
push de
ld e,(hl)
inc hl
ld d,(hl) ; DE=dirram
inc hl
ld c,(hl)
inc hl
ld b,(hl) ; BC=cantidad
ex de,hl ; HL=dirram
pop de ; DE=dirvram
call LDIRVM
#endasm
}
/*
COPYBLOCKTORAM
*/
void CopyBlockToRAM(unsigned int cantidad, unsigned int dirvram, unsigned int dirram)
{
#asm
ld hl,2
add hl,sp
ld e,(hl)
inc hl
ld d,(hl) ; DE=dirram
inc hl
push de
ld e,(hl)
inc hl
ld d,(hl) ; DE=dirvram
inc hl
ld c,(hl)
inc hl
ld b,(hl) ; BC=cantidad
ex de,hl ; HL=dirvram
pop de ; DE=dirram
call LDIRMV
#endasm
}
/*
COPYBYTETOVRAM
*/
void CopyByteToVRAM(unsigned char dato, unsigned int cantidad, unsigned int dirvram)
{
#asm
ld hl,2
add hl,sp
ld e,(hl)
inc hl
ld d,(hl) ; DE=dirvram
inc hl
ld c,(hl)
inc hl
ld b,(hl) ; BC=cantidad
inc hl
ld a,(hl) ; A=dato
ex de,hl ; HL=dirvram
call FILVRM
#endasm
}
/*
CLEARALLSPRITES
*/
void ClearAllSprites(void)
{
#asm
call CLRSPR
#endasm
}
/*
LOADPATSPRITES
*/
void LoadPatSprites(unsigned int dirbancgraf)
{
CopyBlockToVRAM(2048,dirbancgraf,TABPATSPR);
}
/*
ERASECOLUMNS
*/
void EraseColumns(unsigned char columns, unsigned char x, unsigned char y) // x,y en baja resolución (32x24) , columns (1-32)
{
unsigned char i;
unsigned int dirpant;
x*=8; y*=8; // x,y se convierten a alta resolución (256x192)
dirpant=CalculDirXY(x,y);
for (i=1; i<=columns; i++) {
CopyByteToVRAM(0x00,8,dirpant);
dirpant+=8;
}
}
/*
PRINTCHAR
*/
void PrintChar(unsigned char x, unsigned char y, unsigned char *dirpatron, unsigned char *diratrib) // x,y en baja resolución (32x24)
{
unsigned char i;
unsigned int dirpant, dirpantatrib;
x*=8; y*=8;
dirpant=CalculDirXY(x,y);
dirpantatrib=TABCOL+dirpant;
for (i=1; i<=8; i++) {
Vpoke(dirpant,*dirpatron);
Vpoke(dirpantatrib,*diratrib);
dirpant++; dirpantatrib++;
dirpatron++; diratrib++;
}
}
/*
PRINTCHARSTR
Coordenadas x,y en baja resolución (32x24), el número de caracteres máximo es 32, y mínimo 1
*/
void PrintCharStr(unsigned char x, unsigned char y, unsigned char numcaract, unsigned char *dircadena, unsigned char *dirbancgraf, unsigned char *diratrib)
{
unsigned char i;
unsigned char *dirpatron;
for (i=1; i<=numcaract; i++) {
dirpatron=dirbancgraf+((*dircadena) * 8 ) ;
PrintChar(x,y,dirpatron,diratrib);
dircadena++;
x++;
}
}
/*
PUTSPRITE
*/
void PutSprite(struct sprite *nombre,unsigned char plano)
{
unsigned int offsetsprite;
offsetsprite=TABATRSPR+(plano*4);
if (nombre->estado==1) {
Vpoke(offsetsprite+PCOORDY,nombre->coordY);
Vpoke(offsetsprite+PCOORDX,nombre->coordX);
Vpoke(offsetsprite+PMODELO,nombre->modelo);
Vpoke(offsetsprite+PCOLOR,nombre->color);
}
}
/*
GETSPRITE
*/
void GetSprite(struct sprite *nombre, unsigned char plano)
{
unsigned int offsetsprite;
offsetsprite=TABATRSPR+(plano*4);
nombre->coordY=Vpeek(offsetsprite+PCOORDY);
nombre->coordX=Vpeek(offsetsprite+PCOORDX);
nombre->modelo=Vpeek(offsetsprite+PMODELO);
nombre->color=Vpeek(offsetsprite+PCOLOR);
}
/*
MOVESPRITE
*/
void MoveSprite(struct velsprite *nombre, unsigned char plano)
{
unsigned char x,y;
unsigned int offsetsprite;
offsetsprite=TABATRSPR+(plano*4);
y=Vpeek(offsetsprite+PCOORDY);
if (y!=209) {
y=y-(nombre->vector_up);
y=y+(nombre->vector_dw);
x=Vpeek(offsetsprite+PCOORDX)-(nombre->vector_lf);
x=x+(nombre->vector_rg);
Vpoke(offsetsprite+PCOORDY,y);
Vpoke(offsetsprite+PCOORDX,x);
}
}
/*
KILLSPRITE
*/
void KillSprite(struct sprite *nombre, unsigned char plano)
{
unsigned int offsetsprite;
offsetsprite=TABATRSPR+(plano*4);
Vpoke(offsetsprite+PCOORDY,209);
nombre->estado=0;
}
/*
SETSPRITEON
*/
void SetSpriteOn(struct sprite *nombre)
{
nombre->estado=1;
}
/*
DELAYTIME ( 1 seg=384 unidades en bucletime, y 1 unidad equivale a 0.0026 seg)
( 65535 unidades=2 min 50 seg)
*/
void DelayTime(unsigned int bucletime)
{
#asm
ld hl,2
add hl,sp
ld c,(hl)
inc hl
ld b,(hl)
.bucledelay
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
dec bc
ld a,b
or c
jr nz,bucledelay
#endasm
}
/*
INITPSG
*/
void InitPSG(void)
{
#asm
call GICINI
#endasm
}
/*
BEEP
*/
void Beep(void)
{
#asm
call BEEPER
#endasm
}
/*
SOUND
*/
void Sound(unsigned char regPSG, unsigned char dato)
{
#asm
ld hl,2
add hl,sp
ld e,(hl) ; E=dato
inc hl
inc hl
ld a,(hl) ; A=regPSG
call WRTPSG
#endasm
}
/*
PLAYMUSIC
*/
void PlayMusic(unsigned char *dircadmusical)
{
#asm
ld hl,2
add hl,sp
ld e,(hl)
inc hl
ld d,(hl) ;
ex de,hl ; HL=dircadmusical
call PLAY
#endasm
}
/*
READJOYSTICK
*/
unsigned char ReadJoystick(unsigned char conectID)
{
#asm
ld hl,2
add hl,sp
ld a,(hl) ; A=conectID
call GTSTCK
ld l,a
ld h,0 ; HL=Estado del joystick
#endasm
}
/*
PUTPIXEL
*/
void PutPixel(unsigned char x, unsigned char y, unsigned char color)
{
unsigned int dirxy, diratrib;
unsigned char realcolor, colorfondo;
dirxy=CalculDirXY(x,y);
diratrib=TABCOL+dirxy;
realcolor=color<<4;
colorfondo=Vpeek(diratrib);
realcolor=realcolor|colorfondo;
Vpoke(dirxy,mascaradepixel);
Vpoke(diratrib,realcolor);
}
*******************************************************************************
Aqui teneis un ejemplo de uso de la librería:
*********************************************
*
FICHERO: PROGMSXDEMO.C
*/
#include <libecalius.c>
extern char bitmap[8], atribmap[8], cadena[5], cadmus[10];
char objeto[]={ 0,0,0,0,0,0,0,0,0,0 };
void main(void)
{
int i;
struct sprite nave;
struct velsprite vel_nave;
struct sprite *p;
struct velsprite *p2;
p=&nave;
p->coordY=0;
p->coordX=0;
p->modelo=0;
p->color=15;
p->estado=1;
p2=&vel_nave;
p2->vector_up=0;
p2->vector_dw=1;
p2->vector_rg=1;
p2->vector_lf=0;
SetColor(WHITE,BLACK,GREEN);
ClearScreen();
GetKey();
SetDisplayMode(2);
CopyByteToVRAM(0xFF,8,TABPATSPR);
while(1) {
PutSprite(p,0);
GetKey();
for (i=1; i<100; i++) {
MoveSprite(p2,0);
DelayTime(250);
Aqu }
GetKey();
KillSprite(p,0);
GetKey();
PutPixel(100,0,RED);
PutPixel(100,2,WHITE);
PutPixel(100,4,CYAN);
Beep();
GetKey();
for (i=1; i<10; i++) {
Sound(7,55);
Sound(6,0);
Sound(8,16);
Sound(11,50);
Sound(12,47);
Sound(13,0);
DelayTime(100);
}
GetKey();
InitPSG();
PlayMusic(cadmus);
SetSpriteOn(p);
}
}
#asm
._bitmap defb 255,255,255,255,255,255,255,255
._atribmap defb 0xF0,0xE0,0xD0,0xC0,0xB0,0xA0,0x90,0x80
._cadena defb 0,0,0,0,0
._cadmus defb '"','C','D','E','F','G','A','B','"',0
#endasm
**********************************************************************
Todo está preparado para el compilador Z88dk. ;-)
Bueno, ni haciendo la librería me vinieron más ganas de programar en MSX.
Ahora he vuelto a coger la segunda quinzena de vacaciones, volví a intentarlo, pero
la verdad no me venía la inspiración, solamente cambié los gráficos del menú
principal y el area de juego.
Y de repente, buscando por internet encuentro un programa llamado "Game Maker",
que va por la versión 8.1, y sirve para desarrollar juegos para la plataforma Windows,
y me lo instalo, comienzo a leerme el tutorial y al cabo de 3 horitas, porque a mi
lo de leer en inglés no se me da muy bien, consigo desarrollar un juego acabado y listo
para empaquetar, y totalmente jugable, ... increíble!!!
Después me doy cuenta, que el programa ha sido utilizado por miles de personas sin saber
programar, y que han sacado videojuegos casi profesionales, y algunos de ellos llevan
como 12000 y pico de descargas.
Aquí acaba mi andadura en los 8 bits, y empieza ahora en PC, espero poder hacerlo con
este programa tan maravilloso, llamado "Game Maker".
Hasta la proxima amigos!!!
P.D.: Que no programe en MSX, no quiere decir que no me ponga mi HitBit-10P y disfrute
de sus juegos de vez en cuando. ;-)
Bye!!!