News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_AMSDOS

More Silly Programming Using Graphics

Started by AMSDOS, 12:15, 13 June 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

AMSDOS

Here's one really silly routine to draw in a Background pattern:


10 ' Move Block around Background
20 ' Grid Array - Holds Background
30 ' Ref Array - Used to map Graphical Y-Axis
40 ' p variable - used as a pointer for Grid, Ref Array & y-axis of main character
50 ' xp variable - used as x pointer for Grid
60 MODE 0 : DEFINT a-z
70 DIM grid(19,19),ref(19)
80 GOSUB 410 : GOSUB 310
90 GOSUB 710
100 x=32 : xp=8 : p=6
110 GOSUB 210
120 WHILE INKEY(18)=-1
130 IF INKEY(0)<>-1 AND (p<>0) THEN p=p-1 : GOSUB 210
140 IF INKEY(2)<>-1 AND (p<>11) THEN p=p+1 : GOSUB 210
150 IF INKEY(8)<>-1 AND (x<>0) THEN x=x-4 : xp=xp-1 : GOSUB 210
160 IF INKEY(1)<>-1 AND (x<>44) THEN x=x+4 : xp=xp+1 : GOSUB 210
170 WEND
180 WHILE INKEY$<>"":WEND
190 MODE 2:END
200 ' Main character - A Black Square!
210 PLOT -2,-2,1
220 MOVE x,ref(p)
230 TAG : PRINT CHR$(233); : TAGOFF
240 GOSUB 840
250 RETURN
300 ' Setup Ref Array - this holds Y-Coordinate positions
310 RESTORE 350: FOR p=0 TO 19
320  READ ref(p)
330 NEXT p
340 RETURN
350 DATA 398,396,394,392,390,388,386,384
360 DATA 382,380,378,376,374,372,370,368
370 DATA 366,364,362,360
400 ' Setup Grid array - this holds main background graphics
410 RESTORE 470 : FOR yp=0 TO 19
420  FOR xp=0 TO 19
430   READ grid(xp,yp)
440  NEXT xp
450 NEXT yp
460 RETURN
470 DATA 2,2,2,2,2,0,0,0,0,3,3,3,0,4,4,4,0,0,0,5
480 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
490 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
500 DATA 0,2,2,2,6,6,6,0,7,7,7,0,4,4,4,4,4,0,0,5
510 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,4,4,4,0,0,0,5
520 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,0,0,0,0,0,0,5
530 DATA 0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,5
540 DATA 0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,5
550 DATA 0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
560 DATA 0,0,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
570 DATA 0,4,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
580 DATA 0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5
590 DATA 0,4,4,4,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,5
600 DATA 0,0,4,7,7,7,7,7,0,0,0,2,2,2,0,0,0,0,0,5
610 DATA 2,2,2,7,7,7,7,7,0,0,2,2,2,2,2,7,7,0,0,5
620 DATA 2,2,2,7,7,7,7,7,3,3,2,2,2,2,2,7,7,7,0,5
630 DATA 2,2,2,2,7,7,7,3,3,3,2,2,2,2,2,7,7,7,0,5
640 DATA 2,2,2,2,0,0,3,3,3,3,3,2,2,2,7,7,7,7,0,5
650 DATA 2,2,2,0,0,0,3,3,3,3,3,0,0,0,7,7,7,0,0,5
660 DATA 0,0,0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,0,5
700 ' Initial Draw of the Background
710 yp=398 : xp=0 : y=0 : x=0
720 WHILE y<=19
730  WHILE x<=19
740   PLOT xp,yp,grid(x,y)
750   x=x+1 : xp=xp+4
760  WEND
770 x=0 : xp=0 : y=y+1 : yp=yp-2
780 WEND
790 RETURN
800 ' Complicated way to fill in Background graphics around a Black Square
810 ' xp1 & yp1 - calculates x & y positions (1 step at a time) to correctly work out background where block is placed
820 ' f - calculates x positions (times 4 step for mode 0) to plot top & bottom of block
830 ' g - calculates y positions (times 2 for each line) for the side of the block
840 xp1=xp : FOR f=x TO x+32 STEP 4
850 PLOT f,ref(p),grid(xp1,p) : PLOT f,ref(p+7),grid(xp1,p+7)
860 xp1=xp1+1 : NEXT f
870 xp1=xp : yp1 = p : FOR g=ref(p) TO ref(p)-16 STEP -2
880 PLOT x,g,grid(xp1,yp1) : PLOT x+28,g,grid(xp1+7,yp1)
890 yp1=yp1+1 : NEXT g
900 RETURN



Unfortunately I setup the Inks on the Fly and forgot to add them into the program, so if anyone wants to play with it with the inks I used add this following line:


65 BORDER 26 : INK 0,26 : INK 1,0 : INK 2,18 : INK 3,8 : INK 4,15 : INK 5,6 : INK 6,25 : INK 7,2 : INK 8,20


This program is only showing how to draw around the edges of the Square (char 233) and the Fill Routine Lines 800-900 are tailored made to draw around the edges. But it's given me ideas on how to fill in more complicated areas of Objects using a Nested Loop and TEST.  :D
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS


I've created 2 variations of the program above, to deal with how background gets drawn around the main character. The only difference is the type of loop being used, initially I used WHILE..WEND thinking I needed more control, though easily implemented FOR..NEXT, which works out faster in this case.


So in these examples, I'm now using loops to go through the 64 pixels of the main character, inserting the appropriate parts of the array if they are not being obscured by the main bits of the character.


The only snag I've encountered with these, relates to the character used. The Person (Character 248) used is an 8x8 character, unlike my last Block (233) doesn't occupy any edge, and in the case of this Person, Left Edge & Top Edge begin extending themselves when the character moves the other way. Eventually, I resorted to using PLOTs in the lines which dealts filling back appropriate sections of the array when those keypresses are made.



