FASE (Fucking Awesome Spectrum Engine)

Chit chat general. Habla con los MojonTwins y con los amigos de los MojonTwins. Reza a Vah-ka. Delinque. Aviso: está PROHIBIDO tirarse peos fuerte. Si les cortas el pescuezo, vale.

Moderador: na_th_an

antoniovillena
Mensajes: 494
Registrado: Jue, 24 Oct 2013, 15:52

Re: FASE (Fucking Awesome Spectrum Engine)

Mensajepor antoniovillena » Mar, 13 May 2014, 23:38

He hecho unos cambios menores para mejorar la legibilidad, están en el repositorio.
Si no entiendes algo, pregúntamelo. Si ves alguna forma de simplificar código o de hacer lo mismo pero que sea más fácil de entender, dímelo.

Estos serían los ficheros main.c y fase.h

main.c
$this->bbcode_second_pass_code('', '
#include "fase.h"

extern unsigned char *ending;
const unsigned char data[20]= {
0x00, 0x42, 0x11, 0,
0x08, 0x60, 0x60, 2,
0x09, 0x58, 0x48, 3,
0x0a, 0x22, 0x02, 1,
0x0b, 0x50, 0x6e, 2};

char i, j, killed, x, y, spacepressed, dirbul[4], num_bullets;
unsigned char tmpx, tmpy;
void remove_bullet( char k );
void update_screen();
void update_scoreboard();

main(){

start:
killed= x= y= spacepressed= num_bullets= *shadow= 0;
update_scoreboard();

// inicializar engine
INIT;

// pasar datos a sprites y balas
for ( i = 0; i < 5; i++ )
sprites[i].n= data[0 | i<<2],
sprites[i].x= data[1 | i<<2],
sprites[i].y= data[2 | i<<2],
sprites[i].f= data[3 | i<<2];
for ( i = 0; i < 4; i++ )
bullets[i].y= 255;

// mostrar la primera pantalla al comienzo y marcador
*screen= 0;

while(1){

// esto hace que el engine procese un frame generando el escenario
FRAME;

// movimiento de los enemigos
for ( i = 1; i < 5; i++ )
if( sprites[i].n<0x80 ){
for ( j= 0; j < num_bullets; j++ )
if( ( (sprites[i].x<bullets[j].x?bullets[j].x-sprites[i].x:sprites[i].x-bullets[j].x)
+ (sprites[i].y<bullets[j].y?bullets[j].y-sprites[i].y:sprites[i].y-bullets[j].y))<10 ){
sprites[i].n-= 0x80;
remove_bullet( j );
tmpx= sprites[i].x>>4;
tmpy= sprites[i].y>>4;
tiles[tmpy*scrw+tmpx]= 68;
tilepaint(tmpx, tmpy, tmpx, tmpy);
killed++;
if( killed==10 ){
EXIT;
Dzx7b((unsigned int) (&ending-1), 0x5aff);
Pause(100);
goto start;
}
*drwout= (unsigned int)update_scoreboard;
}
if( sprites[i].f&1 )
if( sprites[i].y>0 )
sprites[i].y--;
else
sprites[i].f^= 1;
else
if( sprites[i].y<scrh*16 )
sprites[i].y++;
else
sprites[i].f^= 1;
if( sprites[i].f&2 )
if( sprites[i].x>0 )
sprites[i].x--;
else
sprites[i].f^= 2;
else
if( sprites[i].x<scrw*16 )
sprites[i].x++;
else
sprites[i].f^= 2;
}

// movimiento de las balas
for ( i = 0; i < num_bullets; i++ ){
if( dirbul[i]&3 ){
if( dirbul[i]&1 ){
if( bullets[i].x<scrw*16 )
bullets[i].x+= 2;
else
remove_bullet( i );
}
else{
if( bullets[i].x>2 )
bullets[i].x-= 2;
else
remove_bullet( i );
}
}
if( dirbul[i]&12 ){
if( dirbul[i]&4 ){
if( bullets[i].y<scrh*16 )
bullets[i].y+= 2;
else
remove_bullet( i );
}
else{
if( bullets[i].y>2 )
bullets[i].y-= 2;
else
remove_bullet( i );
}
}
}

// movimiento del protagonista
if( inKey(KeybYUIOP) & 0x01 ){ // P
if( sprites[0].x<scrw*16 )
sprites[0].x++;
else if( x < mapw-1 )
sprites[0].x= 0,
x++,
update_screen();
}
else if( inKey(KeybYUIOP) & 0x02 ){ // O
if( sprites[0].x>0 )
sprites[0].x--;
else if( x )
sprites[0].x= scrw*16,
x--,
update_screen();
}
if( inKey(KeybGFDSA) & 0x01 ){ // A
if( sprites[0].y<scrh*16 )
sprites[0].y++;
else if( y < maph-1 )
sprites[0].y= 0,
y++,
update_screen();
}
else if( inKey(KeybTREWQ) & 0x01 ){ // Q
if( sprites[0].y>0 )
sprites[0].y--;
else if( y )
sprites[0].y= scrh*16,
y--,
update_screen();
}
if( inKey(KeybBNMs_) & 0x01 && !spacepressed && num_bullets<4 ){ // Space
bullets[num_bullets].x= sprites[0].x;
bullets[num_bullets].y= sprites[0].y;
i= inKey(KeybTREWQ)<<3&8 | inKey(KeybGFDSA)<<2&4 | inKey(KeybYUIOP)&3;
dirbul[num_bullets]= i ? i : 1;
num_bullets++;
}
spacepressed= inKey(KeybBNMs_) & 0x01;
}
}

void remove_bullet( char k ){
if( num_bullets ){
num_bullets--;
while ( k<num_bullets )
dirbul[k]= dirbul[k+1],
bullets[k].x= bullets[k+1].x,
bullets[k].y= bullets[++k].y;
bullets[k].y= 255;
}
}

void update_screen(){
*screen= y*mapw + x;
for ( j= 1; j < 5; j++ )
if( sprites[j].n>0x7f )
sprites[j].n-= 0x80;
}

void update_scoreboard(){
unsigned int scr, dst;
char count;
scr= 0x3d80+killed*8;
dst= 0x50de|*shadow<<8;
for ( count= 0; count<8; count++ )
zxmem[dst]= zxmem[scr++]^0xff,
dst+= 0x100;
}

#asm
BINARY "ending.rcs.zx7b"
._ending
#endasm

')

fase.h
$this->bbcode_second_pass_code('', '
#include "define.h"

#define Keyb54321 0xf7
#define KeybTREWQ 0xfb
#define KeybGFDSA 0xfd
#define KeybVCXZc 0xfe
#define Keyb67890 0xef
#define KeybYUIOP 0xdf
#define KeybHJKLe 0xbf
#define KeybBNMs_ 0x7f

#define tilepaint(from_x, from_y, to_x, to_y) *repaint= from_x|from_y<<4|to_x<<8|to_y<<12

#define INIT asm("call 0xfffc")
#define FRAME asm("call 0xfff9")
#define EXIT asm("call 0xfff6")

typedef struct {
unsigned char n;
unsigned char x;
unsigned char y;
unsigned char f;
} SPRITE;

typedef struct {
unsigned char x;
unsigned char y;
} BULLET;

SPRITE *sprites= 0x5b00;
BULLET *bullets= 0x5b30;
unsigned char *tiles= 0x5b40;
unsigned char *screen= 0x5c00;
unsigned char *shadow= 0x5c01;
unsigned int *repaint= 0x5c02;
unsigned int *drwout= 0x5c06;
unsigned char *zxmem= 0;

char __FASTCALL__ inKey ( unsigned char row ){
#asm
ld b, l
ld c, $fe
in a, (c)
cpl
ld l, a
#endasm
}

void __FASTCALL__ Pause ( unsigned int msecs ){
#asm
loop1: ld bc, 21
loop2: djnz loop2
dec c
jr nz, loop2
dec hl
ld a, l
or h
jr nz, loop1
#endasm
}

void __CALLEE__ Dzx7b ( unsigned int source, unsigned int addr ){
#asm
pop af
pop de
pop hl
push af
jp dzx7a
#endasm
}
')
antoniovillena
Mensajes: 494
Registrado: Jue, 24 Oct 2013, 15:52

Re: FASE (Fucking Awesome Spectrum Engine)

Mensajepor antoniovillena » Mié, 14 May 2014, 00:39

Tengo que decir que el compilador Z88DK (versión 1.10) es el más lento de los 3 probados hasta el momento, al menos para la demo. Los otros 2 son SDCC y ZXBasic.

Comprobarlo es muy sencillo, basta con poner el borde a rojo después de FRAME (y a negro antes de FRAME). Podemos observar que se pierden frames usando Z88DK cuando hay 4 sprites y 4 balas a la vez (lo que más consume creo que es la detección de colisiones). Con los otros dos compiladores nunca se pierde un frame, lo más bajo que alcanza la banda roja es más o menos la mitad de la pantalla.

pantalla.png
pantalla.png (32.07 KiB) Visto 7125 veces


Os adjunto los 3 TAPs por si queréis comprobarlo vosotros.
Adjuntos
game_ZXBasic.tap
(20.26 KiB) Descargado 318 veces
game_Z88DK.tap
(20.02 KiB) Descargado 270 veces
game_SDCC.tap
(20.08 KiB) Descargado 309 veces
Avatar de Usuario
radastan
Mensajes: 692
Registrado: Vie, 20 Ago 2010, 12:54
Contactar:

Re: FASE (Fucking Awesome Spectrum Engine)

Mensajepor radastan » Mié, 14 May 2014, 08:07

Te recuerdo que en la última versión (la night build) de Z88DK ya se puede compilar con SDCC. Es decir, supondrá lo mismo.
antoniovillena
Mensajes: 494
Registrado: Jue, 24 Oct 2013, 15:52

Re: FASE (Fucking Awesome Spectrum Engine)

Mensajepor antoniovillena » Mié, 14 May 2014, 09:45

$this->bbcode_second_pass_quote('radastan', 'T')e recuerdo que en la última versión (la night build) de Z88DK ya se puede compilar con SDCC. Es decir, supondrá lo mismo.


Yo me he bajado la última estable. Si quieres probarla tan sólo hay que insertar estas instrucciones para que se vea el borde rojo:

$this->bbcode_second_pass_code('', '
#include <stdlib.h>

...

while(1){

// esto hace que el engine procese un frame generando el escenario
M_OUTP(0xfe, 0);
FRAME;
M_OUTP(0xfe, 2);

// movimiento de los enemigos
')

Y por cierto si cargas las demos en un modelo 128K el frame empieza desde arriba, siendo más intuitivo a la hora de interpretarlo.