News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_bluestar

Erase sprite preserving background (pure BASIC)

Started by bluestar, 14:24, 18 March 23

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

bluestar

I know is a recurrent subject but I wasn't able to find a straight answer or a piece of code.

My goal is to erase a sprite track preserving the background. Mode 1 using 4 colors. As far as I know there are two techniques:

- Copy the tile of the background and use it for erasing, but how can I do that? I'm programming for a CPC464 so there is no COPYCHR$ function available and I'm not going to use any ASM routine here for replicate the function. I was thinking that the only way to achieve this is to keep a record of each background tile in a array... (this implies more processing time and less memory)

- Use XOR. I was tring it (probably wrong) but I see two things. First as you have to use TAG mode you must find a way to convert graphical coordinates to text coordinates... Second: if I print my sprite with a XOR I got a "reversed" sprite (sprite color in background color, background color in sprite color) plus cursor symbols (left arrow, up arrow etc)

Any other idea?

Thanks!!

Animalgril987

#1
To remove the arrows you need to end the PRINT statement with a semicolon when you are in TAG mode.

Edit. Using XOR, you have to XOR your sprite to display it, then XOR again to remove. Note that if ( assuming mode 1) your background is pen 1 and sprite is pen 2 ( as examples ), then the result of XORing the sprite in will be pen 3, so you will need to adjust your inks accordingly.

bluestar

Quote from: Animalgril987 on 15:16, 18 March 23To remove the arrows you need to end the PRINT statement with a semicolon when you are in TAG mode.

Edit. Using XOR, you have to XOR your sprite to display it, then XOR again to remove. Note that if ( assuming mode 1) your background is pen 1 and sprite is pen 2 ( as examples ), then the result of XORing the sprite in will be pen 3, so you will need to adjust your inks accordingly.
Sorry but I don't know how to do it... I wrote a quick program to write an "X" over an " AAAAAAAAAAAAAAAAA ". Then I apply three XORs as you mention, but not erasing. Would you please help me? Thanks!

10 MODE 1
20 INK 1,0:INK 2,24:INK 3,15:PAPER 1:CLS
30 sprite$="X"
40 LOCATE 8,20:PRINT"AAAAAAAAAAAAAAAAA";
45 LOCATE 7,20:PRINT"X"
50 TAG
60 MOVE 100,100:GRAPHICS PEN 2:PRINT sprite$;
70 PRINT CHR$(23)+CHR$(1)
80 MOVE 100,100:GRAPHICS PEN 2:PRINT sprite$;
90 PRINT CHR$(23)+CHR$(1)
100 MOVE 100,100:GRAPHICS PEN 2:PRINT sprite$;
110 PRINT CHR$(23)+CHR$(1)
120 MOVE 100,100:GRAPHICS PEN 2:PRINT sprite$;

andycadley

You only need to XOR it once onto the screen, XORing the same thing again will remove it. The downside is that where things overlap the colours will get distorted and there isn't much you can do about that (well unless you're prepared to sacrifice the total number of colours on screen).

The other alternative is just to reprint the background areas before re-drawing all the moved sprites. It's more likely to be flickery though, especially if sprites might overlap because of the amount of time between erasing sprites and redrawing them.

The manual points out another technique that works in BASIC, which it calls "colour plane sprites". In this case you draw/erase using a combination of OR/AND - it also messes up colours but by arranging the palette you can hide the distortion. You're very limited on colours though and so it really only works in MODE 0 where you'll get four "sprite" colours and a background.

For anything vaguely professional looking, however, you really do have to turn to machine code of some sort.

HAL6128

#4
Do you want to PRINT (with locate) or DRAW/PLOT (with graphic coordinates) a sprite? = different approach in Basic.
...proudly supported Schnapps Demo, Pentomino and NQ-Music-Disc with GFX

bluestar

Quote from: HAL6128 on 19:50, 18 March 23Do you want to PRINT (with locate) or DRAW/PLOT (with graphic coordinates) a sprite? = different approach in Basic.
With LOCATE, but I guess XOR operation only works in graphical mode.

bluestar

Quote from: Animalgril987 on 15:16, 18 March 23To remove the arrows you need to end the PRINT statement with a semicolon when you are in TAG mode.
Edit. Using XOR, you have to XOR your sprite to display it, then XOR again to remove. Note that if ( assuming mode 1) your background is pen 1 and sprite is pen 2 ( as examples ), then the result of XORing the sprite in will be pen 3, so you will need to adjust your inks accordingly.
Ok, XOR operation ( PRINT CHR$(23)+CHR$(1) ) must be outside tag/tagoff in order to work but I'm still not able to remove arrows... (the sprite shows in one line although is in two)

bluestar

Nevertheless I'm thinking that even the XOR operation is not enough I mean...

