Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 00:55 11 Nov 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Micromite eXtreme: Sprite magic

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10569
Posted: 07:14pm 03 Feb 2018
Copy link to clipboard 
Print this post



Check the video

Here is the very simple code

option explicit
option default none
cls
load image "tiger640"
sprite load 1,"apple"
sprite load 2,"apple"
dim float x1,y1,x2, y2, i
box 8,98,304,304,2
box 328,98,304,304,2
sprite show 1,200,200,1
sprite show 2,450,200,1
do
for i=0 to PI*2-pi/50 step PI/50
x1=sin(i)*100+160-sprite(w,2)\2
y1=cos(i)*100+250-sprite(h,2)\2
x2=sin(i)*100+480-sprite(w,2)\2
y2=-cos(i)*100+250-sprite(h,2)\2
sprite next 1,x1,y1
sprite next 2,x2,y2
sprite scrollr 10,100,300,300,1,1
sprite scrollr 330,100,300,300,-1,-1
next i
loop


I need to do some tidying and documenting before I release the firmware but hopefully this meets the needs of the "scrolling region" advocates.

The firmware also now includes the ability to scroll an area or the complete screen without "wrapping" the picture and allows the user to specify what colour should fill the vacated area.

The SCROLL NEXT command is new and specifies where the sprite will move to when the next scroll command occurs. This makes the scroll and move a single atomic action so as seen in the video there are absolutely no tearing effects
Edited by matherp 2018-02-05
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2463
Posted: 09:12pm 03 Feb 2018
Copy link to clipboard 
Print this post

peter, this looks really impressive

is there any chance you could post the syntax of the SPRITE, BLIT, and other related functions? just the extract from the manual would suffice.

is it possible that SPRITE may end up rendering BLIT redundant, or that the functionality of both could be rolled into the one function?

i notice you have load image... and sprite load.... could the syntax perhaps be tweaked to instead use LOAD sprite...?

also, i assume you are still using double buffering? could the need for this be avoided by having graphics commands queued (internally) and only executed during the VBI? just an idea i had floating round in the back of my mind.


cheers,
rob :-)
 
Azure

Guru

Joined: 09/11/2017
Location: Australia
Posts: 446
Posted: 10:02am 04 Feb 2018
Copy link to clipboard 
Print this post

  robert.rozee said  i notice you have load image... and sprite load.... could the syntax perhaps be tweaked to instead use LOAD sprite...?


That would mean the syntax for the other "sprite <subcommand> <parameters>" would be inconsistent.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10569
Posted: 02:52pm 04 Feb 2018
Copy link to clipboard 
Print this post

Slowly working though the bugs. Another demo this time showing collision detection. Note how the centre of the screen flashes with a block coloured to indicate which sprites collided.

To get the performance all the manipulations of graphics data have been converted from bit-based to word-based. This has much more convoluted logic for things like handling the sprites when partially off the screen when each colour in the sprite can appear anywhere across a number of words in memory.

  Quote  i notice you have load image... and sprite load.... could the syntax perhaps be tweaked to instead use LOAD sprite...?


I've enabled both

  Quote  is it possible that SPRITE may end up rendering BLIT redundant, or that the functionality of both could be rolled into the one function?


