Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fucking Awesome Spectrum Engine (FASE)
#1
Hi

We are writing an engine (sprites, tiles, maps) and I would like to interface with ZX Basic. The main thread is here (sorry, it's in spanish)

http://www.mojontwins.com/mojoniaplus/vi...f=9&t=1461

Now the engine is in alpha stage and there is a SDCC working demo. This is the code:

Code:
#include  "bunuelera.h"

const unsigned char data[32]= {
  0x00, 0x42, 0x11, 0,
  0x08, 0x60, 0x60, 2,
  0x09, 0xa8, 0x48, 3,
  0x0a, 0x22, 0x02, 1,
  0x0b, 0xd0, 0x6e, 2,
  0x0c, 0xb6, 0x34, 3,
  0x0d, 0x32, 0x32, 1,
  0x04, 0x52, 0x5e, 0};

int main(){

  // variables
  int i, x= 0, y= 0;

  // pasar personajes a sprites
  for ( i = 0; i < 32; i++ )
    sprites[i>>2][i&3]= data[i];

  // inicializar engine
  INIT;

  // mostrar la primera pantalla al comienzo
  screen= 0;

  while(1){

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

    // movimiento de los enemigos
    for ( i = 1; i < 8; i++ ){
      if( sprites[i][3]&1 )
        if( sprites[i][2] )
          sprites[i][2]--;
        else
          sprites[i][3]^= 1;
      else
        if( sprites[i][2]<0x90 )
          sprites[i][2]++;
        else
          sprites[i][3]^= 1;
      if( sprites[i][3]&2 )
        if( sprites[i][1]>0x08 )
          sprites[i][1]--;
        else
          sprites[i][3]^= 2;
      else
        if( sprites[i][1]<0xe8 )
          sprites[i][1]++;
        else
          sprites[i][3]^= 2;
    }

    // movimiento del protagonista
    if( ~KeybYUIOP & 0x01 ){ // P
      if( sprites[0][1]<0xee )
        sprites[0][1]++;
      else if( x < 11 )
        sprites[0][1]= 0x02,
        screen= y*12 + ++x;
    }
    else if( ~KeybYUIOP & 0x02 ){ // O
      if( sprites[0][1]>0x02 )
        sprites[0][1]--;
      else if( x )
        sprites[0][1]= 0xee,
        screen= y*12 + --x;
    }
    if( ~KeybGFDSA & 0x01 ){ // A
      if( sprites[0][2]<0xa0 )
        sprites[0][2]++;
      else if( y < 1 )
        sprites[0][2]= 0x01,
        screen= ++y*12 + x;
    }
    else if( ~KeybTREWQ & 0x01 ){ // Q
      if( sprites[0][2]>0x01 )
        sprites[0][2]--;
      else if( y )
        sprites[0][2]= 0xa0,
        screen= --y*12 + x;
    }
  }
}

My idea is to traslate this code to ZX Basic. The engine set ups a runtime enviroment that leave between 24K and 30K bytes free from $8000 address. Basically there are 2 routines to call: INIT to initialize the engine and FRAME, that put all the stuff in the screen every frame. With this engine you can move between 8 and 16 sprites flicker free at 50fps in 48K and all 128K models. The engine has diferent implementation for each machine (floating bus in 48K, shadow screen in 128K) so the comunication is done by accessing to next memory locations:

Code:
5b00      number of screen to paint
5b01-5b96 tiles codes of actual screen
5bfe-5bff set to repaint a rectangular area of tiles
5c00-5c3f sprite info, where
    5c00-5c02 first sprite
        5c00  sprite number, set high bit to disable
        5c01  X coord
        5c02  Y coord
    5c04-5c06 second sprite
    ...

More info in the first message of the linked thread

Regards

-----------

Buenas, estamos escribiendo un engine de sprites, tiles y mapas y me gustaría poder usar dicho engine con ZX Basic. En el hilo que enlazo arriba está todo explicado en español. No tengo mucha idea sobre ZX Basic, pero veo que hay una comunidad detrás y me gustaría que me ayudaran a traducir la demo de C a Basic.

Saludos
Reply
#2
Hi, Antonio!

This is, in fact, *fucking awesome* :!:
Please, stand by me Smile
Cuenta conmigo!! Smile
Reply
#3
Thank you very much

I am looking the bitfrost engine interface. The main 2 calls can be easy done by:

Code:
#define INIT        \
    asm             \
        call $fffc  \
    end asm

#define FRAME       \
    asm             \
        call $fff1  \
    end asm

But in the rest of the code I don't know if make a subroutine or a #define with a POKE.
Reply
#4
antoniovillena Wrote:Thank you very much

I am looking the bitfrost engine interface. The main 2 calls can be easy done by:

Code:
#define INIT        \
    asm             \
        call $fffc  \
    end asm

#define FRAME       \
    asm             \
        call $fff1  \
    end asm

But in the rest of the code I don't know if make a subroutine or a #define with a POKE.
For a single Poke, #define is MUCH faster, because it acts as an inline function.
You can also use SUB/Function FASCALL <name>(param) for asm functions, if they are a bit more complicated.
Reply
#5
Hi

I have made some advances in the BASIC code. The demo is functional but not complete, I don't know how to manage the keyboard.

I uploaded a file with all necessary files except SjAsmPlus.exe (download it from http://sourceforge.net/projects/sjasmplus/) because 256K file size restriction in the forum. Also change "set _lang=c" to "set _lang=basic" in the second line on makeBu.bat and correct the path of some utilities.

When you execute makeBu.bat and all works correctly you have the generated file "game.tap", try it on any ZX Spectrum emulator.


Attached Files
.zip   FASE.0.10.zip (Size: 253.17 KB / Downloads: 977)
Reply
#6
Wow! How fast! Confusedhock:
There is already a simple IN (multikeyboard) library management in the standard /library/ directory (see https://github.com/boriel/zxbasic/blob/v...y/keys.bas).

You can use it with:
Code:
#include <keys.bas>

While 1 Do
    IF multikeys(KEYB) THEN PRINT "B Pressed" : End IF
    IF multikeys(KEYA) THEN PRINT "A Pressed" : End IF
    REM etc... etc...
End While
These routine detects several keys pressed at once (beware, there are some hardware limitations on the ZX Spectrum keyboard).
KEYB, KEYA, etc... are constants defined in the previous source code.
Reply
#7
Thank you. Now it's almost done.

Unfortunately the demo only shows 6 of the 7 enemies, so I have debugged the Z80 code and found a word write to $5c0b. This position is the DEFADD variable of the 48 ROM. So, is there any way of disable writing to internal variables?

Code:
#include <keys.bas>
#include "fase.bas"

  DisableInt

  DIM datos(31) as UBYTE = { _
    $00, $42, $11, 0, _
    $08, $60, $60, 2, _
    $09, $a8, $48, 3, _
    $0a, $22, $02, 1, _
    $0b, $d0, $6e, 2, _
    $0c, $b6, $34, 3, _
    $0d, $32, $32, 1, _
    $04, $52, $5e, 0 }

  DIM i, x, y AS UBYTE

  FOR i = 0 TO 31
    SETSPRITE(i>>2, i&3, datos(i))
  NEXT i

  INIT

  SETSCREEN(0)

  WHILE 1

    FRAME

    FOR i = 1 TO 8
      IF GETSPRITE(i, 3) & 1 THEN
        IF GETSPRITE(i, 2) > 0 THEN
          SETSPRITE(i, 2, GETSPRITE(i, 2)-1)
        ELSE
          SETSPRITE(i, 3, GETSPRITE(i, 3) bXOR 1)
        END IF
      ELSE
        IF GETSPRITE(i, 2) < $90 THEN
          SETSPRITE(i, 2, GETSPRITE(i, 2)+1)
        ELSE
          SETSPRITE(i, 3, GETSPRITE(i, 3) bXOR 1)
        END IF
      END IF
      IF GETSPRITE(i, 3) & 2 THEN
        IF GETSPRITE(i, 1) > $08 THEN
          SETSPRITE(i, 1, GETSPRITE(i, 1)-1)
        ELSE
          SETSPRITE(i, 3, GETSPRITE(i, 3) bXOR 2)
        END IF
      ELSE
        IF GETSPRITE(i, 1) < $e8 THEN
          SETSPRITE(i, 1, GETSPRITE(i, 1)+1)
        ELSE
          SETSPRITE(i, 3, GETSPRITE(i, 3) bXOR 2)
        END IF
      END IF
    NEXT i

    IF multikeys(KEYP) THEN
      IF GETSPRITE(0, 1) < $ee THEN
        SETSPRITE(0, 1, GETSPRITE(0, 1)+1)
      ELSEIF x < 11 THEN
        SETSPRITE(0, 1, $02)
        x= x + 1
        SETSCREEN(y*12 + x)
      END IF
    END IF
    IF multikeys(KEYO) THEN
      IF GETSPRITE(0, 1) > $02 THEN
        SETSPRITE(0, 1, GETSPRITE(0, 1)-1)
      ELSEIF x > 0 THEN
        SETSPRITE(0, 1, $ee)
        x= x - 1
        SETSCREEN(y*12 + x)
      END IF
    END IF
    IF multikeys(KEYA) THEN
      IF GETSPRITE(0, 2) < $a0 THEN
        SETSPRITE(0, 2, GETSPRITE(0, 2)+1)
      ELSEIF y < 1 THEN
        SETSPRITE(0, 2, $01)
        y= y + 1
        SETSCREEN(y*12 + x)
      END IF
    END IF
    IF multikeys(KEYQ) THEN
      IF GETSPRITE(0, 2) > $01 THEN
        SETSPRITE(0, 2, GETSPRITE(0, 2)-1)
      ELSEIF y > 0 THEN
        SETSPRITE(0, 2, $a0)
        y= y - 1
        SETSCREEN(y*12 + x)
      END IF
    END IF

  END WHILE
Reply
#8
antoniovillena Wrote:Thank you. Now it's almost done.

Unfortunately the demo only shows 6 of the 7 enemies, so I have debugged the Z80 code and found a word write to $5c0b. This position is the DEFADD variable of the 48 ROM. So, is there any way of disable writing to internal variables?
Not yet, but will be available as an option, as many others.
I put it in the TODO queue.
Reply
#9
Please help. I have this code in C:

Code:
void *Input;  // function pointer declare

...

/* function pointer assign */
  while ( 1 ){
    i= inp(0xf7fe) & 0x1f;
    if( i==0x1e ){
      Input= Joystick;
      break;
    }
    else if( i==0x1d ){
      Input= Cursors;
      break;
    }
    else if( i==0x1b ){
      Input= Keyboard;
      break;
    }
    else if( i==0x17 ){
      Redefine();
    }
  }

...

  if( Input() & RIGHT ) // function pointer call
    ax= vx<maxvx ? 40 : 0;

I want to do something similar in ZX Basic. I know that ZX Basic has not function pointers, but I think that you can find another good solution.
Reply
#10
Awesome !!

It will be fantastic to use FASE with Zx basic !! Big Grin Big Grin
Reply
#11
JBGV Wrote:Awesome !!

It will be fantastic to use FASE with Zx basic !!  Big Grin  Big Grin

Now It's done. Download package here:

http://www.mojontwins.com/mojoniaplus/do...hp?id=5144
Reply
#12
Wow! Confusedhock: Confusedhock:

I have to study this to see how to use it in a game.


Enhorabuena por el trabajo tan enorme !!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)