10 ' Move Man around Background
20 ' Grid Array - Holds Background
30 ' Ref Array - Used to map Graphical Y-Axis
40 ' p variable - used as a pointer for Grid, Ref Array & y-axis of main character
50 ' xp variable - used as x pointer for Grid
60 MODE 0 : INK 0,26 : BORDER 26 : INK 1,0 : INK 2,18 : INK 3,8 : INK 4,15 : INK 5,6 : INK 6,25 : INK 7,2 : INK 8,20 : DEFINT a-z
70 DIM grid(19,19),ref(19)
80 GOSUB 410 : GOSUB 310
90 GOSUB 710
100 x=32 : xp=8 : p=6
110 GOSUB 210
120 WHILE INKEY(18)=-1
130 IF INKEY(0)<>-1 AND (p<>0) THEN p=p-1 : PLOT x+8,ref(p+8),0 : PLOT x+16,ref(p+8),0 : GOSUB 210
140 IF INKEY(2)<>-1 AND (p<>11) THEN p=p+1 : PLOT x+8,ref(p-1),grid(xp+2,p-1) : PLOT x+12,ref(p-1),grid(xp+3,p-1) : PLOT x+16,ref(p-1),grid(xp+4,p-1) : GOSUB 210
150 IF INKEY(8)<>-1 AND (x<>0) THEN x=x-4 : xp=xp-1 : GOSUB 210
160 IF INKEY(1)<>-1 AND (x<>44) THEN PLOT x,ref(p+2),grid(xp,p+2) : x=x+4 : xp=xp+1 : GOSUB 210
170 WEND
180 WHILE INKEY$<>"":WEND
190 MODE 2:END
200 ' Main character
210 PLOT -2,-2,1
220 MOVE x,ref(p)
230 TAG : PRINT CHR$(248); : TAGOFF
240 GOSUB 840
250 RETURN
300 ' Setup Ref Array - this holds Y-Coordinate positions
310 RESTORE 350: FOR p=0 TO 19
320  READ ref(p)
330 NEXT p
340 RETURN
350 DATA 398,396,394,392,390,388,386,384
360 DATA 382,380,378,376,374,372,370,368
370 DATA 366,364,362,360
400 ' Setup Grid array - this holds main background graphics
410 RESTORE 470 : FOR yp=0 TO 19
420  FOR xp=0 TO 19
430   READ grid(xp,yp)
440  NEXT xp
450 NEXT yp
460 RETURN
470 DATA 2,2,2,2,2,0,0,0,0,3,3,3,0,4,4,4,0,0,0,5
480 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
490 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
500 DATA 0,2,2,2,6,6,6,0,7,7,7,0,4,4,4,4,4,0,0,5
510 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,4,4,4,0,0,0,5
520 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,0,0,0,0,0,0,5
530 DATA 0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,5
540 DATA 0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,5
550 DATA 0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
560 DATA 0,0,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
570 DATA 0,4,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
580 DATA 0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5
590 DATA 0,4,4,4,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,5
600 DATA 0,0,4,7,7,7,7,7,0,0,0,2,2,2,0,0,0,0,0,5
610 DATA 2,2,2,7,7,7,7,7,0,0,2,2,2,2,2,7,7,0,0,5
620 DATA 2,2,2,7,7,7,7,7,3,3,2,2,2,2,2,7,7,7,0,5
630 DATA 2,2,2,2,7,7,7,3,3,3,2,2,2,2,2,7,7,7,0,5
640 DATA 2,2,2,2,0,0,3,3,3,3,3,2,2,2,7,7,7,7,0,5
650 DATA 2,2,2,0,0,0,3,3,3,3,3,0,0,0,7,7,7,0,0,5
660 DATA 0,0,0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,0,5
700 ' Initial Draw of the Background
710 yp=398 : xp=0 : y=0 : x=0
720 WHILE y<=19
730  WHILE x<=19
740   PLOT xp,yp,grid(x,y)
750   x=x+1 : xp=xp+4
760  WEND
770 x=0 : xp=0 : y=y+1 : yp=yp-2
780 WEND
790 RETURN
800 ' Complicated way to fill in Background graphics around an object
810 ' xp1 & yp1 - calculates x & y positions (1 step at a time) to correctly work out background where object is placed
820 ' f - calculates x positions of the object
830 ' g - calculates y positions of the object
840 xp1=xp
850 yp1=p
860 g=ref(p)
870 f=x
880 WHILE g>=ref(p)-16
890  WHILE f<=x+32
900   IF TEST(f,g)=0 THEN PLOT f,g,grid(xp1,yp1)
910   xp1=xp1+1
920   f=f+4
930  WEND
940 f=x
950 g=g-2
960 yp1=yp1+1
970 xp1=xp
980 WEND
990 RETURN






10 ' Move Man around Background
20 ' Grid Array - Holds Background
30 ' Ref Array - Used to map Graphical Y-Axis
40 ' p variable - used as a pointer for Grid, Ref Array & y-axis of main character
50 ' xp variable - used as x pointer for Grid
60 MODE 0 : INK 0,26 : BORDER 26 : INK 1,0 : INK 2,18 : INK 3,8 : INK 4,15 : INK 5,6 : INK 6,25 : INK 7,2 : INK 8,20 : DEFINT a-z
70 DIM grid(19,19),ref(19)
80 GOSUB 410 : GOSUB 310
90 GOSUB 710
100 x=32 : xp=8 : p=6
110 GOSUB 210
120 WHILE INKEY(18)=-1
130 IF INKEY(0)<>-1 AND (p<>0) THEN p=p-1 : PLOT x+8,ref(p+8),0 : PLOT x+16,ref(p+8),0 : GOSUB 210
140 IF INKEY(2)<>-1 AND (p<>11) THEN p=p+1 : PLOT x+8,ref(p-1),grid(xp+2,p-1) : PLOT x+12,ref(p-1),grid(xp+3,p-1) : PLOT x+16,ref(p-1),grid(xp+4,p-1) : GOSUB 210
150 IF INKEY(8)<>-1 AND (x<>0) THEN x=x-4 : xp=xp-1 : GOSUB 210
160 IF INKEY(1)<>-1 AND (x<>44) THEN PLOT x,ref(p+2),grid(xp,p+2) : x=x+4 : xp=xp+1 : GOSUB 210
170 WEND
180 WHILE INKEY$<>"":WEND
190 MODE 2:END
200 ' Main character
210 PLOT -2,-2,1
220 MOVE x,ref(p)
230 TAG : PRINT CHR$(248); : TAGOFF
240 GOSUB 840
250 RETURN
300 ' Setup Ref Array - this holds Y-Coordinate positions
310 RESTORE 350: FOR p=0 TO 19
320  READ ref(p)
330 NEXT p
340 RETURN
350 DATA 398,396,394,392,390,388,386,384
360 DATA 382,380,378,376,374,372,370,368
370 DATA 366,364,362,360
400 ' Setup Grid array - this holds main background graphics
410 RESTORE 470 : FOR yp=0 TO 19
420  FOR xp=0 TO 19
430   READ grid(xp,yp)
440  NEXT xp
450 NEXT yp
460 RETURN
470 DATA 2,2,2,2,2,0,0,0,0,3,3,3,0,4,4,4,0,0,0,5
480 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
490 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
500 DATA 0,2,2,2,6,6,6,0,7,7,7,0,4,4,4,4,4,0,0,5
510 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,4,4,4,0,0,0,5
520 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,0,0,0,0,0,0,5
530 DATA 0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,5
540 DATA 0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,5
550 DATA 0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
560 DATA 0,0,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
570 DATA 0,4,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
580 DATA 0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5
590 DATA 0,4,4,4,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,5
600 DATA 0,0,4,7,7,7,7,7,0,0,0,2,2,2,0,0,0,0,0,5
610 DATA 2,2,2,7,7,7,7,7,0,0,2,2,2,2,2,7,7,0,0,5
620 DATA 2,2,2,7,7,7,7,7,3,3,2,2,2,2,2,7,7,7,0,5
630 DATA 2,2,2,2,7,7,7,3,3,3,2,2,2,2,2,7,7,7,0,5
640 DATA 2,2,2,2,0,0,3,3,3,3,3,2,2,2,7,7,7,7,0,5
650 DATA 2,2,2,0,0,0,3,3,3,3,3,0,0,0,7,7,7,0,0,5
660 DATA 0,0,0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,0,5
700 ' Initial Draw of the Background
710 yp=398 : xp=0 : y=0 : x=0
720 WHILE y<=19
730  WHILE x<=19
740   PLOT xp,yp,grid(x,y)
750   x=x+1 : xp=xp+4
760  WEND
770 x=0 : xp=0 : y=y+1 : yp=yp-2
780 WEND
790 RETURN
800 ' Complicated way to fill in Background graphics around an object
810 ' xp1 & yp1 - calculates x & y positions (1 step at a time) to correctly work out background where object is placed
820 ' f - calculates x positions of the object
830 ' g - calculates y positions of the object
840 xp1=xp
850 yp1=p
860 FOR g=ref(p) TO ref(p)-16 STEP -2
870  FOR f=x TO x+32 STEP 4
880   IF TEST(f,g)=0 THEN PLOT f,g,grid(xp1,yp1)
890   xp1=xp1+1
900  NEXT f
910 yp1=yp1+1
920 xp1=xp
930 NEXT g
940 RETURN
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ronaldo