1) I have a sprite (tile) printed in a specific position
2) Then I print the player character over so the tile is gone forever. Right?

Gonna think another alternative (keep tiles and position in array and delete with them)

Animalgril987

This works ( note PEN 2 and PEN 3 must be same ink):

100 MODE 1
110 INK 2, 18: INK 3,18
120 LOCATE 1,1: PEN 0: PRINT CHR$( 23);CHR$(1): REM XOR mode
130 PEN 1
140 CALL &BBDE,1,1: REM graphics pen ( different to text pen)
150 LOCATE 1,8
160 PRINT "AAAAAAAA"
170 TAG
180 MOVE 0,284
190 FOR I=1 TO 8
200      PRINT "X"; : REM semicolon at the end is important.
210.    FOR j =1 TO 500:NEXT : REM just a delay loop so you can see it happen
220.      MOVER -16,0: PRINT "X"; : REM again the semicolon
230 NEXT






Animalgril987

Should have mentioned that call to &BBDE:
The number of parameters that follow the call  set the graphics pen number, the values are unimportant. ( BASIC 1.1 users can use GRAPHICS PEN instead).

andycadley

Quote from: bluestar on 20:53, 18 March 231) I have a sprite (tile) printed in a specific position
2) Then I print the player character over so the tile is gone forever. Right?

With XOR, you can effectively undo a drawing 

The reason is mathematical. If A XOR B = C then A XOR C = B . So printing the same thing in the same position will restore the original background. But the result on screen looks kind of messy and usually isn't worth it.

If you use TAG mode, you can't embed control characters - this is why you're seeing the arrows appearing. Instead you have to print different rows of the sprite using separate PRINTs.

bluestar

Quote from: andycadley on 22:41, 18 March 23
Quote from: bluestar on 20:53, 18 March 231) I have a sprite (tile) printed in a specific position
2) Then I print the player character over so the tile is gone forever. Right?

With XOR, you can effectively undo a drawing

The reason is mathematical. If A XOR B = C then A XOR C = B . So printing the same thing in the same position will restore the original background. But the result on screen looks kind of messy and usually isn't worth it.

If you use TAG mode, you can't embed control characters - this is why you're seeing the arrows appearing. Instead you have to print different rows of the sprite using separate PRINTs.
Thank you!! No control characters embebed in TAG mode. Noted!

bluestar

#12
Quote from: Animalgril987 on 20:55, 18 March 23This works ( note PEN 2 and PEN 3 must be same ink):

100 MODE 1
110 INK 2, 18: INK 3,18
120 LOCATE 1,1: PEN 0: PRINT CHR$( 23);CHR$(1): REM XOR mode
130 PEN 1
140 CALL &BBDE,1,1: REM graphics pen ( different to text pen)
150 LOCATE 1,8
160 PRINT "AAAAAAAA"
170 TAG
180 MOVE 0,284
190 FOR I=1 TO 8
200      PRINT "X"; : REM semicolon at the end is important.
210.    FOR j =1 TO 500:NEXT : REM just a delay loop so you can see it happen
220.      MOVER -16,0: PRINT "X"; : REM again the semicolon
230 NEXT






:laugh: Thank you it works fantastic but... I'm not *#$%%% able to do the same with this piece of code (tomorrow will be another day). It prints footprints in orange and then two mummies in yellow. If you press "x" the first mummy must dissapear (it does) but the footprints are gone too...

10 SYMBOL AFTER 210
20 DIM mummies$(2,2)
30 yellow=24:black=0:blue=11:orange=15
40 MODE 1
50 INK 0,yellow:INK 1,orange: INK 2,black:INK 3,blue
60 GOSUB 30000
70 PAPER 2:CLS
80 FOR i=1 TO 20
90 LOCATE i+1,1:PRINT footprints$
100 NEXT i
110 LOCATE 7,1:PRINT mummies$(0,1):LOCATE 9,1:PRINT mummies$(0,0)
120 vidas=3:WHILE(vidas>0)
130 IF(INKEY$="x") THEN GOSUB 1000
140 WEND
150 PEN 0
160 END

1000 INK 2,black:INK 3,black:LOCATE 1,1:PEN 0:PRINT CHR$(23);CHR$(1):PEN 1:CALL &BBDE,1,1
1010 TAG:MOVE 96,398:PRINT CHR$(216)+CHR$(217);:MOVER -31,-15:PRINT CHR$(220)+CHR$(221);:TAGOFF
1020 GOTO 150
1030 RETURN

