SpriteWorks Starter Kit

GFA BASIC-related articles in here please
Post Reply
User avatar
dje
Atari maniac
Atari maniac
Posts: 79
Joined: Sat Apr 08, 2023 10:21 am

SpriteWorks Starter Kit

Post by dje »

I've been testing out the amazing SpriteWorks, but I found it has a steep learning curve compared to other options like LINEA, VDI or STOS. The examples for the sprite routines arn't overly helpful and are filled with "gotcha's". ie: If you modify one variable incorrectly the code will abruptly crash!! :x

So, after working out exactly what is needed for animated sprites and how to implement them in a safe robust way, I though I'd upload a starter kit with the bare bones code to render 16 moving animated sprites. You only need 2 INL files and 7 asm call functions.
"SPRITES.INL" (4 functions) and "WAIT_VBI.INL" (3 functions).

Note: This code does a few things which is not the typical "GFA BASIC style". eg: I load INL at runtime and I calc jump table addresses via a procedure.

This was done to provide robust safely checks to minimize the chances of crashes due to slightly incorrect code.

I also used a different method of defining the sprite records. I used a 2D array which allows for code like this to set sprite positions:

Code: Select all

  sprite(xpos|,a)=RAND(320)
  sprite(ypos|,a)=RAND(200)
Anyway, I could go on and on about what I've learn't. If anyone has any questions, sing out. My main Sprite Works code is essentially the same as this, plus some PI1 image loading and some 16:16 fixed point maths stuff. I just load in a PI1 sprite sheet, grab the frames into animations, and,... that's about it. Everything else is stock standard 2D game programming.

Here is the code in question, so it can be read without download:

Code: Select all

DEFLIST 0
DEFWRD "A-Z"
'
' ** Set this to the path location of STARTER.GFA
' ** Remove it before compiling!
'
' CHDIR "\STARTER"
'
screen.init(16)
'
SETCOLOR 0,0
SETCOLOR 15,&H777
'
animation.init(4,FALSE,16,ball())
FOR i=0 TO 3
  r=2+i*2
  CLS
  DEFFILL 2
  PCIRCLE 8,8,r
  DEFFILL 0
  PCIRCLE 8,8,r\2
  COLOR 6
  CIRCLE 8,8,r
  animation.grab(i,0,0,ball())
NEXT i
'
CLS
FOR i=1 TO 500
  PSET RAND(320),RAND(200),RAND(15)
NEXT i
BMOVE screen%(0),screen%(1),32000
'
sprite.show(0,ball())
sprite.show(1,ball())
sprite.show(2,ball())
sprite.show(3,ball())
sprite.show(4,ball())
sprite.show(5,ball())
sprite.show(6,ball())
sprite.show(7,ball())
sprite.show(8,ball())
sprite.show(9,ball())
sprite.show(10,ball())
sprite.show(11,ball())
sprite.show(12,ball())
sprite.show(13,ball())
sprite.show(14,ball())
sprite.show(15,ball())
'
FOR a=sprite.min TO sprite.max
  sprite(xpos|,a)=RAND(320)
  sprite(ypos|,a)=RAND(200)
NEXT a
'
REPEAT
  FOR a=sprite.min TO sprite.max
    sprite(frame|,a)=sprite(xpos|,a) AND 3
    INC sprite(xpos|,a)
    INC sprite(ypos|,a)
    IF sprite(xpos|,a)>320+16
      SUB sprite(xpos|,a),320+32
    ENDIF
    IF sprite(ypos|,a)>200+16
      SUB sprite(ypos|,a),200+32
    ENDIF
  NEXT a
  screen.swap
UNTIL LEN(INKEY$)
'
screen.done
'
END
'
' ---------------------------------------------------------------------------
'
PROCEDURE screen.init(count)
  library("sprites.inl",sprites%())
  '
  extern(1,sprites%(),print_sprites%)
  extern(2,sprites%(),erase_sprites%)
  extern(3,sprites%(),clip_sprites%)
  extern(9,sprites%(),store_sprite%)
  '
  library("wait_vbi.inl",wait_vbi%())
  '
  extern(0,wait_vbi%(),counter_on%)
  extern(1,wait_vbi%(),counter_off%)
  extern(3,wait_vbi%(),swap_sync%)
  '
  LOCAL a
  CLS
  HIDEM
  SPOKE &H484,BCLR(PEEK(&H484),0)
  '
  sprite.min=0
  sprite.max=PRED(count)
  sprite.count=count
  '
  mode|=0
  animation|=1
  frame|=3
  xpos|=4
  ypos|=5
  width|=6
  height|=7
  size|=8
  buffer_1|=9
  buffer_2|=11
  '
  DIM sprite(12,sprite.max)
  DIM screen.buffer|(2320,1,sprite.max)
  DIM screen.double|(32256),screen%(2)
  '
  FOR a=sprite.min TO sprite.max
    {V:sprite(buffer_1|,a)}=V:screen.buffer|(0,0,a)
    {V:sprite(buffer_2|,a)}=V:screen.buffer|(0,1,a)
  NEXT a
  '
  screen%(0)=(V:screen.double|(0)+&HFF) AND NOT &HFF
  screen%(1)=XBIOS(3)
  screen%(2)=screen%(1)
  screen.oldrez=XBIOS(4)
  '
  ~XBIOS(5,L:screen%(0),L:screen%(1),0)
  '
  bc(clip_sprites%)
  ~C:clip_sprites%(0,0,319,199)
  bc(counter_on%)
  ~C:counter_on%()
  '
  ON BREAK GOSUB screen.break
  ON ERROR GOSUB screen.error