#2
I've taken again the freedom of modyfing your code to make an optimized version. I sum up here what I've done for your reference:

       
  • I've removed the ref array (as y locations are easy to calculate, and that is much faster than accessing the array)
  • I've changed Grid matriz from DIM Grid(19,19) to DIM g(9,9). As integers in BASIC are 2-bytes wide, but we only need 1 byte to store values from 0 to 15 (INKs), this halves the required space. Also, accessing it manually (using POKE, PEEK and a pointer) is much faster.
  • I've created a Mask of the character (symbol 249) and changed the way it is redrawn. The process is:
       1. Redraw background (only redrawing the pixels that form the character)
       2. Draw the Mask with an AND operation to erase the pixels where the character is to be drawn
       3. Draw the Character with an OR operation, leaving backgound as is, and adding character pixels to the previously erased ones
  • I've separated keyboard reading code from updating and drawing code
  • I've also changed some IF's and other checking code, doing the same but in a more optimized way. To understand these optimizations, I've done also a simple code that demonstrate which options are faster (I attach some results as screenshots).     
  • There are also 2 commented approaches in the code that I've tested. One is using PLOT to draw only the pixels of the character (instead of PRINT CHR$) and the other is erasing the character printing its bounding box (8x8 pixel box). The second one is clearly slower, so it is discarded. The first is not clearly slower, but I think the firmware does it better with PRINGS than a string of PLOTs. Some testing will be requiered to confirm it, but I think PRINT does it better.
This is the final result:
[attachimg=6]
And here you are the final code:

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Move Man around Background
' VARIABLES USED:
' g(9,9): Background array (inks for pixels of the background stored as 1-byte per INK)
'   x, y: Screen coordinates of the upper-left corner of the character
'  xp,yp: temporal index variables for loops
'      p: Pointer to the background array (to access it byte by byte)
'      v: Value read from DATAs, to be stored of the background array
'   i, j: Coordinates of the upper-left corner of the character with
'         respect to the background (0,0 is the upper-left corner of the
'         background). Used to know the portion of the background to redraw.
'      z: Used as temporal value for x when redrawing background over character
'      t: Used as temporal value for y when redrawing background over character
'      m: Movement to be performed (0,1,2,4,8 = no,up,down,left,right)
'      s: Pointer to the start of the Background array g
'     c$: Character of the Man
'     m$: Mask of the c$ character (inverse)
'     o$: Control Codes to enable Graphics  OR Drawing Mode
'     a$: Control Codes to enable Graphics AND Drawing Mode
'     f$: Control Codes to set Graphis drawing normal mode
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
10 MODE 0:INK 0,26:BORDER 26:INK 1,0:INK 2,18:INK 3,8:INK 4,15:INK 5,6:INK 6,25:INK 7,2:INK 8,20:DEFINT a-z
' Create a Mask for the character to be used in redrawing it
20 SYMBOL 249,&C7,&C7,&6D,&83,&EF,&D7,&D7,&D7
' Grid do not need to use 2-bytes per element (a BASIC integer)
' So we define it halved, and access bytes directly using PEEK and POKE
' 20 items = 20 bytes = 10 integers
' Remember that BASIC defines arrays from 0 to NUM, so 10 elements = dim ARRAY(9)
30 DIM g(9,9)
' As we are using some variables as pointers, it is preferably to define all variables
' first (before using @ operator to point to memory locations) to prevent BASIC from
' messing around with memory re-ordering when she encounters new undefined variables
40 x=0:y=0:xp=0:yp=0:p=0:v=0:i=0:j=0:z=0:t=0:m=0:s=0
50 c$=CHR$(248):m$=CHR$(249)$=CHR$(23)+CHR$(3):a$=CHR$(23)+CHR$(2):f$=CHR$(23)+CHR$(0)+CHR$(31)+CHR$(1)+CHR$(1)
60 s=@g(0,0)
' First Insert the background into the Grid Array
70 GOSUB 1000
' Than draw the complete background
80 GOSUB 2000
' Locate Main Character at its first location (0,0) and draw it
100 x=0:y=398:i=0:j=0:GOSUB 3000
' Main Loop (Read keyboard and redraw when required
120 WHILE INKEY(18)<0:m=0
130 IF NOT INKEY(0)AND j THEN m=1ELSE IF NOT INKEY(2)AND j<12THEN m=2
140 IF NOT INKEY(8)AND i THEN m=4ELSE IF NOT INKEY(1)AND i<13THEN m=8
150 IF m<1 THEN 180
160 GOSUB 4000:IF m AND 1THEN j=j-1:y=y+2ELSE IF m AND 2THEN j=j+1:y=y-2ELSE IF m AND 4THEN i=i-1:x=x-4ELSE i=i+1:x=x+4
170 GOSUB 3000
180 WEND
190 WHILE INKEY$<>"":WEND
200 MODE 2:END

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Setup Grid array - this holds main background graphics
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Read the value and insert it into the array. Array has 20 rows of 20 bytes each
' Each row corresponding to 20 values over the same yp, and increasing xp.
' So p starts pointing to g(0,0) in memory and goes increasing
1000 RESTORE 1080
1010 p=s
1020 FOR yp=0 TO 19
1030  FOR xp=0 TO 19
1040   READ v:POKE p,v:p=p+1
1050  NEXT xp
1060 NEXT yp
1070 RETURN
1080 DATA 2,2,2,2,2,0,0,0,0,3,3,3,0,4,4,4,0,0,0,5
1090 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
1100 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
1110 DATA 0,2,2,2,6,6,6,0,7,7,7,0,4,4,4,4,4,0,0,5
1120 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,4,4,4,0,0,0,5
1130 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,0,0,0,0,0,0,5
1140 DATA 0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,5
1150 DATA 0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,5
1160 DATA 0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
1170 DATA 0,0,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
1180 DATA 0,4,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
1190 DATA 0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5
1200 DATA 0,4,4,4,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,5
1210 DATA 0,0,4,7,7,7,7,7,0,0,0,2,2,2,0,0,0,0,0,5
1220 DATA 2,2,2,7,7,7,7,7,0,0,2,2,2,2,2,7,7,0,0,5
1230 DATA 2,2,2,7,7,7,7,7,3,3,2,2,2,2,2,7,7,7,0,5
1240 DATA 2,2,2,2,7,7,7,3,3,3,2,2,2,2,2,7,7,7,0,5
1250 DATA 2,2,2,2,0,0,3,3,3,3,3,2,2,2,7,7,7,7,0,5
1260 DATA 2,2,2,0,0,0,3,3,3,3,3,0,0,0,7,7,7,0,0,5
1270 DATA 0,0,0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,0,5

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Initial Draw of the Background
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' p points to the start of the background array and goes byte by byte
' moving to the next byte that should be drawn to screen
2000 p=s
2010 FOR yp=398 to 360 step -2
2020  FOR xp=0 to 76 step 4
2030   PLOT xp,yp,PEEK(p):p=p+1
2040  NEXT xp
2050 NEXT yp
2060 RETURN

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' REDRAW Character with MASK (AND + OR)
' - MASK must be drawn with pen 15 (1111) to have 1's where
'   there is no color and 0's where there is color
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
3000 PLOT -2,-2,15:?a$:MOVE x,y:TAG:?m$;:TAGOFF:PLOT -2,-2,1:?o$:MOVE x,y:TAG:?c$;:TAGOFF:?f$:RETURN

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' REDRAW Character optimized (Only Character Pixels)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'3000 PLOT x+8,y,1:PLOT x+12,y:PLOT x+16,y:t=y-2:PLOT x+8,t:PLOT x+12,t:PLOT x+16,t:t=t-2:PLOT x,t:PLOT x+12,t:PLOT x+24,t:t=t-2:PLOT x+4,t:PLOT x+8,t:PLOT x+12,t:PLOT x+16,t:PLOT x+20,t:t=t-2
'3010 PLOT x+12,t:t=t-2:PLOT x+8,t:PLOT x+16,t:t=t-2:PLOT x+8,t:PLOT x+16,t:t=t-2:PLOT x+8,t:PLOT x+16,t:RETURN

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Background redrawing over Character optimized (only character pixels)
'  - One plot for each pixel of the character to redraw background
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
4000 p=s+20*j+i:PLOT x+8,y,PEEK(p+2):PLOT x+12,y,PEEK(p+3):PLOT x+16,y,PEEK(p+4):t=y-2:PLOT x+8,t,PEEK(p+22):PLOT x+12,t,PEEK(p+23):PLOT x+16,t,PEEK(p+24):t=t-2:PLOT x,t,PEEK(p+40):PLOT x+12,t,PEEK(p+43):PLOT x+24,t,PEEK(p+46):t=t-2
4010 PLOT x+4,t,PEEK(p+61):PLOT x+8,t,PEEK(p+62):PLOT x+12,t,PEEK(p+63):PLOT x+16,t,PEEK(p+64):PLOT x+20,t,PEEK(p+65):t=t-2:PLOT x+12,t,PEEK(p+83):t=t-2:PLOT x+8,t,PEEK(p+102):PLOT x+16,t,PEEK(p+104):t=t-2:PLOT x+8,t,PEEK(p+122)
4020 PLOT x+16,t,PEEK(p+124):t=t-2:PLOT x+8,t,PEEK(p+142):PLOT x+16,t,PEEK(p+144):RETURN

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Background redrawing over Character (all character box)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'4000 p=@g(0,0)+20*j+i:FOR t=y TO y-14STEP -2:FOR z=x TO x+28STEP 4:PLOT z,t,PEEK(p):p=p+1:NEXT z:p=p+12:NEXT t
'4010 RETURN