30000 REM Sprites
30010 SYMBOL 214,&0,&0,&0,&0,&0,&6F,&6F,&3
30020 SYMBOL 215,&3,&6F,&6F,&0,&0,&0,&0,&0
30030 SYMBOL 216,&0,&3,&7,&7,&3,&7,&7,&5
30040 SYMBOL 217,&0,&80,&C0,&C0,&C0,&80,&F8,&FC
30050 SYMBOL 218,&3,&3,&3,&3,&3,&3,&3,&3
30060 SYMBOL 219,&4C,&C0,&C0,&C0,&C0,&C0,&C0,&E0
30070 SYMBOL 220,&7,&7,&7,&F,&E,&E,&E,&F
30080 SYMBOL 221,&4C,&C0,&C0,&C0,&E0,&E0,&38,&3C
30090 footprints$=CHR$(22)+CHR$(0)+CHR$(15)+CHR$(1)+CHR$(214)
30100 sprite$=CHR$(15)+CHR$(0)+CHR$(216)+CHR$(217)+CHR$(8)+CHR$(8)+CHR$(10)+CHR$(218)+CHR$(219)
30110 mummies$(0,0)=sprite$
30120 sprite$=CHR$(15)+CHR$(0)+CHR$(216)+CHR$(217)+CHR$(8)+CHR$(8)+CHR$(10)+CHR$(220)+CHR$(221)
30130 mummies$(0,1)=sprite$
30140 RETURN


Animalgril987

I'll have to get back to you. I was typing and testing your code when Winape crashed! Of course, I hadn't SAVED, so I'm going to have to type it all in again!.
I knew I should have done it on a real CPC!

bluestar

#14
Quote from: Animalgril987 on 17:21, 19 March 23I'll have to get back to you. I was typing and testing your code when Winape crashed! Of course, I hadn't SAVED, so I'm going to have to type it all in again!.
I knew I should have done it on a real CPC!
You can copy and paste in WinApe!!! Or use the attached DSK (no need to press x for xoring)

Anthony Flack

Quote from: andycadley on 19:48, 18 March 23The manual points out another technique that works in BASIC, which it calls "colour plane sprites". In this case you draw/erase using a combination of OR/AND
Just keep using XOR. It's all about how you set up the inks.

Say if you set the even numbered pens all to different colours, and the odd numbered pens all to the same colour as pen 1. Now anything in pen 1 that is xored over an even-coloured background will appear unchanged, because for any even number n XOR 1 equals n + 1, and we set all the n+1 pens to the same as pen 1.

Or, set all the even-odd pairs (2+3,4+5,6+7 etc) to the same colour, now pen 1 appears behind the other colours because pen n+1 looks the same as pen n. Or, using some combination of the two, pen 1 appears behind some colours and in front of others.

Great! But unfortunately you've just lost nearly half your inks. And it only works with pen 1.

More common is to use three inks on each plane (not counting zero), where you would go (bg = background, fg=foreground)

ink 1,fg1: ink 2,fg2: ink 3,fg3: ink 4,bg1: ink 5,fg1: ink 6,fg2: ink 7,fg3: ink 8,bg2: ink 9,fg1: ink 10,fg2: ink 11,fg3: ink 12,bg3: ink 13,fg1: ink 14,fg2: ink 15,fg3

Anthony Flack

It should be noted that while the text printing routine in BASIC is pretty slow, XORing text to the graphics pointer is even slower. There's quite a bit of number crunching being done to draw text symbols (stored in a different data format) at arbitrary screen positions in any pen colour, and with clipping too. All these things slow it down, and most of it you can do without. A tiny little bit of machine code that you call from BASIC can xor sprite data to the screen much more efficiently.

Well, everything in BASIC is a tiny little bit of machine code that you call from BASIC. They never added a fast sprite drawing routine to the firmware, but they did make it easy to add one. I know you said you want to work in pure BASIC but I like to think that the Locomotive Software folks fully intended people to make use of the ability to extend BASIC for that sort of thing.

ZbyniuR

@bluestar - To use COPYCHR$ in 1.0 Basic try this:
10 FOR g=0 to 16:READ a$:POKE 40000+g,VAL("&"+a$):NEXT:DATA dd,7e,00,cd,b4,bb,f5,cd,60,bb,32,00,00,f1,c3,b4,bb
And now if you need COPYCHR$  use LOCATE x,y:CALL 40000,0  and  your char is CHR$(PEEK(0))

@Animal - WinApe have function AutoType, start by Ctrl+F5. Paste there text (for example basic from net) and program is typing in emulator itself.

My version sprite fast enough to made pointer by TAG:PRINT  size 8x8 pix in 4 colors, and jumps by 4 pixels, I made on DSK there:
https://www.cpcwiki.eu/forum/index.php?msg=117543
In GUI.BAS move pointer by joystick, or in GUI2.BAS move it by Functions keys 123 & 5, as ,<v> & ^. I know my code look messy, so if someone have question how the hell it's work? just ask. :)
In STARS, TREK is better than WARS.

