Jump to content


Photo

Setting a rope's horizontal position by pixel


  • Please log in to reply
9 replies to this topic

#1 IRF

IRF

    Advanced Member

  • Contributor
  • 4,307 posts

Posted 07 September 2017 - 11:41 PM

Please see the attached test file.

 

PREAMBLE: In 'Jet Set Mini', I managed to implement perfectly laterally-inverted ropes, partially by changing the position of the top segment of each rope within its host cell.  (i.e. In original JSW, the top rope segment occupies the leftmost pixel in the defined start-column; whereas in 'Jet Set Mini' the top rope segment occupies the rightmost pixel.)

 

This test file extends that concept further.  I have slightly rewritten the 'Draw the Ropes' routine, so that the precise horizontal pixel-position of the top of each rope in the game may be specified separately. i.e. on a 'rope instance' basis.  The pixel position of the top segment is stored in the highest three bits* of Byte 2 of the Rope Definition (which is copied over, from the second byte of each rope's specification in the room's guardian list, when the 'Room Setup' routine is executed).

 

The value of that three-bit number is then translated into the correct pixel to infill for the top segment, using a similar principle to that which is used in Manic Miner to draw the remaining pixels of air supply at the right-hand end of the air bar (except that I've used the RLC E command here, instead of RRC E, and there is no setting of additional bits during each pass through the DJNZ loop).

 

 

Within the the start-up room (Swimming Pool) in the attached file, there are eight** ropes which are very closely spaced horizontally (only three pixels apart).  I have called this effect a 'Swinging Curtain', as that's what I think it looks like!

 

Note that the game is slowed down somewhat in the room in question, because of the need to perform eight complex rope-drawing operations during each time-frame.

 

 

******

 

* One consequence of this change is that you lose the ability to create an 'Invalid Rope' like the one in the 'Overgrown MegaTree' in 'Jet Set Mini' (the top segment of which is drawn further down the screen than is usually the case, because I assigned an 'invalid' value [greater than #1F] for the x-coordinate of the top segment of rope, in the room's guardian table).  However, that's probably not a great loss - Invalid Ropes can be very 'quirky', especially if they extend down beyond the boundary between the top and bottom half of the playing area, which causes segments to appear in strange places (the one in 'Jet Set Mini' is sufficiently short to prevent this from happening).

 

 

** Note that because there are eight ropes present in the room, it can be quite difficult to dismount the ropes/curtain!  The 'Draw the Ropes' routine usually allows Willy 16 time-frames to elapse, after jumping or falling off a rope, before he can be caught by a rope again.  However, with eight ropes being drawn consecutively in each time-frame, that reduces to two time-frames!  (Although that is not a result of the changes that I made in the attached; it is a curious feature of the JSW game engine, and would be the case in any JSW room with eight ropes.)

Attached Files


Edited by IRF, 18 September 2017 - 04:23 PM.


#2 IRF

IRF

    Advanced Member

  • Contributor
  • 4,307 posts

Posted 08 September 2017 - 08:38 AM

I've made a minor variation to the previous file - see the attached.  The patch* has been re-written slightly more efficiently, saving three bytes.  And in the test room I've put all eight ropes into adjacent pixels (the top segments are all located within the same cell-column, although they could just as easily have straddled two columns), so the composite whole now resembles a swinging rope ladder.

 

That can be scaled back to achieve a 'fat rope' by having, say, just two ropes sitting adjacent to each other, one pixel apart - which would have the benefit that it doesn't slow the game down to the same extent (as well as only requiring two guardian instances, of course).

 

 

EDIT: *I forgot to say last night: the patch for this and last night's test file is contained in a subroutine at #9718 (which is CALLed from #92AC, near the start of the 'Draw the Ropes' code).

Attached Files


Edited by IRF, 08 September 2017 - 06:36 PM.


#3 Spider

Spider

    DEC (HL)

  • Administrator
  • 3,994 posts

Posted 08 September 2017 - 01:15 PM

That's very unusual but I do quite like it. :D


  • IRF likes this
Changing order to chaos since 1984

#4 IRF

IRF

    Advanced Member

  • Contributor
  • 4,307 posts

Posted 08 September 2017 - 04:49 PM

Incidentally, aside from the perhaps frivolous 'composite ropes', as seen in the test files above, the ability to set a rope's horizontal position at the individual pixel level could be useful for fine tuning a difficult game, where you want to ensure that a tricky jump onto or off of a rope is just about possible (if the player gets the timing exactly right), without actually becoming impossible!


Edited by IRF, 08 September 2017 - 08:36 PM.


#5 IRF

IRF

    Advanced Member

  • Contributor
  • 4,307 posts

Posted 08 September 2017 - 06:36 PM

Here is the 'Fat Rope' test file - this is comprised of just two ropes, so it runs faster.  The Fat Rope is exactly centred horizontally in the room.

Attached Files



#6 Spider

Spider

    DEC (HL)

  • Administrator
  • 3,994 posts

Posted 08 September 2017 - 07:32 PM

That looks quite good like that I think. :) A certain "chunkyness" to it without it being excessive.

 

The ropes in the C64 version are slightly chunky as standard (lets not talk about the square stairs that are difficult to jump through though!) , similar for the C+4 / C16 versions actually...

 

swimming_pool_c64.png

 

 


Changing order to chaos since 1984

#7 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 2,164 posts

Posted 17 September 2017 - 04:39 PM

Ian, these new inventions are fantastic! I really like them  :)



#8 IRF

IRF

    Advanced Member

  • Contributor
  • 4,307 posts

Posted 17 September 2017 - 04:43 PM

Thanks Danny!

#9 IRF

IRF

    Advanced Member

  • Contributor
  • 4,307 posts

Posted 18 September 2017 - 05:03 PM

I've re-named this thread to reflect the substantive subject matter. ('Swinging Curtain' was just one example of what can be achieved with this approach.)

Here is a short disassembly of the changes made to the original code to implement ropes where the horizontal position is set at the pixel level:

Original code (from Skoolkid's disassembly):

92A4 LD IY,$8200 Point IY at the first byte of the screen buffer address lookup table at 8200
92A8 LD (IX+$06),$00 Initialise the seventh byte of the rope's buffer to zero; this will count the segments of rope to draw [Note that the Adjacent Ropes patch is in place to prevent overspill of the rope's definition!]
92AC LD A,(IX+$02) Initialise the fourth byte of the rope's buffer; this holds the x-coordinate of the cell in which the segment of rope under consideration will be drawn
92AF LD (IX+$03),A
92B2 LD (IX+$05),$80 Initialise the sixth byte of the rope's buffer to 0x80 (Bit 7 set); the value held here is used to draw the segment of rope under consideration
(N.B. In 'Jet Set Mini', this was changed to LD (IX+$05),$01 which sets Bit 0 instead.)

New code:

92A4 LD IY, $8200 Point IY at the first byte of the screen buffer address lookup table at 8200
92A8 LD (IX+$06), $00 Initialise the seventh byte of the rope definition in the entity buffer to zero; this will count the segments of rope to draw
92AC CALL $9718 Call a subroutine to initialise the horizontal position of the top segment of rope (by cell-column and by pixel)
92AF NOP x 7 [I could have used some of these NOPs for part of the subroutine, but I decided to keep it all in the same place in the test files, for ease of understanding]
-92B5

9718 LD A, (IX+$02) Load up the third byte (Byte 2) of the rope definition to the A register
971B AND $1F Keep only Bits 0-4 (representing the cell-column of the top segment)
971D LD (IX+$03), A Initialise the fourth byte of the rope definition; this holds the x-coordinate of the cell in which the segment of rope under consideration will be drawn
9720 XOR (IX+$02) This bitwise XOR operation leaves the A register holding the pixel-position of the top segment of the rope in Bits 5-7, whilst clearing Bits 0-4 of A
9723 RLCA
9724 RLCA
9725 RLCA The pixel-position of the top segment of rope has been rotated round to occupy Bits 0-2 of the A register; thus A holds a value between 0 and 7
9726 INC A A now holds a value between 1 and 8
9727 LD B, A Copy the value of A into the B register, in preparation for a DJNZ loop later
9728 XOR A The A register is cleared (A=0) and the Carry Flag is reset by this operation
9729 SCF Set the Carry Flag (in light of the previous operation, a CCF operation - complement the Carry Flag - would also work here)
972A RRA Rotate A rightwards - in the first instance, the value of the Carry Flag is rotated in to Bit 7
972B DJNZ $972A The preceding RRA command is performed B number of times, which leaves the A register with one (and only one) set bit
972D LD (IX+$05), A Initialise the sixth byte of the rope definition; the single set bit is used to draw the segment of rope under consideration
9730 RET Return to the rope-drawing routine, to commence the loop (starting at 92B6) which draws each segment in turn

With the above in place, if the highest three bits of Byte 2 of a rope's definition hold the value 000, then the top segment of the rope will occupy Bit 7 (the leftmost bit) of the appropriate cell-column (as specified by Bits 0-4 of Byte 2).
If Bits 5-7 of Byte 2 hold the value 111, then the top segment of the rope will be drawn in Bit 0 of its cell-column.
All intermediate values behave as you would expect.

And of course, Byte 2 for any guardian is specified on a guardian-instance basis, so only one guardian-class is required to populate a room with ropes that have different pixel-positions.

Edited by IRF, 14 January 2018 - 12:28 AM.


#10 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 2,164 posts

Posted 18 September 2017 - 06:17 PM

Thanks for the disassembly, Ian, it's much appreciated!  :)






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users