And the code use for testing different options and select the most optimal

''
'' Testing TIME difference between NOT and <>-1 in comparisons
''
10 DEFINT a-z:it=5000
20 MODE 2:PRINT"TESTING COMPARISONS USING 'NOT' vs '<>-1'"
30 PRINT"Doing";it;"iterations for '<>-1'"
40 t!=TIME:GOSUB 1000:t!=TIME-t!
50 t!(0)=t!
60 PRINT"Doing";it;"iterations for 'NOT'"
70 t!=TIME:GOSUB 2000:t!=TIME-t!
80 t!(1)=t!
90 PRINT:PRINT"RESULTS"
100 PRINT "<> :";t!(0);"(";t!(0)/300;"seconds)"
110 PRINT "NOT:";t!(1);"(";t!(1)/300;"seconds)"
900 END
''
'' COMPARISONS USING <>-1
''
1000 FOR i=0 to it
1010 IF INKEY(18)<>-1 THEN a=0
1020 NEXT i
1030 RETURN
''
'' COMPARISONS USING NOT
''
2000 FOR i=0 to it
2010 IF NOT(INKEY(18)) THEN a=0
2020 NEXT i
2030 RETURN


There is still a lot of room for improvements, starting from synchronizing with VSYNC to improve the resulting experience.

Hope this approach to be helpful for you  :)

AMSDOS


I've printed out a copy of your program in case I've missed something, the only thing I've picked up on is calculating the positions for the y-axis and storing them into my ref array instead of reading that data, but essentially I'm looking to move away from Control Code 23 function 3 because it causes flicker and colour clash (not evident in your example though).


I don't quite understand what's happened with the Array when you've condensed it 9x9 and it's unfortunate Locomotive BASIC doesn't have any Byte Type and since I picture 2D array's as a spreadsheet with numbers stuck in rows/columns.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ronaldo

#4
If you want some explanations on the things I do, please ask. I assume there are lots of things to be explained.

The flickering is not due to graphics mix mode 3. It is doe to too many things to do when drawing and no syncrhonization with VSYNC. In fact, the program does not use mode 3 and has no color clash at all. I use mode 3 and mode 2 combined to produce a masked draw that only erases background in the part that is going to be occupied by the pixels of the sprite. This technique has 2 steps, one is done with mode 2 (AND step) and the other uses mode 3 (OR step). The fist erases the pixels that are to be occupied by the sprite (and only that pixels) with an AND operation, and the second step uses mode 3 to draw the sprite without erasing the background with an OR operation. The result is the sprite being drawn with no color clash and no background erasing.

Flickering may be reduced, by synchronizing with VSYNC, but I think it would be almost impossible to eliminate, as there are to many things to do in the drawing step. In your version, there is no flickering by there is a "slow background drawing" effect  which is the same, but with a different feeling. It is extremelly difficult to draw these things in basic without flicker. The alternative is to do them directly accessing video memory byte by byte, which could be faster, as there would be less bytes to consider. We did a prototype that uses this alternative (called Zeldo), but without background.

ronaldo

#5
I've tried changing background re/drawing from a PLOT-based version to a POKE-based one. This time, I write directly to video memory putting bytes in pixel format.

This is faster in drawing the background, but not enough for preventing flickering (even waiting for VSYNC).

The other thing I'm thinking of is making a more accurate redrawing, depending on the movement, to redraw only thouse exact pixels that change. That could be the best approach I can think of at the momment.

This is the result of this new version:
[attachimg=1]