RETURN
'
PROCEDURE screen.done
  bc(counter_off%)
  ~C:counter_off%()
  ~XBIOS(5,L:screen%(2),L:screen%(2),screen.oldrez)
RETURN
'
PROCEDURE screen.error
  screen.done
  ~FORM_ALERT(1,ERR$(ERR))
  END
RETURN
'
PROCEDURE screen.break
  screen.done
  END
RETURN
'
PROCEDURE screen.swap
  bc(erase_sprites%)
  ~C:erase_sprites%(sprite.count,L:V:sprite(0,0))
  bc(print_sprites%)
  ~C:print_sprites%(sprite.count,L:V:sprite(0,0),L:screen%(0))
  SWAP screen%(0),screen%(1)
  bc(swap_sync%)
  ~C:swap_sync%(1,L:screen%(0),L:screen%(1))
RETURN
'
PROCEDURE animation.init(frames,width!,height,VAR a())
  frames=MIN(MAX(frames,1),16)
  height=MIN(MAX(height,1),48)
  DIM a(3+SHL(5,width! AND 1)*height*frames)
  a(0)=width! AND 1
  a(1)=height
  a(2)=SHL(10,width! AND 1)*height
  a(3)=frames
RETURN
'
PROCEDURE animation.grab(frame,x,y,VAR a())
  LOCAL w
  IF frame>=0 AND frame<a(3)
    x=SHL(x,4)
    w=SHL(16,(a(0)<>0) AND 1)
    bc(store_sprite%)
    ~C:store_sprite%(frame,x,y,w,a(1),L:V:a(4),L:screen%(0))
  ENDIF
RETURN
'
PROCEDURE sprite.show(a,VAR a())
  sprite(mode|,a)=1
  sprite(width|,a)=a(0)
  sprite(height|,a)=a(1)
  sprite(size|,a)=a(2)
  {V:sprite(animation|,a)}=V:a(4)
RETURN
'
PROCEDURE sprite.hide(a)
  sprite(mode|,a)=0