SPRITE and BLIT are synonyms with identical functionality. Some commands make more sense as a BLIT (e.g. scrolling" ) and some as a SPRITE (e.g. "showing")


  Quote  is there any chance you could post the syntax of the SPRITE, BLIT, and other related functions? just the extract from the manual would suffice.


I'm still tweaking syntax as I work more with the code so don't want to release anything yet.

Code for this demo

option explicit
option default none
cls
load image "tiger640"
load sprite 1,"apple"
load sprite 2,"apple"
load sprite 3,"apple"
load sprite 4,"apple"
dim float x1,y1,x2, y2, i, crash=0
box 8,98,304,304,2
box 328,98,304,304,2
sprite show 3,170,200,1
sprite show 1,200,200,2
sprite show 2,450,200,1
sprite show 4,400,200,2
blit read 5, 310,240,20,30
do
for i=0 to PI*2-pi/50 step PI/50
x1=sin(i)*230+220-sprite(w,2)\2
y1=cos(i)*230+250-sprite(h,2)\2
x2=sin(i)*230+420-sprite(w,2)\2
y2=-cos(i)*230+250-sprite(h,2)\2
sprite next 1,x1,y1
sprite next 2,x2,y2
' sprite move
sprite scrollr 10,100,300,300,2,2
if sprite(s)<>-1 and crash=0 then
if sprite(c,0,1)=1 then box 311,241,18,18,,rgb(red),rgb(red)
if sprite(c,0,1)=2 then box 311,241,18,18,,rgb(blue),rgb(blue)
timer=0
crash=1
endif
if sprite(s) = -1 and crash = 1 and timer > 500 then
blit write 5,310,240
crash=0
endif
sprite scrollr 330,100,300,300,-2,-2
next i
loop


Background and sprite

2018-02-05_005226_apple.zip Edited by matherp 2018-02-06
 
IanT

Senior Member

Joined: 29/11/2016
Location: United Kingdom
Posts: 115
Posted: 04:38pm 05 Feb 2018
Copy link to clipboard 
Print this post

Do you ever sleep Peter?

Regards, IanT
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10569
Posted: 04:51pm 05 Feb 2018
Copy link to clipboard 
Print this post

The scrolling region capability also works nicely on the SSD1963 to create a real time chart



Watch another boring video here

Again the new functionality makes the code very simple and I hope I'm getting to the end of the bugs - found another bizarre one this morning - right hand end of a sprite not displaying when left hand x coordinate satisfies x= 16+ n*32

const scrollxstart=100, scrollxwidth=280,newpoint=scrollxstart+scrollxwidth-2
const scrollystart=20,scrollyheight=232, scrolldirection=0
dim integer i, j, rp=130, bp=100, yp=160, wp=190, cp=70, xp=40, zp=220
cls
text scrollxstart+scrollxwidth\2,0,"Micromite eXtreme V5.4.13 with SSD1963",C,1,,rgb(white),rgb(black)
text newpoint+16,scrollystart-13+(scrollyheight\2),"Fixed",,2,,rgb(green),rgb(black)
text newpoint+16,scrollystart+13+(scrollyheight\2),"Area",,2,,rgb(green),rgb(black)
text 10,scrollystart-13+(scrollyheight\2),"Fixed",,2,,rgb(green),rgb(black)
text 10,scrollystart+13+(scrollyheight\2),"Area",,2,,rgb(green),rgb(black)
text scrollxstart+scrollxwidth\2,scrollystart+scrollyheight+5,"Demonstration of scrolling data",C,1,,rgb(white),rgb(black)
BOX scrollxstart-1,scrollystart-1,scrollxwidth+2, scrollyheight+2,1,rgb(white),rgb(gray)
do
' scroll an area defined by the x-y coordinates of the top left point
' the width of the area to be scrolled
' the height of the are to be scrolled
' the scroll driection
' define the colour of the scroll background
rp=nextpos(rp)'get the new data points
bp=nextpos(bp)
yp=nextpos(yp)
xp=nextpos(xp)
zp=nextpos(zp)
wp=nextpos(wp)
cp=nextpos(cp)
box newpoint,xp,2,2,1,rgb(yellow) 'write them to the space left
box newpoint,rp,2,2,1,rgb(blue)
box newpoint,yp,2,2,1,rgb(red))
box newpoint,bp,2,2,1,rgb(green)
box newpoint,wp,2,2,1,rgb(magenta)
box newpoint,cp,2,2,1,rgb(cyan)
box newpoint,zp,2,2,1,rgb(white))
blit scrollr scrollxstart,scrollystart,scrollxwidth,scrollyheight,-2,0,rgb(gray)
loop
'
function nextpos(d as integer) as integer
nextpos=d+(rnd()*4)-2
if nextpos<=scrollystart then nextpos=scrollystart+1
if nextpos>=scrollystart+scrollyheight then nextpos=scrollystart+scrollyheight-1
end function


Here is the current SPRITE/BLIT syntax

  Quote  