And this is the code:

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Move Man around Background
' VARIABLES USED:
' g(9,9): Background array (inks for pixels of the background stored as 1-byte per INK)
'   x, y: Screen coordinates of the upper-left corner of the character
'  xp,yp: temporal index variables for loops
'      p: Pointer to the background array (to access it byte by byte)
'      v: Value read from DATAs, to be stored of the background array
'   i, j: Coordinates of the upper-left corner of the character with
'         respect to the background (0,0 is the upper-left corner of the
'         background). Used to know the portion of the background to redraw.
'      z: Used as temporal value for x when redrawing background over character
'      t: Used as temporal value for y when redrawing background over character
'      m: Movement to be performed (0,1,2,4,8 = no,up,down,left,right)
'      s: Pointer to the start of the Background array g
'     c$: Character of the Man
'     m$: Mask of the c$ character (inverse)
'     o$: Control Codes to enable Graphics  OR Drawing Mode
'     a$: Control Codes to enable Graphics AND Drawing Mode
'     f$: Control Codes to set Graphis drawing normal mode
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
10 MODE 0:INK 0,26:BORDER 26:INK 1,0:INK 2,18:INK 3,8:INK 4,15:INK 5,6:INK 6,25:INK 7,2:INK 8,20:DEFINT a-z
' Create a Mask for the character to be used in redrawing it
20 SYMBOL 249,&C7,&C7,&6D,&83,&EF,&D7,&D7,&D7
' Grid do not need to use 2-bytes per element (a BASIC integer)
' So we define it halved, and access bytes directly using PEEK and POKE
' 20 items = 20 bytes = 10 integers
' Remember that BASIC defines arrays from 0 to NUM, so 10 elements = dim ARRAY(9)
30 DIM g(9,4)
' As we are using some variables as pointers, it is preferably to define all variables
' first (before using @ operator to point to memory locations) to prevent BASIC from
' messing around with memory re-ordering when she encounters new undefined variables
' Video Memory Start => &C000
40 x=0:y=0:xp=0:yp=0:p=0:v1=0:v2=0:i=0:j=0:z=0:t=0:m=0:s=0:q=&C000:nx=0:ny=0:ni=0:nj=0:nq=0
50 c$=CHR$(248):m$=CHR$(249):o$=CHR$(23)+CHR$(3):a$=CHR$(23)+CHR$(2):f$=CHR$(23)+CHR$(0)+CHR$(31)+CHR$(1)+CHR$(1)
60 s=@g(0,0)
' First Insert the background into the Grid Array
70 GOSUB 1000
' Than draw the complete background
80 GOSUB 2000
' Locate Main Character at its first location (0,0) and draw it
100 x=0:y=398:i=0:j=0:nx=x:ny=y:nj=j:ni=i:nq=q:GOSUB 3000
' Main Loop (Read keyboard and redraw when required
120 WHILE INKEY(18)<0:m=0
130 IF NOT INKEY(0)AND j THEN m=1ELSE IF NOT INKEY(2)AND j<12THEN m=2
140 IF NOT INKEY(8)AND i THEN m=4ELSE IF NOT INKEY(1)AND i<6THEN m=8
150 IF m<1 THEN 180
160 IF m AND 1THEN nj=j-1:ny=y+2:IF (j AND 7)=0THEN nq=q+&37B0:GOTO 170ELSE nq=q-&800:GOTO 170
164 IF m AND 2THEN nj=j+1:ny=y-2:IF (j AND 7)=7THEN nq=q-&37B0:GOTO 170ELSE nq=q+&800:GOTO 170
168 IF m AND 4THEN ni=i-1:nx=x-8:nq=q-1ELSE ni=i+1:nx=x+8:nq=q+1
170 p=s+10*j+i:t=q:z=j:CALL &BB19:DI:GOSUB 4000:j=nj:i=ni:x=nx:y=ny:q=nq:GOSUB 3000:EI
180 WEND
190 WHILE INKEY$<>"":WEND
200 MODE 2:END

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Setup Grid array - this holds main background graphics
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Read the value and insert it into the array. Array has 20 rows of 20 bytes each
' Each row corresponding to 20 values over the same yp, and increasing xp.
' So p starts pointing to g(0,0) in memory and goes increasing
' [url=http://cpctech.cpc-live.com/docs/graphics.html]Display pixel data format[/url]
1000 RESTORE 1110
1010 p=s
1020 FOR yp=0 TO 19
1030  FOR xp=0 TO 9
1040   READ v1,v2
       ' Transforms INKs for 2 pixels to 1 byte in Screen Pixel Format
1050   v1=(v1 AND/4 + (v1 AND 4)*8 + (v1 AND 2)*4 + (v1 AND 1)*128
1060   v1=v1 + (v2 AND/8 + (v2 AND 4)*4 + (v2 AND 2)*2 + (v2 AND 1)*64
1070   POKE p,v1:p=p+1
1080  NEXT xp
1090 NEXT yp
1100 RETURN
1110 DATA 2,2,2,2,2,0,0,0,0,3,3,3,0,4,4,4,0,0,0,5
1120 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
1130 DATA 2,2,2,2,2,0,0,0,0,3,3,3,4,4,4,4,4,0,0,5
1140 DATA 0,2,2,2,6,6,6,0,7,7,7,0,4,4,4,4,4,0,0,5
1150 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,4,4,4,0,0,0,5
1160 DATA 0,0,0,6,6,6,6,6,7,7,7,0,0,0,0,0,0,0,0,5
1170 DATA 0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,5
1180 DATA 0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,5
1190 DATA 0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
1200 DATA 0,0,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
1210 DATA 0,4,4,4,4,3,3,3,0,0,0,0,0,0,0,0,8,8,8,5
1220 DATA 0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5
1230 DATA 0,4,4,4,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,5
1240 DATA 0,0,4,7,7,7,7,7,0,0,0,2,2,2,0,0,0,0,0,5
1250 DATA 2,2,2,7,7,7,7,7,0,0,2,2,2,2,2,7,7,0,0,5
1260 DATA 2,2,2,7,7,7,7,7,3,3,2,2,2,2,2,7,7,7,0,5
1270 DATA 2,2,2,2,7,7,7,3,3,3,2,2,2,2,2,7,7,7,0,5
1280 DATA 2,2,2,2,0,0,3,3,3,3,3,2,2,2,7,7,7,7,0,5
1290 DATA 2,2,2,0,0,0,3,3,3,3,3,0,0,0,7,7,7,0,0,5
1300 DATA 0,0,0,0,0,0,0,3,3,3,0,0,0,0,0,0,0,0,0,5


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Initial Draw of the Background
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' p points to the start of the background array and goes byte by byte
' moving to the next byte that should be drawn to screen
2000 p=s:t=&C000:z=8
2010 FOR yp=0 to 19
2020  FOR xp=0 to 9
2030   POKE t,PEEK(p):p=p+1:t=t+1
2040  NEXT xp
2050  t=t+&7F6:z=z-1
2060  IF z THEN 2080
2070   z=8:t=t+&C050
2080 NEXT yp
2090 RETURN

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' REDRAW Character with MASK (AND + OR)
' - MASK must be drawn with pen 15 (1111) to have 1's where
'   there is no color and 0's where there is color
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
3000 PLOT -2,-2,15:?a$:MOVE x,y:TAG:?m$;:TAGOFF:PLOT -2,-2,1:?o$:MOVE x,y:TAG:?c$;:TAGOFF:?f$:RETURN

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Background redrawing over Character (all character box. using POKE)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'4000 p=s+10*j+i:t=q:FOR z=j TO j+7:POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
'4010 NEXT z:RETURN

' UNROLLED VERSION
4000 POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4010 z=z+1:POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4020 z=z+1:POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):POKE t+3,PEEK(p+3):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4030 z=z+1:POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4040 z=z+1:POKE t,PEEK(p):POKE t+1,PEEK(p+1):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4050 z=z+1:POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4060 z=z+1:POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):p=p+10:IF (z AND 7)=7THEN t=t+&C850 ELSE t=t+&800
4070 POKE t,PEEK(p):POKE t+1,PEEK(p+1):POKE t+2,PEEK(p+2):RETURN

AMSDOS

Please find attached my assembly workings of this background problem, there maybe some improvement that could be applied on the assembly routine, though results would improve from a compiled language, at the moment it's just a teaser written in BASIC.


org &4000


;; Conditions of Entry Usage :-
;; CALL &4000,<size of x loop>,<offset for x>,<size of y loop>,<xpos>,<ypos>,<address of image>

ld l,(ix+00) ;; Address of Data Colour
ld h,(ix+01)
ld (addrcolour),hl ;; Place this into Address Colour


ld l,(ix+02)
ld h,(ix+03)
ld (ypos),hl ;; Place co-ordinates of Images into Ypos


