News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_EgoTrip

Screen Wipe

Started by EgoTrip, 19:19, 16 September 13

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

EgoTrip

I suck at maths and can't figure out how to do this.

What I want is a screen wipe, that fills the screen with spaces (or chr$(143) to show it working) in a clockwise motion starting from the top left corner and finishing in the center, if you get me.

How would you do it in both BASIC (slow I know) and machine code?

redbox

You could use variables to define the boundaries and also the current x and y.

So in all it would be 6 variables: x and y, x-left, x-right, y-top and y-bottom.

Then write loops such as:

Increase x until it reaches x-right
Decrease x-right by 1
Increase y until it reaches y-bottom
Decrease y-bottom by 1
Decrease x until it reaches x-left
Increase x-left by 1
Decrease y until it reaches y-top
Increase y-top by 1

Check to see if we've got to the desired end variables, and if not then repeat.

TFM

Well first I would adjust the number of lines to the number of columns, else it obviously can't work.





TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

redbox

Quote from: TFM on 22:15, 16 September 13
Well first I would adjust the number of lines to the number of columns, else it obviously can't work.

The algorithm I described above would still work without equal lines and columns.

tastefulmrship

Quote from: redbox on 22:13, 16 September 13
You could use variables to define the boundaries and also the current x and y.

So in all it would be 6 variables: x and y, x-left, x-right, y-top and y-bottom.

Then write loops such as:

Increase x until it reaches x-right
Decrease x-right by 1
Increase y until it reaches y-bottom
Decrease y-bottom by 1
Decrease x until it reaches x-left
Increase x-left by 1
Decrease y until it reaches y-top
Increase y-top by 1

Check to see if we've got to the desired end variables, and if not then repeat.


10 MODE 1
20 PAPER 2
30 CLS
40 PAPER 0
50 :
60 XPosition%=1 :YPosition%=1
70 XMinimum%=1  :YMinimum%=2
80 XMaximum%=40 :YMaximum%=25
90 XDirection%=1:YDirection%=0
100 :
110 TempXDirection%=XPosition%
120 TempYDirection%=YPosition%
130 :
140 WHILE XMaximum%>27
150    LOCATE XPosition%,YPosition%
160    PRINT " ";
170    :
180    TempXPosition%=XPosition%+XDirection%
190    TempYPosition%=YPosition%+YDirection%
200    :
210    IF TempXPosition%>XMaximum% AND XDirection%= 1 THEN XDirection%= 0:YDirection%= 1:XMaximum%=XMaximum%-1:GOTO 180
220    IF TempXPosition%<XMinimum% AND XDirection%=-1 THEN XDirection%= 0:YDirection%=-1:XMinimum%=XMinimum%+1:GOTO 180
230    IF TempYPosition%>YMaximum% AND YDirection%= 1 THEN XDirection%=-1:YDirection%= 0:YMaximum%=YMaximum%-1:GOTO 180
240    IF TempYPosition%<YMinimum% AND YDirection%=-1 THEN XDirection%= 1:YDirection%= 0:YMinimum%=YMinimum%+1:GOTO 180
250    :
260    XPosition%=TempXPosition%:YPosition%=TempYPosition%
270 WEND

EgoTrip

#5
Thanks a lot thats perfect. Now I need to figure out how to do it in machine code so it works faster.

I dont know how to test if a variable is greater or less than another in machine code. So I guess that I'm gonna fail at this excercise :(

redbox

Just use the CP instruction. 

If equal, Z flag is set. If argument is greater, C is set. If none set, then A is greater.


ld a,number
cp 40
jp z,equal
jp c,lessthan
jp morethan



ervin

Nice work tastefulmrship!
Here's your code converted to ccz80.


include "cpc6128.ccz80";

byte xPosition,yPosition;
byte xMinimum,yMinimum;
byte xMaximum,yMaximum;
byte xDirection,yDirection;
byte tempXPosition,tempYPosition;
byte tempXDirection,tempYDirection;

mode(1);
paper(2);

cls();
paper(0);

xPosition=1;
yPosition=1;

xMinimum=1;
yMinimum=2;

xMaximum=40;
yMaximum=25;

xDirection=1;
yDirection=0;

tempXDirection=xPosition;
tempYDirection=yPosition;

while (xMaximum>27)
{
locate(xPosition,yPosition);
prints(" ");

LOOP:

tempXPosition=xPosition+xDirection;
tempYPosition=yPosition+yDirection;

if ((tempXPosition>xMaximum) && (xDirection==1))
{
  xDirection=0;
  yDirection=1;
  xMaximum--;
  goto LOOP;
}

if ((tempXPosition<xMinimum) && (xDirection==-1))
{
  xDirection=0;
  yDirection=-1;
  xMinimum++;
  goto LOOP;
}

if ((tempYPosition>yMaximum) && (yDirection==1))
{
  xDirection=-1;
  yDirection=0;
  yMaximum--;
  goto LOOP;
}

if ((tempYPosition<yMinimum) && (yDirection==-1))
{
  xDirection=1;
  yDirection=0;
  yMinimum++;
  goto LOOP;
}

xPosition=tempXPosition;
yPosition=tempYPosition;
}

