Jump to content


Photo

Wraparound Guardians


  • Please log in to reply
8 replies to this topic

#1 IRF

IRF

    Advanced Member

  • Contributor
  • 3,640 posts

Posted 01 March 2018 - 04:39 PM

I have managed to amend the code which moves vertical guardians, and also the guardian-drawing and sprite-drawing routines, in such a way that a guardian may safely wrap around past the top/bottom of the screen without crashing into its own 'trail of havoc' (i.e. errant pixels left on the primary screen buffer.

Please see the attached. The starting room is 'On Top of the House'. There are now two flag guardians in that room, which have identical definition bytes to each other except that, for one of the flags, the upper and lower bounds have been transposed (causing it to wander up off the top of the screen and back again).

I thought it was appropriate to use the flag guardians to illustrate this behaviour, as I managed to achieve this technical novelty by careful use of the F Register flags (the Zero, Carry and Parity Flags were all instrumental).

I'll type up the source code when I find the time. But note that the same routine handles both guardians.

Attached Files


Edited by IRF, 03 March 2018 - 09:20 AM.


#2 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 1,888 posts

Posted 01 March 2018 - 06:16 PM

Interesting stuff, Ian! Congratulations on this novelty :).



#3 Spider

Spider

    XOR (HL)

  • Administrator
  • 3,147 posts

Posted 02 March 2018 - 11:27 AM

Excellent. :)


  • IRF likes this
Changing order to chaos since 1984

#4 IRF

IRF

    Advanced Member

  • Contributor
  • 3,640 posts

Posted 03 March 2018 - 09:23 AM

Horizontal and Vertical Guardians can now wrap around both the vertical and horizontal edges of the screen - see the attached.

 

Note that the horizontal guardians do not change Base Sprite as they wrap around (which they do in the original JSW game engine).

 

Getting both the graphic bytes and attributes to fully behave was quite a challenge.  But I got there in the end.  :)

 

P.S. In the test file (startup room = Back Door), don't be surprised if the two guardians eventually collide with each other!

Attached Files


Edited by IRF, 03 March 2018 - 09:23 AM.


#5 Spider

Spider

    XOR (HL)

  • Administrator
  • 3,147 posts

Posted 03 March 2018 - 12:19 PM

That's brilliant. :)

 

It does slightly remind me in a way of how some guardians in T.Ted can behave (this is a positive comment) too.

 

It certainly is an interesting twist on things. :thumbsup:


Changing order to chaos since 1984

#6 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 1,888 posts

Posted 03 March 2018 - 08:26 PM

Congratulations again, Ian! :)



#7 IRF

IRF

    Advanced Member

  • Contributor
  • 3,640 posts

Posted 08 March 2018 - 05:02 PM

Several things needed to be done to achieve these wraparound guardians.

 