ld l,(ix+04)
ld h,(ix+05)
ld (xpos),hl ;; Place co-ordinates of Image into Xpos
ld (stxpos),hl ;; Restore value for later use


ld a,(ix+06) ;; y position of loop
ld (ylcount),a


ld a,(ix+08) ;; offset to calculate correct position of array
ld (xoffset),a


ld a,(ix+10) ;; x position of loop
ld (xlcount),a

.pltimg
ld hl,(xpos)
ex hl,de
ld hl,(ypos)
call &bbf0 ;; GRA TEST ABSOLUTE
cp 0
jr nz,iszero


ld hl,(addrcolour)
ld a,(hl)
call &bbde ;; GRA SET PEN


ld de,(xpos) ;; XPOS data into DE
ld hl,(ypos) ;; YPOS data into HL
call &bbea ;; GRA ABSOLUTE PLOT


.iszero
  ld hl,(addrcolour) ;; Take address of address colour
  inc hl ;; Increment it by 1
ld (addrcolour),hl

ld hl,(xpos) ;; Obtain Contents of XPOS
inc hl ;;   
inc hl ;; Increase XPOS by 4 (Mode 0)
inc hl ;;
inc hl ;;
ld (xpos),hl ;;

ld a,(fcount) ;; First Counter Position into A
inc a ;; Increment this
ld (fcount),a ;; Put New Value into First Count Position
ld b,a ;; Put this value into B


ld a,(xlcount) ;; Place First Counter Marker into A


cp b ;; Has value of B reached A value
jr nz,pltimg ;; If No Loop back, otherwise continue


ld a,(xoffset) ;; is there offset required to calculate next line?
cp 0 ;; if no
jr z,bypass ;; bypass this routine
ld b,a ;; otherwise size of offset can go here
.offsetzero
ld hl,(addrcolour) ;;
inc hl ;; Increase to next position
ld (addrcolour),hl ;;
djnz offsetzero ;; Loop until offset is zero


.bypass ld a,(fcount) ;; At this stage fcount equals 8
xor a ;; This will make it 0 again
ld (fcount),a ;; And put that value into fcount


ld hl,(ypos) ;; YPOS of data can now be Incremented
dec hl ;; Decrease twice for next position 
dec hl ;;
ld (ypos),hl


ld hl,(stxpos) ;; Restore value for XPOS
ld (xpos),hl ;; New Value goes into XPOS.

ld a,(scount) ;; Second counter goes into A
inc a ;; Increase it.
ld (scount),a ;; Place back into Second Counter
ld b,a ;; Put value of Second counter into B


ld a,(ylcount) ;; Place Y-counting position into A


cp b ;; Compare A to value of B
jr nz,pltimg ;; If reached exit, otherwise return

ld a,0 ;; \
ld hl,fcount ;; \\
ld (hl),a ;; Returns loop values back to 0 (important)
ld hl,scount ;; //
ld (hl),a ;; /

ret ;; Program exits here.


.fcount defb 0
.scount defb 0
.xlcount
defb 0
.ylcount
defb 0
.xoffset
defb 0
.xpos defw 0 ;; Left Position the image
.ypos defw 0 ;; Bottom Position of the image.
.stxpos defw 0


.addrcolour
defw 0 ;; Pointer for next address position of array






10 ' Move Man around Background
20 ' Grid Array - No longer exists, is loaded from memory
30 ' Ref Array - Used to map Graphical Y-Axis
40 ' p variable - used as a pointer for Grid, Ref Array & y-axis of main character
50 ' xp variable - used as x pointer for Grid
60 ' M/C Subroutine at &4000 for Displaying Background:-
70 '     This needs 6 paramaters :
80 '      <xloop> - number of times to loop for x
90 '      <xoffset> - think of this as a rounding up tool for looping to the
100 '                  next row down along the x axis. The background I've made
110 '                  is 20 x 20 in size, my loop is 9 positions across, to
120 '                  get to the correct position of the next row, add 11 to
130 '                  it.
140 '      <yloop> - number of times to loop for y
150 '      <xpos> -  Position for xpos along top left corner
160 '      <ypos> - Position for ypos along top left corner
170 '      <address of array> - start position of the array, or it is possible
180 '                           to use this to calculate the correct position
190 '                           of the background. The formula I worked out is
200 '                           <address of array>+xp1+(yp1*<size of array>)
210 '
220 DEFINT a-z : IF PEEK(&4000)<>221 THEN MEMORY &3FFF : LOAD"plotarry.bin",&4000 : LOAD"bkgnd.dat",&456B
230 MODE 0 : INK 0,26 : BORDER 26 : INK 1,0 : INK 2,18 : INK 3,8 : INK 4,15 : INK 5,6 : INK 6,25 : INK 7,2 : INK 8,20
240 DIM ref(19)
250 GOSUB 450
260 CALL &4000,20,0,20,0,398,&456B
270 x=0 : xp=0 : xp1 = xp : p=0 : yp1=p : g=ref(p)
280 GOSUB 390
290 WHILE INKEY(18)=-1
300 IF INKEY(0)<>-1 AND (p<>0) THEN p=p-1 : PLOT x+8,ref(p+8),0 : PLOT x+16,ref(p+8),0 : yp1=p : g=ref(p) : GOSUB 390
310 IF INKEY(2)<>-1 AND (p<>11) THEN p=p+1 : PLOT x+8,ref(p-1),0 : PLOT x+12,ref(p-1),0 : PLOT x+16,ref(p-1),0 : yp1=p-1 : g=ref(p-1) : GOSUB 390
320 IF INKEY(8)<>-1 AND (x<>0) THEN x=x-4 : xp=xp-1 : xp1=xp : f=x : GOSUB 390
330 IF INKEY(1)<>-1 AND (x<>44) THEN PLOT x,ref(p+2),0 : x=x+4 : f=x-4 : xp1=xp : xp=xp+1 : GOSUB 390
340 LOCATE 1,10
350 WEND
360 WHILE INKEY$<>"":WEND
370 MODE 2:END
380 ' Main character
390 PLOT -2,-2,1
400 MOVE x,ref(p)
410 TAG : PRINT CHR$(248); : TAGOFF
420 GOSUB 560
430 RETURN
440 ' Setup Ref Array - this holds Y-Coordinate positions
450 RESTORE 510
460 v=398
470 FOR p=0 TO 19
480  ref(p)=v
490  v=v-2
500 NEXT p
510 RETURN
520 ' Complicated way to fill in Background graphics around an object
530 ' xp1 & yp1 - holds x & y positions (1 step at a time) to correctly work out background where object is placed
540 ' f - holds x positions of the object
550 ' g - holds positions of the object
560 CALL &4000,9,11,9,f,g,&456B+xp1+(yp1*&14)
570 RETURN
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

With the example I wrote above with the Assembly routine to FILL in the Background, I was trying to do some experimentation using AND/OR operators, to see if I could move that Man, though preserve some of the backdrop in the process (save Filling it in). AND seems to be the Operator which does that, though it does some funny things, and my Man didn't look like the regular char 248, which had bits disappearing on him and only appeared behind certain backdrops which was usual.
Though I was going to work at generating a Backdrop for Entire Screen now I'm happy with that Snippet, though I'm going to have to make my Backdrop slightly larger for the effect to work.
For the problem above, I'm considering tackling it with a Sprite Driver with 0s around the edge of it for the backdrop to be drawn in.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ronaldo