SPRITE/BLIT COMMANDS
The BLIT and SPRITE commands can be used interchangeably. The command is only available on VGA, SSD1963 (pin RD must be connected and specified) and ILI9341 (SPI-IN must be connected) displays

SPRITE x1, y1, x2, y2, w, h
Copies the memory area specified by top right coordinate x1, y1 and of width w and height h to a new location where the top right coordinate is x2, y2.

SPRITE CLOSE {#}n
Closes sprite n and releases all memory resources. Updates the screen (see SPRITE HIDE). Sprites which have been “copied” cannot be closed until all “copies” have been closed

SPRITE COPY {#}n, {#}m, nbr
Makes a copy of sprite “n” to “nbr” of new sprites starting a number “m”. Copied sprites share the same loaded image as the original to save memory

SPRITE HIDE {#}n
Removes sprite n from the display and replaces the stored background. To restore a screen to a previous state sprites should be hidden in the opposite order to which they were written "LIFO"

SPRITE INTERRUPT sub
Specifies the name of the subroutine that will be called when a sprite collision occurs. See Appendix C for how to use the function SPRITE to interrogate details of what has collided

SPRITE LOAD {#}n, fname$ {,colour}
Loads the file fname$ as a sprite into buffer number n. The file must be in PNG format RGB888 or RGBA888. If the file extension .PNG is omitted then it will be automatically added. The parameter “colour” specifies the background colour for the sprite. Pixels in the background colour will not overwrite the background when the sprite is displayed. Colour defaults to zero

SPRITE MOVE
Actions a single atomic transaction that re-locates all sprites which have previously had a location change set up using the SPRITE NEXT command. Collisions are detected once all sprites are moved and reported in the same way as from a scroll

SPRITE NEXT {#}n, x, y
Sets the X and Y coordinate of the sprite to be used when the screen is next scrolled or the SPRITE MOVE command is executed. Using SPRITE NEXT rather than SPRITE SHOW allows multiple sprites to be moved as part of the same atomic transaction.

SPRITE NOINTERRUPT
Disables collision interrupts

SPRITE READ {#}n, x , y, w, h
Reads the display area specified by coordinates x and y, width w and height h into buffer number n. If the buffer is already in use and the width and height of the new area are the same as the original then the new command will overwrite the stored area.

SPRITE SCROLLH n {,col}
Scrolls the background and any sprites on layer 0 n pixels to the right. n can be any number between -31 and 31. Sprites on any layer other than zero will remain fixed in position on the screen. By default the scroll wraps the image round. If “col” is specified the colour will replace the area behind the scrolled image

SPRITE SCROLLR x, y, w, h, delta_x, delta_y {,col}
Scrolls the region of the screen defined by top-right coordinates “x” and “y” and width and height “w” and “h” by “delta_x” pixels to the right and “delta_y” pixels up. By default the scroll wraps the background image round. If “col” is specified the colour will replace the area behind the scrolled image. Sprites on any layer other than zero will remain fixed in position on the screen. Sprites in layer zero where the centre of the sprite (x+ w/2, y+ h/2) falls within the scrolled region will move with the scroll and wrap round if the centre moves outside one of the boundaries of the scrolled region.

SPRITE SCROLLV n {,col}
Scrolls the background, and any sprites on layer 0, n pixels up. n can be any number between -MM.VRES-1 and MM.VRES-1. Sprites on any layer other than zero will remain fixed in position on the screen. . By default the scroll wraps the image round. If “col” is specified the colour will replace the area behind the scrolled image

SPRITE SHOW {#}n, x, layer
Displays sprite n on the screen with the top left at coordinates x, y. Sprites will only collide with other sprites on the same layer, layer zero, or with the screen edge. If a sprite is already displayed on the screen then the SPRITE SHOW command acts to move the sprite to the new location. The display background is stored as part of the command such that it can be replaced when the sprite is hidden or moved further.

SPRITE SWAP {#}n, {#}m
Replaces the sprite number n with number m. The sprites must be the same width and height. Sprite "n" must be currently active(displayed) and sprite "m" must be inactive "hidden". This command is highly optimised to minimise overhead and allow fast effects like animation.

SPRITE WRITE {#}n, x y
Overwrites the display with the contents of sprite buffer n with the top left at coordinates x, y. SPRITE WRITE overwrites the complete area of the display. The background that is overwritten is not stored so SPRITE WRITE is inherently higher performing than SPRITE SHOW but with greater functional limitations.

SPRITE/BLIT FUNCTIONS
The BLIT and SPRITE functions can be used interchangeably. The function is only available on VGA, SSD1963 (pin RD must be connected and specified) and ILI9341 (SPI-IN must be connected) displays

SPRITE(C, {#}n )
Returns the number of currently active collisions for sprite n. If n=0 then returns the number of sprites that have a currently active collision following a SPRITE SCROLL command

SPRITE(C, {#}n, m)
Returns the number of the sprite which caused the “m”th collision of sprite n. If n=0 then returns the sprite number of “m”th sprite that has a currently active collision following a SPRITE SCROLL command

SPRITE(H,{#}n)
Returns the height of sprite n. This function is active whether or not the sprite is currently displayed (active).

SPRITE(L, {#}n)
Returns the layer number of active sprites number n

SPRITE(N)
Returns the number of displayed (active) sprites

SPRITE(N,n)
Returns the number of displayed (active) sprites on layer l

SPRITE(S)
Returns the number of the sprite which last caused a collision. NB if the number returned is Zero then the collision is the result of a SPRITE SCROLL command and the SPRITE(C…) function should be used to find how many and which sprites collided.

SPRITE(W, {#}n)
Returns the width of sprite n. This function is active whether or not the sprite is currently displayed (active).

SPRITE(X, {#}n)
Returns the X-coordinate of sprite n. This function is only active when the sprite is currently displayed (active). Returns 10000 otherwise.

SPRITE(Y, {#}n)
Returns the Y-coordinate of sprite n. This function is only active when the sprite is currently displayed (active). Returns 10000 otherwise



Edited by matherp 2018-02-07
 
Azure

Guru

Joined: 09/11/2017
Location: Australia
Posts: 446
Posted: 10:16pm 05 Feb 2018
Copy link to clipboard 
Print this post

Fantastic work Peter. A couple of questions, clarifications and suggestions.

1. I might be reading the commands incorrectly but it seems like sprites cannot be placed partially off wholly off screen in the minimum X and Y side but can be on the maximum X and Y directions (where they will be clipped). Is that correct?

2. For the following commands the horizontal move range is less than the vertical move range for these commands:
SPRITE SCROLLH n {,col}
Scrolls the background and any sprites on layer 0 n pixels to the right. n can be any number between -31 and 31...

SPRITE SCROLLV n {,col}
Scrolls the background, and any sprites on layer 0, n pixels up. n can be any number between -MM.VRES-1 and MM.VRES-1...


3. Following description may contain a typo:
SPRITE(N,n)
Returns the number of displayed (active) sprites on layer l
I think it should be:
SPRITE(N,n)
Returns the number of displayed (active) sprites on layer N


4. I think I have missed something but for collision detection do sprites on all layers collide with the background (layer 0)? So you can't have the background scrolling passively without it causing collisions (eg planes flying high over a city not detecting background collisions)?

5. Is there any way to add flags to the sprites like:
SPRITE FLIP {#}n XF YF
Where n is the sprite number and XY and YF are flag to cause the sprite to be drawn mirrored in the horizontal and/or vertical directions (default 0,0). This is great to allow a sprite to change direction (and invert its image) as it encounters something or when the screen is inverted (2nd player). Another option that could achieve a similar result and not impact other logic might be a command to invert a sprite #n image in the X or Y direction.

Great work, still trying tp process it all.Edited by Azure 2018-02-07
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10569
Posted: 11:30pm 05 Feb 2018
Copy link to clipboard 
Print this post

  Quote  1. I might be reading the commands incorrectly but it seems like sprites cannot be placed partially off wholly off screen in the minimum X and Y side but can be on the maximum X and Y directions (where they will be clipped). Is that correct?


No they can be placed anywhere as long as they overlap the screen to some extent

  Quote  For the following commands the horizontal move range is less than the vertical move range for these commands:


Yes, because of the way the bitshift works

  Quote  SPRITE(N,n)
Returns the number of displayed (active) sprites on layer l


Should be:

Returns the number of displayed (active) sprites on layer "n"

  Quote  I think I have missed something but for collision detection do sprites on all layers collide with the background (layer 0)? So you can't have the background scrolling passively without it causing collisions (eg planes flying high over a city not detecting background collisions)?


The background image scrolls without any collisions. Sprites on layer 0 will collide but that can be ignored in the program

  Quote  Is there any way to add flags to the sprites like:
SPRITE FLIP {#}n XF YF
Where n is the sprite number and XY and YF are flag to cause the sprite to be drawn mirrored in the horizontal and/or vertical directions (default 0,0). This is great to allow a sprite to change direction (and invert its image) as it encounters something or when the screen is inverted (2nd player). Another option that could achieve a similar result and not impact other logic might be a command to invert a sprite #n image in the X or Y direction.


Certainly do-able if worth the effort



 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 01:21am 06 Feb 2018
Copy link to clipboard 
Print this post

I always wonder what the phrase "if worth the effort" means?
Isn't that a very personal thing?

Here is my opinion.
To save resource it is very helpful to be able to flip, rotate an image or sprite.
This enables a lot of reuse of resources saving precious memory.

Even in high end 3D game engines, reusing the same resource is very efficient.
Rating, scaling etc the object is used very often to build landscapes.
On 2D it can be used to build backgrounds,several characters with common parts etc.




Microblocks. Build with logic.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10569
Posted: 06:39pm 06 Feb 2018
Copy link to clipboard 
Print this post

Another demo

Watch it here



I've implemented sprite mirroring as a new parameter on the sprite show command

SPRITE SHOW {#}n, x, layer {,orientation}

Displays sprite n on the screen with the top left at coordinates x, y. Sprites will only collide with other sprites on the same layer, layer zero, or with the screen edge. If a sprite is already displayed on the screen then the SPRITE SHOW command acts to move the sprite to the new location. The display background is stored as part of the command such that it can be replaced when the sprite is hidden or moved further. The orientation is an optional parameter, valid values are:
0 - normal display (default if omitted)
1 - mirrored left to right
2 - mirrored top to bottom
3 - rotated 180 degrees (= 1+2)

I've also implemented

SPRITE CLOSE ALL

This closes all sprites and frees up all used memory. It does not change the screen.

If I can get away without any more requirements I should be able to release the firmware soon as it is now starting to become pretty stable

Basic program for the above demo demonstrates the new functionality + collision detection interrupt handling. Note how the collision interrupt has to do something to clear the "collision" - in this case a scroll in the opposite direction. Otherwise the interrupt will re-occur when the second unrelated scroll is actioned.

option explicit
option default none
const leftbar = 1, rightbar = 2, topbar=3, bottombar=4, rightapple=5, leftapple=6
dim integer moveright=1, movedown=1
box 250,100,10,280,,rgb(magenta),rgb(magenta)
box 50,50,150,10,,rgb(cyan),rgb(cyan)
blit read leftbar,250,100,10,280
sprite copy leftbar, rightbar, 1 'make one copy
blit read topbar,50,50,150,10
sprite copy topbar, bottombar, 1 'make one copy
load sprite rightapple,"apple"
sprite copy rightapple,leftapple,1 'make one copy
load image "tiger640"
sprite interrupt collision
blit show rightapple,300,200,0
blit show leftapple,100,200,0,2
blit show leftbar,250,100,1
blit show rightbar,580,100,1
blit SHOW topbar,50,50,2
blit SHOW bottombar,50,420,2
do
if moveright then
sprite scrollr 259,100,322,280,2,0
else
sprite scrollr 259,100,322,280,-2,0
endif
if movedown then
sprite scrollr 50,59,150,362,0,-2
else
sprite scrollr 50,59,150,362,0,2
endif
loop
'
'
sub collision
local integer i, c(10), j
if sprite(S) = 0 then 'collisions caused by scroll
j=sprite(c,0)
for i=1 to j 'store the collisions because a clearing scroll move will clear them from the list
c(i)=sprite(C,0,i)
next i
for i=1 to j 'now process them
process_collision(c(j))
next i
endif
end sub
' get details of the specific collisions for a given sprite
sub process_collision(S as integer)
select case S
case leftbar
sprite scrollr 259,100,322,280,2,0 'make a move to clear the collision
sprite show rightapple,sprite(x,rightapple),sprite(y,rightapple),0,0 'normal orientation
moveright=1
case rightbar
sprite scrollr 259,100,322,280,-2,0 'make a move to clear the collision
sprite show rightapple,sprite(x,rightapple),sprite(y,rightapple),0,1 'mirror the sprite
moveright=0
case topbar
sprite scrollr 50,59,150,362,0,-2 'make a move to clear the collision
sprite show leftapple,sprite(x,leftapple),sprite(y,leftapple),0,3 'rotate the sprite 180 degrees
movedown=1
case bottombar
sprite scrollr 50,59,150,362,0,2 'make a move to clear the collision
sprite show leftapple,sprite(x,leftapple),sprite(y,leftapple),0,0 'normal orientation
movedown=0
case else
end select
end sub




Edited by matherp 2018-02-08
 
Azure

Guru

Joined: 09/11/2017
Location: Australia
Posts: 446
Posted: 10:54pm 06 Feb 2018
Copy link to clipboard 
Print this post

Peter,

Wonderful work. You have done an amazing job putting together a software platform for doing sprite and graphics animation.

Apologies for asking basic questions, but I do not have access to an MMX at the moment so can't play to answer these questions myself.

I am sure I am missing something but I do not see how you can place a sprite off the left and/or top of the screen (before the min X,Y values) and slowly make it appear on screen. I hope that makes sense.

The only other feature that comes to mind is sprite wrapping. Can you clarify that there is no wrapping of the sprite at the screen edge it just gets clipped at the screen boundaries. So to wrap a sprite you would create a second sprite that is as much on screen as the one that is off screen (during the wrapping).

Please ignore if I am asking stupid questions, just trying to get a good understanding of how this will work based on my previous work in the arcade game industry and high end graphics work on computers.

Again great work, can't wait to get onto a MMX and have a play.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10569
Posted: 08:08am 07 Feb 2018
Copy link to clipboard 
Print this post

  Quote  I am sure I am missing something but I do not see how you can place a sprite off the left and/or top of the screen (before the min X,Y values) and slowly make it appear on screen. I hope that makes sense.


You can place a sprite anywhere as long as some part of it overlaps the screen so

SPRITE SHOW #1, -SPRITE(W, #1)+1, 100,1

will place the sprite with just one column of pixels showing at the left of the screen. NB, if the rightmost column of the sprite contains the background colour then you won't see it at all

SPRITE HIDE #1

has, of course, no pixels showing

  Quote  Can you clarify that there is no wrapping of the sprite at the screen edge it just gets clipped at the screen boundaries. So to wrap a sprite you would create a second sprite that is as much on screen as the one that is off screen (during the wrapping).


I've played with several variants of this and am still not convinced what is best. At the moment the spite will disappear off the edge of the screen until it is half gone, at that point it will appear half on at the other side of the screen. Better ideas on this appreciated but too much flexibility risks making the syntax even more complicatedEdited by matherp 2018-02-08
 
Azure

Guru

Joined: 09/11/2017
Location: Australia
Posts: 446
Posted: 11:35am 07 Feb 2018
Copy link to clipboard 
Print this post

My first though is if it is too difficult (given the number of sprites supported), have no wrapping. Any needed wrapping should be able to be easily handled in the application.

That said my suggestion (if it is possible) would be that each sprite has a flag (like orientation) that specifies if it wraps or not. This can always be added later if it is wanted but too much work now.

If wrapping is supported it should wrap so that it wraps in only the X or Y like the orientation option, but without the option for both X and Y.
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025