- In the 'Draw a sprite' routine (#9456), I added a command after the code at #9482-85 [original addresses] which moves HL down from one vertical screen-third to the next.  The command RES 4, H ensures that the guardian doesn't extend from the secondary pixel-buffer into the primary pixel-buffer, but wraps back round to the top of the former. i.e. a value #70xx is adjusted to #60xx.

 

- Also in 'Draw a sprite', after the INC L command at #9462 [original address], I made a check to see if the right-hand half of the sprite is wrapping round to the left-hand side of the screen:

LD A,L

AND #1F

If that sets the Zero Flag, then subtract #20 and load back to L, draw the graphic byte under consideration and then add #20 again before moving down to draw the next pair of graphic bytes on the next pixel-row.

 

- The 'Draw a guardian' routine also needs to be adjusted, in a similar manner to the above, to keep the guardian's colour attributes within the same character row when it is wrapping round past the right-hand edge of the screen, and also to prevent its colour attribute being written permanently onto the primary attribute buffer when it is wrapping past the bottom of the screen.  In the latter case, a RES 1, H command is used to adjust a value for the attribute coordinates of #5Exx to #5Cxx, which is back within the valid range.

 

- In the 'Move the guardians' routine, a simple adjustment has been made for horizontal guardians at #9151 and #9174 [original addresses], in order to prevent the guardians from changing sprite (which previously occurred because the DEC (IX+$02) / INC (IX+$02) commands meant that the adjustment of the x-coordinate in Bits 0-4 was spilling over into the Base Sprite setting in Bits 5-7).  Preventing this was achieved by loading the guardian byte definition byte 02 into both the Accumulator and the C register, then adjusting A accordingly for the appropriate direction of movement (e.g. applying a DEC A or an INC A, although in the test file uploaded above I have implemented the shared left/right movement code for guardians), and then doing the following sequence:

XOR C

AND #1F

XOR C

before reloading the result in A back to IX+$02.  That adjusts the x-coordinate from #00 to #1F or vice versa, whilst leaving the Base Sprite setting unaltered.

 

- The changes to the vertical guardians part of the 'Move the guardians' routine are the 'piece de resistance'!  After the code which updates the animation frame for vertical guardians (or not, depending on the animation speed), I have devised the following [starts at #9193 in the original code], which was built upon an earlier draft of this part of the routine provided by Norman Sword:

 

(Note that HL is pointing at guardian definition byte 00 going into this, after a pair of commands PUSH IX / POP HL.)

 

INC HL

INC HL

INC HL                            ;HL points at guardian definition byte 03 (pixel y-coordinate)

LD A, (HL)

INC HL                            ;HL now points at guardian definition byte 04 (vertical speed)

ADD A, (HL)

LD B, A                            ;A and B now both hold the updated y-coordinate

LD C, #00                        ;C will be used to keep track of various flags

LD D, (IX+$06)                ;upper bound of guardian in D

LD E, (IX+$07)                ;lower bound of guardian in E

CP D                               ;has the guardian moved past its upper bound?
RR C                               ;rotate a raised flag into C if so
CP E                               ;has the guardian moved past its lower bound?
RR C                               ;rotate a lowered flag into C if so [or if it is exactly at its upper bound, but that situation is dealt with separately below]
LD A, E                           ;load the guardian's lower bound into A
CP D                               ;if this is a normal vertical guardian, then E>D; if it is a wraparound, then D>E
RR C                               ;rotate a flag into C (raised only for a wraparound vertical guardian)
BIT 7, (HL)                      ;is the guardian currently moving downwards?
JR Z, down                     ;if so, skip the next command
LD A, D                           ;otherwise, load the guardian's upper bound into A (the guardian is currently moving upwards)
 
down:
CP B                               ;has the guardian exactly reached the extent of its permitted range for the current direction of travel?
JR Z, change_direction  ;if so, then jump to toggle the direction of travel
RRC C                            ;this command doesn't change the value in C, it merely test the status of the Parity Flag
JP PO, y_update            ;If Parity is odd, then jump to update y-coordinate with the value stored in B (the guardian is within its permitted range)
LD B, A                           ;otherwise, if Parity is even, then the guardian has exceeded its permitted range, so load up B with the extent of its permitted range for the current direction of travel
 
change_direction:
LD A, (HL)                      ;load vertical speed into A
NEG                               ;toggle it to reverse the guardian's direction of travel
LD (HL), A                      ;and load back into guardian byte 04
 
y_update:
DEC HL                         ;HL points at guardian definition byte 03 again (pixel y-coordinate)
LD (HL), B                     ;update the guardian's y-coordinate with the value stored in B
 
That is then directly followed by (or a jump is made to) the existing command LD DE, #0008 at #91B6.
 
I'll add some commentary about the use of the Parity Flag when I get more time.

Edited by IRF, 08 March 2018 - 06:02 PM.


#8 IRF

IRF

    Advanced Member

  • Contributor
  • 3,640 posts

Posted 08 March 2018 - 06:07 PM

More analysis on the use of the Parity Flag in the above, for handling wraparound vertical guardians:
C starts off holding 00000000 (Parity Even)
 
Normal vertical guardian - three scenarios (other than a guardian located exactly on one of its bounds, which is dealt with by a separate check):
 
 
TOP OF SCREEN
GUARDIAN POSITION
UPPER BOUND IN D
LOWER BOUND IN E
BOTTOM OF SCREEN
 
C=01100000; Parity Even, guardian is out of bounds
 
 
TOP OF SCREEN
UPPER BOUND IN D
GUARDIAN POSITION
LOWER BOUND IN E
BOTTOM OF SCREEN
 
C=00100000; Parity Odd, guardian is within its permitted bounds
 
 
TOP OF SCREEN
UPPER BOUND IN D
LOWER BOUND IN E
GUARDIAN POSITION
BOTTOM OF SCREEN
 
C=00000000; Parity Even, guardian is out of bounds
 

 

Wraparound vertical guardian - three scenarios (other than a guardian located exactly on one of its bounds, which is dealt with by a separate check):
 
 
TOP OF SCREEN
GUARDIAN POSITION
LOWER BOUND IN E
UPPER BOUND IN D
BOTTOM OF SCREEN
 
C=11100000; Parity Odd, guardian is within its permitted bounds
 
 
TOP OF SCREEN
LOWER BOUND IN E
GUARDIAN POSITION
UPPER BOUND IN D
BOTTOM OF SCREEN
 
C=10100000; Parity Even, guardian is out of bounds
 
 
TOP OF SCREEN
LOWER BOUND IN E
UPPER BOUND IN D
GUARDIAN POSITION
BOTTOM OF SCREEN
 
C=10000000; Parity Odd, guardian is within its permitted bounds
 


#9 IRF

IRF

    Advanced Member

  • Contributor
  • 3,640 posts

Posted 09 March 2018 - 10:29 AM

RRC C ;this command doesn't change the value in C, it merely tests the status of the Parity Flag


Just to clarify, the above isn't strictly true - the eight bits of C are rotated rightwards once by the operation.

What I meant to say is that the RRC C command doesn't alter the balance of the number of set/reset bits in C, and so the balance of parity isn't changed by the operation; rather it tests what that balance is (i.e. whether an odd or an even number of bits are set), and then the conditionality of the subsequent jump is determined on that basis.

Whereas the three preceding RR C commands did determine the balance of parity in C (because RR is a nine-bit rotation, bringing the Carry Flag into Bit 7 of the register), the RRC is an eight-bit 'internal' rotation of C (it also copies Bit 0 of C into the Carry Flag, but that is of no consequence here).

N.B. It's easy to get mixed up between "RR C" and "RRC" - perhaps I should have swapped the roles of the B and C registers to reduce the prospect for confusion!?




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users