To draw the man without overwritting the background you have to use a MASK and 2 draws:

       
  • Draw the MASK in AND mode (this clears only the pixels where the man will be drawn)
  • Draw the MAN in OR mode (adds man to background but, as pixels where MAN goes have been previously cleared, it's like only drawing the man)
This is what I suggested in the last example I posted, in the line 3000:

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' REDRAW Character with MASK (AND + OR)
' - MASK must be drawn with pen 15 (1111) to have 1's where
'   there is no color and 0's where there is color
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
3000 PLOT -2,-2,15:?a$:MOVE x,y:TAG:?m$;:TAGOFF:PLOT -2,-2,1:?o$:MOVE x,y:TAG:?c$;:TAGOFF:?f$:RETURN

       
  • a$ activates AND mode
  • o$ activates OR mode
  • m$ is the mask of the MAN
  • c$ is the MAN (character)
That's the standard way of drawing without erasing backgrounds.

AMSDOS

I followed your example from my latest example, though all I seem to be getting is a man blacking up the area and I'm not sure why, guessing I need to follow things a little bit different for it to work in my example. The only change I made was with the MOVE x,y to MOVE x,ref(p), ref(p) holds the position of Y, so I don't think that would be the issue.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ronaldo

The man seems to be correctly drawn, but you don't seem to be erasing it when it moves: you seem to be just drawing it again, in a new position, over the backgorund.

The man is drawn transparent, but if you don't erase it when it moves, it stays there, creating a brush effect.

AMSDOS

Quote from: ronaldo on 14:34, 03 July 15
The man seems to be correctly drawn, but you don't seem to be erasing it when it moves: you seem to be just drawing it again, in a new position, over the backgorund.

The man is drawn transparent, but if you don't erase it when it moves, it stays there, creating a brush effect.


Oh okay. For some reason I thought it was all been taken care of. So if I just do a XOR of itself, that will remove those parts then restore that part of the background.


When you were returning to Fill Mode (f$), you have CHR$(31)+CHR$(1)+CHR$(1) on the end of it, I wasn't sure what that bit was for.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

Okay so I've put in a XOR to remove the graphic & draw the background back in when a key is pressed, which works well. I've modified the routines for drawing the man and erasing him to handle it from assembly which has improved how well the man travels, though he's always going to blink when this approach, but given with what I've come up with here, it's quite good.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

ronaldo

It works. You can work on optimizations and improvements, but you now have a working version :)

Nice work :D

AMSDOS

Oops, I temporarily forgot the Sprite Driver operates a little bit differently onscreen.
Up to this point, everything I've done is working on Graphical PEN colours and GRA WR CHAR works the same. So when I start poking around with a Sprite Driver, those Graphical PEN Colours are stored into Bytes, which produces a different result.
Sprite Driver in my case uses SCR DOT POSITION as a base position, though maps the screen differently as well. So all of a sudden you don't have 0-640, 0-398, and in my situation (using Mode 0), SCR DOT POSITION gives me 0-160,0-199 to work with, so if I say 0,199 & use SCR DOT POSITION, it returns &C000 (which is correct), but then I go 1,199 & use SCR DOT POSITION, that also gives me &C000 & then if I say 2,199, it gives me &C001, presumably because a MODE 0 Encoded INK holds 2 Pen Colours, and then the Sprite Driver moves the graphic around a little bit differently to what you can get with GRA WR CHAR because of the way Sprite Drivers handle whole Bytes instead of just an Graphical Pen Colour.
The easiest way to adjust for Sprite Driver, is to have it's own set of independent variables to avoid messing around with the others which restore the screen, though with the change in how the character is moved, the correct position needs to be used to restore the background.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS


This is my latest monster I've come up with:


10 ' Move Man around Background
20 ' Variables Used :-
30 '     Ref Array - Used to map Graphical Y-Axis
40 '     p variable - used as a pointer for Grid, Ref Array & y-axis of main
50 '     character
60 '     xp variable - used as x pointer for Grid
70 '     x1 & y1 - these hold Byte Values for the Main Sprite
80 '
90 ' M/C RSX @ &9000 for Handling Sprites & Background,
100 ' Commands Are :-
110 '     XOR - From Sean McManus ESD2, I'm using this to delete main
120 '           character when he moves, paramaters are:-
130 '           <address of sprite>,<xpos = 0-160>,<ypos = 0-199>
140 '     OVERLAY - Also from Sean McManus ESD2, used to draw Main Character to
150 '               new position, paramater are:-
160 '               <address of sprite>,<xpos = 0-160>,<ypos = 0-199>
170 '     RESTORE - Used for drawing Background around Main Character (line
180 '               840) or for drawing in Background (line 460)
190 '     This needs 6 paramaters :
200 '      <xloop> - number of times to loop for x
210 '      <xoffset> - think of this as a rounding up tool for looping to the
220 '                 next row down along the x axis. The background I've made
230 '                 is 20 x 20 in size, my x loop is 14 positions across, to
240 '                  get to the correct position of the next row, add 6 to
250 '                  get the next line.
260 '      <yloop> - number of times to loop for y
270 '      <xpos> - Position for xpos along top left corner
280 '      <ypos> - Position for ypos along top left corner
290 '      <address of array> - start position of the array, or it is possible
300 '                           to use this to calculate the correct position
310 '                           of the background. The formula I worked out is
320 '                           <address of array>+xp1+(yp1*<size of array>)
330 '
400 DEFINT a-z
410 IF PEEK(&9000)<>33 THEN MEMORY &3FFF : LOAD"bkgnd.dat",&4000 : LOAD"driver.bin",&9000
420 CALL &9000
430 MODE 0 : INK 0,26 : BORDER 26 : INK 1,0 : INK 2,18 : INK 3,8 : INK 4,15 : INK 5,6 : INK 6,25 : INK 7,2 : INK 8,20
440 DIM ref(19)
450 GOSUB 710
460 |RESTORE,20,0,20,0,398,&4000
470 x=0 : x1=0 : y1=199 : xp=0 : xp1 = xp : p=0 : yp1=p : g=ref(p)
480 GOSUB 610 : GOSUB 840
490 WHILE INKEY(18)=-1
500 IF INKEY(0)<>-1 AND (p<>0) THEN p=p-1 : |XOR,&9172,x1,y1 : y1=y1+1 : yp1=p : g=ref(p) : GOSUB 610 : GOSUB 840
510 IF INKEY(2)<>-1 AND (p<>11) THEN p=p+1 : |XOR,&9172,x1,y1 : y1=y1-1 : yp1=p-1 : g=ref(p-1) : GOSUB 610 : GOSUB 840
520 IF INKEY(8)<>-1 AND (x<>0) THEN x=x-4 : |XOR,&9172,x1,y1 : x1=x1-2 : xp=xp-1 : xp1=xp : f=x : GOSUB 610 : GOSUB 840
530 IF INKEY(1)<>-1 AND (x<>20) THEN x=x+4 : |XOR,&9172,x1,y1 : x1=x1+2 : f=x-4 : xp1=xp : xp=xp+1 : GOSUB 610 : GOSUB 840
540 LOCATE 1,10
550 WEND
560 WHILE INKEY$<>"":WEND
570 MODE 2:END
600 ' Main character
610 |OVERLAY,&9172,x1,y1
620 RETURN
700 ' Setup Ref Array - this holds Y-Coordinate positions
710 v=398
720 FOR p=0 TO 19
730  ref(p)=v
740  v=v-2
750 NEXT p
760 RETURN
800 ' Complicated way to fill in Background graphics around an object
810 ' xp1 & yp1 - holds x & y graphical positions of the background
820 ' f - holds x position of the object
830 ' g - holds y position of the object
840 |RESTORE,14,6,9,f,g,&4000+xp1+(yp1*&14)
850 RETURN