return;


tastefulmrship

Sorry, guys!!! It was late last night and I had to resort to using the dreaded GOTO (my Computer Studies teacher would've caned me for using it), so here's a Structured BASIC "updated" version of the screen-wipe code.


10 MODE 1
20 PAPER 2
30 CLS
40 PAPER 0
50 :
60 XPosition%= 1:YPosition%=  1
70 XMinimum%=  1:YMinimum%=   1
80 XMaximum%= 40:YMaximum%=  25
90 XDirection%=0:YDirection%=-1
100 :
110 WHILE XMaximum%>27
120    :
130    TempXDirection%=XPosition%
140    TempYDirection%=YPosition%
150    :
160    LOCATE XPosition%,YPosition%
170    PRINT " ";
180    :
190    TempXPosition%=XPosition%+XDirection%
200    TempYPosition%=YPosition%+YDirection%
210    :
220    IF TempXPosition%>XMaximum% AND XDirection%= 1 THEN XDirection%= 0:YDirection%= 1:XMaximum%=XMaximum%-1
230    IF TempXPosition%<XMinimum% AND XDirection%=-1 THEN XDirection%= 0:YDirection%=-1:XMinimum%=XMinimum%+1
240    IF TempYPosition%>YMaximum% AND YDirection%= 1 THEN XDirection%=-1:YDirection%= 0:YMaximum%=YMaximum%-1
250    IF TempYPosition%<YMinimum% AND YDirection%=-1 THEN XDirection%= 1:YDirection%= 0:YMinimum%=YMinimum%+1
260    :
270    XPosition%=XPosition%+XDirection%
280    YPosition%=YPosition%+YDirection%
290    :
300 WEND
310 LOCATE 1,1


@ervin; Could you please convert this version to ccz80? Ta, muchly!

AMSDOS

Quote from: EgoTrip on 19:19, 16 September 13
I suck at maths

Must be doing something right with games like "Subtera Puzlo" or was that Redbox doing all that?  :)


* Using the old Amstrad Languages :D * And create my own ;)
* Incorporating 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

Axelay

An assembly version, using firmware.  Cut & paste into Winape or another emulator assembler, assemble it and then call &8000 from basic.  I've used a slightly different approach to the previous examples so that the number of variables and comparisons is smaller.  There is just a current cursor x & y in hl, the clear region height & width in de, plus an index which loops around the 4 different directions held in c.


org &8000
run &8000

TXT_SetCursor equ &bb75
TXT_Output equ &bb5a
SCR_SetMode equ &bc0e
GRA_SetPaper equ &bbe4
GRA_ClearWindow equ &bbdb

.Start
; set up display
  ld a,1
  call SCR_SetMode
  ld a,2
  call GRA_SetPaper
  call GRA_ClearWindow
  ld a,0
  call GRA_SetPaper

; the four directions the clearing moves in are stored as a lookup table to avoid multiple comparisons on direction change
  ld c,0 ; index or pointer to y & x move lookup table
; clear region dimensions
  ld d,40 ; x width
  ld e,25-1 ; y height, less one because one row already cleared at first y move
; start position.  As routine will clear an ever decreasing 'swirl', the start position character will be left 'stranded' unless
; the routine moves to new position first, then clears that char, rather than clearing at the current char & then moving the cursor.
; As a result, the start position is not cleared, and in this case is a dummy off screen position
  ld h,1-1 ; x position start, 1 step left of actual position
  ld l,1 ; y position start

  ld b,d ; get counter for initial direction, which is in x, or clear region width
  dec d ; decrease x or region width for next time
.WipeLoop
; first step is move the char ptr to the next position,
; so find direction of next char
  ld ix,DirectionLookup
  push bc ; preserve counter in b
  ld b,0 ; zero b so bc is offset in direction lookup table
  add ix,bc ; add lookup offset to base of direction table
  pop bc ; restore counter in b
; get new x from lookup table
  ld a,(ix+0) ; get x change for current dir
  add a,h ; add to current x
  ld h,a ; place back in current x
; get new y
  ld a,(ix+1) ; get y change for current dir
  add a,l ; add to current y
  ld l,a ; place back in current y

; now clear character at new x,y pos
  push de:push bc:push hl ; preserve registers
  call TXT_SetCursor ; locate cursor at hl
  ld a,32 ; ascii code for space
  call TXT_Output ; print the space
  pop hl:pop bc:pop de ; restore registers

; repeat if end of current row or col not reached
  dec b
  jr nz,WipeLoop

; b=0, time to change direction
  ld a,c ; get direction index
  add a,2 ; move to next direction
  and a,7 ; loop between the 4 directions by restricting index to 0,2,4,6
  ld c,a ; c now points to index of new x & y direction