RETURN
'
PROCEDURE library(filename$,VAR library%())
  OPEN "I",#1,filename$
  DIM library%(SHR(LOF(#1),2))
  BGET #1,V:library%(0),LOF(#1)
  CLOSE #1
RETURN
'
PROCEDURE extern(index,VAR library%(),extern%)
  IF extern%<>0
    ERROR -36
  ENDIF
  extern%=V:library%(index)
  bc(extern%)
RETURN
'
PROCEDURE bc(VAR a%)
  IF a%=0
    ERROR 9
  ENDIF
  IF DPEEK(a%)<>&H6000
    ERROR 9
  ENDIF
RETURN
'
END
You do not have the required permissions to view the files attached to this post.
Atari STE 4160 / OMIKRON.BASIC 4.08
User avatar
Mug UK
Administrator
Administrator
Posts: 12304
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Re: SpriteWorks Starter Kit

Post by Mug UK »

Nice one. I bought but barely used the Sprite Works except for the mouse menu selector in Synthetic Dreams demo.
Main site: www.mug-uk.co.uk - digging up bits from my past: Atari ST, ZX Spectrum, Sega 8-bit (game hacks) and NDS (ripping guides). I host a C64 Radio Show for a mate, Max Hall via www.chipsidshow.co.uk

I develop a free Word (for Windows) add-in for Word 2007 upwards. A toolbox that will allow power Word users to fix document errors. You can find it at: mikestoolbox.co.uk
stormy
Atari God
Atari God
Posts: 1756
Joined: Tue Jan 26, 2016 12:39 pm

Re: SpriteWorks Starter Kit

Post by stormy »

Hi dje,

Since you seem very keen investigating lots of programming lately, have you seen or heard of dml's 'AGT' Atari game tools? It's designed for rapid prototyping of Atari STe games. It's the most comprehensive tool ever released to take advantage of all the hardware, recently a guy called masteries ported the first level of Metal Slug over with it!

I wonder if you might look:
https://bitbucket.org/d_m_l/agtools/src/master/
https://bitbucket.org/d_m_l/agtools/wiki/Tutorials
viewtopic.php?t=31558
User avatar
dje
Atari maniac
Atari maniac
Posts: 79
Joined: Sat Apr 08, 2023 10:21 am

Re: SpriteWorks Starter Kit

Post by dje »

stormy wrote: Fri Apr 28, 2023 9:03 pm Hi dje,

Since you seem very keen investigating lots of programming lately, have you seen or heard of dml's 'AGT' Atari game tools? It's designed for rapid prototyping of Atari STe games. It's the most comprehensive tool ever released to take advantage of all the hardware, recently a guy called masteries ported the first level of Metal Slug over with it!

I wonder if you might look:
Yep, I've seen AGT. I'm sure its amazing, but ATM I enjoy using older dev tools on a 512kb machine. I enjoy the constraints. Plus, I get a little bit excited using all the software I didn't have as a teenager. I find it interesting to see what could be achieved.
Atari STE 4160 / OMIKRON.BASIC 4.08
User avatar
dje
Atari maniac
Atari maniac
Posts: 79
Joined: Sat Apr 08, 2023 10:21 am

Re: SpriteWorks Starter Kit

Post by dje »

Mug UK wrote: Fri Apr 28, 2023 8:11 pm Nice one. I bought but barely used the Sprite Works except for the mouse menu selector in Synthetic Dreams demo.
Yea, I was a little overwhelmed by Sprite Works. Considering it was marketed as a "sprite" solution, it didn't seem to focus on providing simple sprite examples.

There isn't much info about store_sprite() which is IMHO, highly important for learning. ie: being able to grab a sprite off the screen. The editor is just too difficult to work with and I'm guessing a lot of people would want to create sprites in degas, or neochrome, then load and grab. I think most GFA coders learn to load PI1/NEO files pretty early.

The SW sprites examples also have extremely fragile sprite erase buffer allocations. In reality, the largest sprite is 32*48, which requires 2320*2 bytes of erase memory. ie: ~4K per sprite. So, its easier just to allocate the full amount per sprite and optimize later. That way you can develop without fear of overwriting the buffers. That's what this line is: Yes, its 32K for 8 sprites, but who cares when your'e developing.

Code: Select all

DIM screen.buffer|(2320,1,sprite.max)
I also prefer the library()/extern() functions in my code. extern() ensures you are 1) using a long to store addresses and 2) referencing a valid jump address.
The procedure bc() or "before call" is just a double check mechanism. ie: it checks for NULL pointers and invalid jumps.
bc() was chosen because it lines up with the ~c: command, so you can eye ball the variable name to confirm its correct.

Anyway, I hope it helps anyone. GFA and SpriteWorks is way ahead of STOS, but I think the complexity of these solutions didn't help take up.

On the topic of complexity, MAGE gave me headaches!

EDIT: I must have been half asleep when I coded all those sprite.show() commands! Yes, a for/next loop should have been used. :roll:
Last edited by dje on Sat Apr 29, 2023 12:05 am, edited 5 times in total.
Atari STE 4160 / OMIKRON.BASIC 4.08
simonsunnyboy
Forum Administrator
Forum Administrator
Posts: 5834
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: SpriteWorks Starter Kit

Post by simonsunnyboy »

Nice job. I once tried understanding the sprite system but gave up and then I programmed my own.
Though only one GFABASIC game made it with that sprite system in place, "Attackwave"

However my routines are now also available for gcc and PurC/AHCC aswell.
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee
IntoTheVerticalBlank
Retro freak
Retro freak
Posts: 10
Joined: Tue Sep 26, 2023 4:30 pm

Re: SpriteWorks Starter Kit

Post by IntoTheVerticalBlank »

Amazing. Thank you!!
User avatar
dje
Atari maniac
Atari maniac
Posts: 79
Joined: Sat Apr 08, 2023 10:21 am

Re: SpriteWorks Starter Kit

Post by dje »

IntoTheVerticalBlank wrote: Thu Oct 03, 2024 3:03 am Amazing. Thank you!!
Cool. Since writing this, I did find the method doesn't upscale to scrolling maps. The print_sprites()/erase_sprites() system is kinda difficult to get working due to its individual double buffers for each sprite. ie: Getting buffer sizes wrong can lead to major headaches.

After playing with print_sprites()/erase_sprites(), I couldn't workout scrolling, until I realized, the sprite works scrolling demos _don't_ use print_sprites()/erase_sprites(). They use individual print_sprite() commands which don't require back buffers, since it is expected that the entire screen is to be redrawn via the mappers, or a simple SPUT.

Which simplifies everything! Only one SPRITES.INL command is actually needed for most games IMHO. print_sprite()

store_sprite() can be incorporated into a game dev tool which pre-converts a PI1 to a sprite set file.

My overall feeling now is just use individual print_sprite() commands. The only time I think there would be an issue, if for games with lots of sprites. ie: asterioids or a space shooter. Which would be improved by using the fast_sprite() command since, space shooters don't tend to have lots of animations.

After I tried fast_sprite(), it was obvious the double buffered sprite routines in print_sprites()/erase_sprites() don't really have much use. Too complex for their own good.

Maybe someone has a different take on this.
Atari STE 4160 / OMIKRON.BASIC 4.08
Post Reply

Return to “GFA BASIC”