andycadley

Quote from: Anthony Flack on 21:30, 19 March 23
Quote from: andycadley on 19:48, 18 March 23The manual points out another technique that works in BASIC, which it calls "colour plane sprites". In this case you draw/erase using a combination of OR/AND
Just keep using XOR. It's all about how you set up the inks.

Say if you set the even numbered pens all to different colours, and the odd numbered pens all to the same colour as pen 1. Now anything in pen 1 that is xored over an even-coloured background will appear unchanged, because for any even number n XOR 1 equals n + 1, and we set all the n+1 pens to the same as pen 1.

Or, set all the even-odd pairs (2+3,4+5,6+7 etc) to the same colour, now pen 1 appears behind the other colours because pen n+1 looks the same as pen n. Or, using some combination of the two, pen 1 appears behind some colours and in front of others.

Great! But unfortunately you've just lost nearly half your inks. And it only works with pen 1.

More common is to use three inks on each plane (not counting zero), where you would go (bg = background, fg=foreground)

ink 1,fg1: ink 2,fg2: ink 3,fg3: ink 4,bg1: ink 5,fg1: ink 6,fg2: ink 7,fg3: ink 8,bg2: ink 9,fg1: ink 10,fg2: ink 11,fg3: ink 12,bg3: ink 13,fg1: ink 14,fg2: ink 15,fg3
Yeah. The advantage of the AND/OR combination as described in the manual is that it's more like a real sprite approach. And so you can have to sprites on the same "colour plane" overlap without erasing each other as they would do with XOR. You do have to be more careful about drawing order though.

Still very limited in terms of on screen colours though and it's more complex in BASIC to do the 3+3 arrangement. Using a proper sprite routine is just a lot easier (even if you go with one of the classic BASIC extensions like Sprites Alive)

HAL6128

In my example of BASIC sprites I don't use the XOR techniques but preserve (save) the background in a table. Normally that should be easy because in a mode 0 screen you only have to save 20 x 25 background sprites which shouldn't be much for your memory.
Just try the DSK example attached, run "DISC", wait after the entry screen and start the game.
The XOR technique is obviously faster (see @ZbyniuR great examples of the GUI ...should try it, nice one!)
...proudly supported Schnapps Demo, Pentomino and NQ-Music-Disc with GFX

ZbyniuR

WOW, Frogger made in Basic!  I'm impress. :)
In STARS, TREK is better than WARS.

bluestar

Thanks for all your help. I'll have a look during this week. Currently I'm working on a version of Oh Mummy! in pure Basic (and writting a tutorial), then I'll do the same game using BASIC+Machine code calls, then 8BP, then CPCtelera and finally ASM :)

As you can imagine I'm currently working in the mummy's traces... I guess I'm going to store the player tracks (the background) in an array and recover it if needed.

Cheers!

arnolde

If your background consists of only monochrome symbols, my approach would be the following:
Make an array for your "level map" (size x*y), either a 2-dimensional (map(x,y)) or an array of strings (map$(y)) where every string has the whole length of one map line (=x). For erasing you would do LOCATE x,y and then either 
PRINT CHR$(map(x,y)); or PRINT MID$(map$(y),x,1);
The 2-dimensional approach is faster, but takes more memory than the string one. In any case, I would use integers (DEFINT a-z) for both speed and memory optimization.

For displaying the sprite, I'd use the escape code for transparency, i.e. 
LOCATE x,y:PRINT CHR$(22)+CHR$(1)+sprite$;

That way, you could even design a multicolored sprite, printing multiple symbols in different PENs over each other.
For erasing, don't forget to turn transparency off again with CHR$(22)+CHR$(0)

bluestar

Quote from: arnolde on 12:20, 23 March 23If your background consists of only monochrome symbols, my approach would be the following:
Make an array for your "level map" (size x*y), either a 2-dimensional (map(x,y)) or an array of strings (map$(y)) where every string has the whole length of one map line (=x). For erasing you would do LOCATE x,y and then either
PRINT CHR$(map(x,y)); or PRINT MID$(map$(y),x,1);
The 2-dimensional approach is faster, but takes more memory than the string one. In any case, I would use integers (DEFINT a-z) for both speed and memory optimization.

For displaying the sprite, I'd use the escape code for transparency, i.e.
LOCATE x,y:PRINT CHR$(22)+CHR$(1)+sprite$;

That way, you could even design a multicolored sprite, printing multiple symbols in different PENs over each other.
For erasing, don't forget to turn transparency off again with CHR$(22)+CHR$(0)
Thanks! that's what I'm doing. Currently I'm using a 2-dimensional array but I'll consider your proposal during optimization phase. I need to finish this and then optimize the main loop :)

Powered by SMFPacks Menu Editor Mod