; get length of new direction, first determine if moving in x or y
  bit 1,a ; check second bit of a, when a = 0 or 4, then bit 1 is 0 so is x move
          ; when a = 2 or 6, bit 1 is 1 so is y move
  jr nz,MovinginY

; moving in X
  xor a ; set a=0
  cp a,d ; check if region height has reduced to 0
  jr z,WipeDone ; has cleared entire region if d=0
  ld b,d ; set counter to current width of clear region
  dec d ; decrease x or region width for next time
  jr WipeLoop

.MovinginY
  xor a ; set a=0
  cp a,e ; check if region width has reduced to 0
  jr z,WipeDone ; has cleared entire region if d=0
  ld b,e ; set counter to current height of clear region
  dec e ; decrease y or region height for next time
  jr WipeLoop

.WipeDone
  ret
;  jr Start

.DirectionLookup ; format is x direction, y direction, starting from top left of clear region, clearing clockwise
                 ; with screen co-ord system 1,1 at top left
  defb 1,0,0,1,-1,0,0,-1


ervin

Quote from: tastefulmrship on 09:28, 17 September 13
@ervin; Could you please convert this version to ccz80? Ta, muchly!

Sure! Here you go.


include "cpc6128.ccz80";

byte xPosition,yPosition;
byte xMinimum,yMinimum;
byte xMaximum,yMaximum;
byte xDirection,yDirection;
byte tempXPosition,tempYPosition;

mode(1);
paper(2);

cls();
paper(0);

xPosition=1;
yPosition=1;

xMinimum=1;
yMinimum=1;

xMaximum=40;
yMaximum=25;

xDirection=0;
yDirection=-1;

while (xMaximum>27)
{
    locate (xPosition,yPosition);
    prints(" ");

    tempXPosition=xPosition+xDirection;
    tempYPosition=yPosition+yDirection;

    if ((tempXPosition>xMaximum) && (xDirection==1))
    {
        xDirection=0;
        yDirection=1;
        xMaximum--;
    }

    else if ((tempXPosition<xMinimum) && (xDirection==-1))
    {
        xDirection=0;
        yDirection=-1;
        xMinimum++;
    }

    else if ((tempYPosition>yMaximum) && (yDirection==1))
    {
        xDirection=-1;
        yDirection=0;
        yMaximum--;
    }

    else if ((tempYPosition<yMinimum) && (yDirection==-1))
    {
        xDirection=1;
        yDirection=0;
        yMinimum++;
    }

    xPosition+=xDirection;
    yPosition+=yDirection;
}

locate(1,1);
return;

EgoTrip

Quote from: AMSDOS on 09:44, 17 September 13
Must be doing something right with games like "Subtera Puzlo" or was that Redbox doing all that?  :)

Yeah, Redbox did all the z80 coding, I did everything else.

Thanks everyone for your help on this.

ervin

I've gotta say, I'm surprised at PRINT's performance when called from assembler or ccz80.
It runs much quicker than I thought it would.

Under BASIC of course it's very slow - though it's likely that it isn't PRINT itself that is slow, but the data being sent to PRINT.
And of course all the other code in BASIC runs slowly as well, which has, for all these years, skewed my opinion of PRINT's speed.
(After all, our assembly, ccz80 and BASIC versions all use the same firmware call to print).

I'm having some trouble explaining this - I hope you all know what I mean!
:-[

Let me try this way:
- PRINT has never been as slow as I thought
- It's the code around it that is slow
- When the code around PRINT is compiled, it makes PRINT look a lot faster

Yeah, maybe that's sort of what I'm trying to say.

Anyway, just thinking out loud!


AMSDOS

Quote from: ervin on 00:49, 18 September 13
I've gotta say, I'm surprised at PRINT's performance when called from assembler or ccz80.
It runs much quicker than I thought it would.

Under BASIC of course it's very slow - though it's likely that it isn't PRINT itself that is slow, but the data being sent to PRINT.
And of course all the other code in BASIC runs slowly as well, which has, for all these years, skewed my opinion of PRINT's speed.
(After all, our assembly, ccz80 and BASIC versions all use the same firmware call to print).

I'm having some trouble explaining this - I hope you all know what I mean!
:-[

Let me try this way:
- PRINT has never been as slow as I thought
- It's the code around it that is slow
- When the code around PRINT is compiled, it makes PRINT look a lot faster

Yeah, maybe that's sort of what I'm trying to say.

Anyway, just thinking out loud!

The way I see it, you're comparing an Interpreted Language (BASIC) to some Compiled Languages, so every instruction in the BASIC program is tokenised and needs an Interpreter to convert it into Machine Code for the machine to understand it, which is where the delay comes from.

So I suppose if you were to write a whole chain of RSXes which talk to the firmware via a series of M/C Routines to access via BASIC, then things will start moving a lot quicker.
* Using the old Amstrad Languages :D * And create my own ;)
* Incorporating 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