It works by loading background data, which is using Graphic Pen colours to draw the image using RESTORE, a little Green Man is then drawn to Screen using Sean McManus Overlay Sprite Driver from ESD2, once you begin moving the little Green Man, the sprite is XORed (also from ESD2) to remove it, followed by using Overlay to draw in new position and an RESTORE to fill in the appropriate bits of background.


The reason the Background is a Graphic is due to the nature of the RESTORE command, which uses GRA TEST ABSOLUTE to determine what needs to be drawn. The slight flicker happens when OVERLAY is used & RESTORE draws the background. It maybe possible to make RESTORE redundant by working out which edge to restore based on it's movement, which is kind of what my earlier programs were doing.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

#16
I've only done some trial tests from the program above, which involves converting the background into a series of Bytes, and POKEing those values for the background, based on when I have moved the graphic using OVERLAY and found the dilemma.


[attachimg=1]


In my example my little person isn't flat around the edges. So in my example the character is being drawn in MODE 0 (yes he does look a little too square to be MODE 0, but that's just me quickly knocking something up in an PC art prog), so what happens when the man is stored as a byte as a sprite, 2 bytes are allocated per pixels (left & right). So in my example on the top line (Left to Right) OVERLAY is good enough to detect the 2 zero bytes at the beginning, so doesn't overwrite the background, but as soon as it goes to the next 2 bytes which is a zero followed by an one, the OVERLAY won't register that as an Zero and that Zero has just overwritten part of the background - without any chance of restoring it. So in effect what RESTORE does in my routine above, is use the position I've provided through calculating the position of the background and draw that part of the background back in. Of course it flickers a little bit in effect, though from memory I think made it a little bit faster by only working out where the Zero's will be. You may also notice that using this approach in the program above no FRAME Flyback effects have been used.







* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

#17
This is my latest rendition, which replaces the Graphics Restoration routine for the Background and implements a Screen Based one.




10 ' Move Man around Background
20 ' Variables Used :-
30 '     yp variable - used for calculating ypos relative to background
40 '     xp variable - used for calculating xpos relative to background
50 '     x1 & y1 - these hold Byte Values for the Main Sprite
60 '
70 ' M/C RSX @ &9000 for Handling Sprites & Background,
80 ' Commands Are :-
90 '     XOR - From Sean McManus ESD2, I'm using this to delete main
100 '           character when he moves, paramaters are:-
110 '           <address of sprite>,<xpos = 0-160>,<ypos = 0-199>
120 '     OVERLAY - Also from Sean McManus ESD2, used to draw Main Character to
130 '               new position, paramater are:-
140 '               <address of sprite>,<xpos = 0-160>,<ypos = 0-199>
150 '     RESTORE - Used for drawing Background around Main Character (line
160 '               740) or for drawing in Background (line 440)
170 '     This needs 6 paramaters :
180 '      <xloop> - number of times to loop for x
190 '      <xoffset> - think of this as a rounding up tool for looping to the
200 '                 next row down along the x axis. The background I've made
210 '                 is 10 x 20 in size, my x loop is 6 positions across, to
220 '                 get to the correct position of the next row, add 4 to
230 '                 get the next line.
240 '      <yloop> - number of times to loop for y
250 '      <xpos> - Position for xpos along top left corner
260 '      <ypos> - Position for ypos along top left corner
270 '      <address of array> - start of the background, or it is possible
280 '                           to use this to calculate the position
290 '                           of the background. The formula I worked out is
300 '                           <address of array>+xp1+(yp1)
310 '
400 DEFINT a-z
410 IF PEEK(&9000)<>33 THEN MEMORY &7FFF : LOAD"driver.bin",&9000
420 CALL &9000
430 MODE 0 : INK 0,0 : BORDER 0 : INK 1,26 : INK 2,18 : INK 3,8 : INK 4,15 : INK 5,6 : INK 6,25 : INK 7,2 : INK 8,20
440 ad=&915F : |RESTORE,10,0,20,0,199,ad
450 x1=0 : y1=199 : xp=0 : yp=0
460 GOSUB 610
470 WHILE INKEY(18)=-1
480 IF INKEY(0)<>-1 AND (y1<>199) THEN |XOR,&9227,x1,y1 : GOSUB 740 : y1=y1+1 : yp=yp-10 : GOSUB 610
490 IF INKEY(2)<>-1 AND (y1<>188) THEN |XOR,&9227,x1,y1 : GOSUB 740 : y1=y1-1 : yp=yp+10 : GOSUB 610
500 IF INKEY(<>-1 AND (x1<>0) THEN |XOR,&9227,x1,y1 : GOSUB 740 : x1=x1-2 : xp=xp-1 : GOSUB 610
510 IF INKEY(1)<>-1 AND (x1<> THEN |XOR,&9227,x1,y1 : GOSUB 740 : x1=x1+2 : xp=xp+1 : GOSUB 610
520 LOCATE 1,10
530 WEND
540 WHILE INKEY$<>"":WEND
550 MODE 2:END
600 ' Main character
610 |OVERLAY,&9227,x1,y1
620 CALL &BD19
630 RETURN
700 ' Fill in Background graphics around an object
710 ' xp & yp - are used to work out the background position
720 ' Formula is <start address of Background>+xp+(yp) lookup lines 480-510
730 ' to see how I have calculated xp and yp to get this result
740 |RESTORE,6,4,9,x1,y1,&915F+(xp+yp)
750 RETURN



So this is a lot more polished, so no flicker occurring in the Background (I'm using LDI to poke it in), and a small amount of flicker from the main sprite that seems to occur after the sprite has been stationary. I removed a lot of variables from the BASIC program, main reason was due to calculating Graphical positions in the earlier version. The compromise here is not having Backdrop to the edge of the Main Sprite, though in some places you can see this happening, this is because the Overlay Sprite routine has detected an zero byte. In MODE 0 a byte represents a Left Most Pixel & a Right Most Pixel, so in the event of a Right Most Pixel occurring, the Overlay Sprite Routine will plot a Left Most one as well (even if it's an zero).
Guess I need to improve my Sprite Handing and use a different INK for the edge, though I didn't think this looked too bad.
EDIT:Sorry I wanted to add my assembly source code, but it's using parts of ESD2 and I'm unsure if Sean wants to see his code splashed on the forum. I can edit it down to just my routine if anyone wants to look at it or improve it.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

AMSDOS

Quote from: ronaldo on 19:52, 14 June 15


       
  • I've changed Grid matriz from DIM Grid(19,19) to DIM g(9,9). As integers in BASIC are 2-bytes wide, but we only need 1 byte to store values from 0 to 15 (INKs), this halves the required space. Also, accessing it manually (using POKE, PEEK and a pointer) is much faster.


This would seem to support the issue in this program I made earlier. By contrast the array in that could be half the size, though it would simply be easier to scrap the array and set aside some memory to poke the data to.


Perhaps it would be better to utilise an array more like a pointer where each component simply holds an address of an position in memory? Which is how I've been tackling Information in Assembly (by having pointers pointing to them).
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Powered by SMFPacks Menu Editor Mod