Jump to content
IGNORED

HEEELP! Ladder bug in scrolling platformer


Recommended Posts

I have this bug in my game that I can't figure out, when you stand to the right of a ladder (not overlapping) and press down and right at the same time, you end up in some weird loop, as if you were overlapping, constantly snapping you back to the ladder, but since there is no ladder I guess you get ejected from the ground instead.

 

 

(if you're at the bottom of the ladder press up and right instead)

Great, just found another bug while recording the first one, but obviously the same issue.

 

 

I don't see anything wrong with my playerX to backtab column conversion:

CONST TILE_WIDTH = 8

CONST PF_DIFF = 8

DEF FN left   = (((#playerX / 256) - fineScrollX) - PF_DIFF) / TILE_WIDTH

 

I have extracted the least amount of code necessary to trigger the bug, to a separate file, and commented the relevant code. Hopefully someone can find it, because I really can't. Has anyone here made a scrolling game with working ladders or any other kind of working player pixel to backtab row/column conversion?

 

Feel free to replace the code with something that works

climb2.bas

 

 

Edited by Lillapojkenpåön
  • Like 1
Link to comment
Share on other sites

Hi, @Lillapojkenpåön,  (thank God for auto-complete! 😄)

 

I just took a cursory look at your code and I see that when you are at the base of the first ladder (which is blocked by a wall on the right side), pressing RIGHT will cause procedure handleRight() to update the #playerX position fractionally, even though I am blocked and unable to move.  Later, when I climb up and down the ladder, this fractional position remains, even though the camera is centered on the screen, and the player object has been "snapped" to an 8x8 background tile.

 

Eventually, if I touch the ground again, the player position is "corrected" (presumably due to the remaining fractional portion), which places the object within the wall (this is the second bug you mentioned).

 

I believe these two bugs -- the original one you were asking about, and the new one you discovered while testing, and described above -- are related.

 

On the surface (and without thinking too hard about it and, therefore, not fully understanding how your code works), it seems that the adjustment to the player position when "snapping" to a ladder in the context of scrolling (i.e., when centering the camera), is not handled correctly.

 

Indeed, when I get close to the ladder and press up or down, the object is "snapped" to the ladder, and its position adjusted correctly:  with no fraction.  However, pressing to the right again (or just moving continuously to the right until blocked by a wall), will result in an incorrect fractional position even though the object is still "snapped" to the ladder.

 

I've prepared a quick-and-dirty video illustrating this phenomenon.

 

 

 

     -dZ.

 

 

  • Like 1
Link to comment
Share on other sites

Hmm, well if you think about how the gravity works, you are constantly adding gravity to velocityY, and adding velocityY to playerY, but as soon as playerY integer increases and you overlap with the ground, you move playerY out of the ground and reset velocityY to zero (otherwise the integer will eventually become bigger than tile height and you fall thru the ground.. But it is constantly increasing and resetting like that, otherwise you wouldn't fall down when walking off a platform

 

you can do it in different ways, but this is pretty standard.

 

That's exactly what happens when you press right against a wall, otherwise you wouldn't move right if jumping up and holding right to jump up on a platform, same thing.

I don't think that's the problem.

 

I think I'm using fineScrollX (the 0-7 fine scroll variable) wrong in my conversions, probably just got lucky that I typed in something that kinda worked first try

 

I went with -fineScrollX because it looked smooth when drawing the sprite

 

    SPRITE 0, (#playerX / 256) - fineScrollX,..

 

but maybe I'm suppose to use

(8-fineScrollX)

or

(7-fineScrollX)

or a + where I have a - or vice versa, I'm pretty sure that's the problem

 

Here's the problematic code and how it works

 

the sides of the sprite

    DEF FN top    = ((#playerY AND 255) - pfDiff) / tileHeight
    DEF FN bottom = (((#playerY AND 255) - pfDiff) + spriteHeightMinusOne) / tileHeight
    DEF FN left   = (((#playerX / 256) - fineScrollX) - pfDiff) / tileWidth
    DEF FN right  = ((((#playerX / 256) - fineScrollX) - pfDiff) + spriteWidthMinusOne) / tileWidth

 

when moving right you check top/right and bottom/right pixels for overlap

    #backtab(right + top * 20)
    #backtab(right + bottom * 20)

 

If there's overlap with a solid tile, there's a very simple solution to knowing how many pixels to move back, the first three bits of playerX will be the amount of pixels to move back,

no looping or adjusting hitboxes or anything complex needed.

    #playerX = alignLeft * 256

    DEF FN alignLeft  = #playerX - (((#playerX / 256) - fineScrollX) AND tileWidthMask)

 

when moving left and checking top/left and bottom/left, if you overlap 1px, the first three bits of playerX will be 7 instead of 1, so you have to do

TILE_WIDTH - (playerX AND 7) instead to get the amount of pixels to move back

    DEF FN alignRight = #playerX + (((tileWidth - (#playerX / 256)) + fineScrollX) AND tileWidthMask)

 

 

when overlapping with the ladder I just use those in the reversed way, to move you into the tile.

 

But I'm pretty sure I'm using fineScrollX wrong in all those calculations, and my attention span is too short to figure out how to use it correctly

Calculate Zach Galifianakis GIF

 

 

 

 

Edited by Lillapojkenpåön
Link to comment
Share on other sites

1 hour ago, Lillapojkenpåön said:

Hmm, well if you think about how the gravity works, you are constantly adding gravity to velocityY, and adding velocityY to playerY, but as soon as playerY integer increases and you overlap with the ground, you move playerY out of the ground and reset velocityY to zero (otherwise the integer will eventually become bigger than tile height and you fall thru the ground.. But it is constantly increasing and resetting like that, otherwise you wouldn't fall down when walking off a platform

 

you can do it in different ways, but this is pretty standard.

 

Except that is not working correctly.  So, perhaps not a problem with the methodology, but the implementation. ;)

 

I made a quick modification to truncate the #playerX variable when updating it in handleRight() and handleLeft(), and it fixed the second problem you reported (the one in the video), so obviously updating the variable after snapping it to the ladder and adding a fraction to it without actually moving it, is not correct.

 

1 hour ago, Lillapojkenpåön said:

That's exactly what happens when you press right against a wall, otherwise you wouldn't move right if jumping up and holding right to jump up on a platform, same thing.

I don't think that's the problem.


It is not the same problem as what you were asking about (the shaking back-and-forth at the top when pressing down+right), you are right; but it is a problem nonetheless, as mine and your own video suggest (the sprite goes off the ladder when moving right past the ladder and then climbing up or down and reaching the extreme).

 

1 hour ago, Lillapojkenpåön said:

I think I'm using fineScrollX (the 0-7 fine scroll variable) wrong in my conversions, probably just got lucky that I typed in something that kinda worked first try

 

That was my point in my earlier post: that adjusting the position when scrolling (i.e., when fineScrolling changes) is not working correctly.

 

Unfortunately, I haven't studied your code too closely to understand what is actually wrong.

 

1 hour ago, Lillapojkenpåön said:

I went with -fineScrollX because it looked smooth when drawing the sprite

 

    SPRITE 0, (#playerX / 256) - fineScrollX,..

 

but maybe I'm suppose to use

(8-fineScrollX)

or

(7-fineScrollX)

or a + where I have a - or vice versa, I'm pretty sure that's the problem

 

I'll take a look at that.

 

1 hour ago, Lillapojkenpåön said:

Here's the problematic code and how it works

 

the sides of the sprite

    DEF FN top    = ((#playerY AND 255) - pfDiff) / tileHeight
    DEF FN bottom = (((#playerY AND 255) - pfDiff) + spriteHeightMinusOne) / tileHeight
    DEF FN left   = (((#playerX / 256) - fineScrollX) - pfDiff) / tileWidth
    DEF FN right  = ((((#playerX / 256) - fineScrollX) - pfDiff) + spriteWidthMinusOne) / tileWidth

 

 

I think here is an "off-by-one" error somewhere.  Pressing down+right at the top of the ladder snaps you back to the ladder on every single position to the right of the ladder, except when you are exactly 8 pixels away -- that is, fully on the next card.

 

That's when it tries to snap you back, but fails and just shakes back and forth.

 

So it seems rather likely that the computation of the current position has a discrepancy between the checking for a ladder (there is a ladder, we should snap to it) and actually snapping to it (there is actually a block there, so move back).

 

Then again, I wouldn't expect it to snap me to back to the ladder so for off its range; even 7 pixels to the right of a ladder seems much too far to force the sprite back to the ladder, in my opinion.

 

1 hour ago, Lillapojkenpåön said:

when moving right you check top/right and bottom/right pixels for overlap

    #backtab(right + top * 20)
    #backtab(right + bottom * 20)

 

If there's overlap with a solid tile, there's a very simple solution to knowing how many pixels to move back, the first three bits of playerX will be the amount of pixels to move back,

no looping or adjusting hitboxes or anything complex needed.

 

I think the problem is in the "right" and "bottom" macros. Why "spriteHeightMinusOne" and "spriteWidthMinusOne" and not the full height or length?  I may be missing something, but if you are checking the next card, you would add the full length of a sprite's side.  What I typically do is adjust the position to the center of the sprite (i.e., +4 from origin), and add 8 (or the dimensions of the bounding box).  This projects the sprite a full card to one side and check the card directly under, rather than at the edge of it.

 

(Could that be the "off-by-one" culprit?)

 

1 hour ago, Lillapojkenpåön said:
    #playerX = alignLeft * 256

    DEF FN alignLeft  = #playerX - (((#playerX / 256) - fineScrollX) AND tileWidthMask)

 

when moving left and checking top/left and bottom/left, if you overlap 1px, the first three bits of playerX will be 7 instead of 1, so you have to do

TILE_WIDTH - (playerX AND 7) instead to get the amount of pixels to move back

    DEF FN alignRight = #playerX + (((tileWidth - (#playerX / 256)) + fineScrollX) AND tileWidthMask)

 

 

Except that if you are off by one, you may get zero when it should be 7 and the adjustment is not done, or vice versa.

 

1 hour ago, Lillapojkenpåön said:

when overlapping with the ladder I just use those in the reversed way, to move you into the tile.

 

But I'm pretty sure I'm using fineScrollX wrong in all those calculations, and my attention span is too short to figure out how to use it correctly


No worries.  I also have a hard time figuring out how other people's code works (well, even my own code, sometimes), so it may take me a while to figure out what could be wrong.

 

    dZ.

Link to comment
Share on other sites

1 hour ago, DZ-Jay said:

 

I think the problem is in the "right" and "bottom" macros. Why "spriteHeightMinusOne" and "spriteWidthMinusOne" and not the full height or length?  I may be missing something, but if you are checking the next card, you would add the full length of a sprite's side.  What I typically do is adjust the position to the center of the sprite (i.e., +4 from origin), and add 8 (or the dimensions of the bounding box).  This projects the sprite a full card to one side and check the card directly under, rather than at the edge of it.

 

(Could that be the "off-by-one" culprit?)

 

Nope that's not it, I know the intybasic standard way is to check the card that's coming up, and not do the move if it's a wall or something, but I do the move and check if the pixels overlap and then add or subtract the overlap in the opposite direction, and the last pixel is 7 pixels from the first, not 8.

I use 8 for the "bellow" macro, to check one pixel bellow the player for ground when climbing down

 

But remember how I used to do coarse scroll when finescroll was 0 or 7, now I do it when less than 0, and bigger than 7, doesn't that create a fine scroll range of 9 between the coarse scrolls, I remember that I was confused how it even worked, that also sounds like a "off-by-one" culprit, arrrrgh, so many culprits!

Edited by Lillapojkenpåön
Link to comment
Share on other sites

2 hours ago, DZ-Jay said:

 

Except that is not working correctly.  So, perhaps not a problem with the methodology, but the implementation. ;)

 

I made a quick modification to truncate the #playerX variable when updating it in handleRight() and handleLeft(), and it fixed the second problem you reported (the one in the video), so obviously updating the variable after snapping it to the ladder and adding a fraction to it without actually moving it, is not correct.

 

 

Why would it matter if the playerX fraction remains while climbing??? And why would it affect the position of the player which is in the upper integer byte??? It's just used to control the speed in an easy 8.8 way???

 

Going Crazy Will Ferrell GIF

Link to comment
Share on other sites

2 hours ago, Lillapojkenpåön said:

Nope that's not it, I know the intybasic standard way is to check the card that's coming up, and not do the move if it's a wall or something, but I do the move and check if the pixels overlap and then add or subtract the overlap in the opposite direction, and the last pixel is 7 pixels from the first, not 8.

 

That's not what I meant.  I have no idea what is the "IntyBASIC standard way," for I do not program in IntyBASIC.  (Is there a "standard" way of doing anything in IntyBASIC?)

 

The last pixel of one card is 7 pixels from the first, that is true; but if you start at the origin of one card and end up overlapping the next, that card is 8 pixels away from the first.

 

As I see it, the problem is that the sprite is being treated as if it where 7 pixels away from origin of the ladder (overlapping the next card), when it is actually 8 pixels away (aligned with the origin of the next card).  This is why the snapping fails, because there is no ladder there.


Anyway, that particular function may not be the culprit, but there is definitely a problem that results in a single pixel discrepancy:  when I am 7 pixels away from the ladder and I press down+right, it snaps me back to the ladder; but if I move to the 8th pixel (the next card), it shakes back and forth because it tries to snap me to the ladder, but there is no ladder there.  On the next pixel (9th) it works normally.

 

 

2 hours ago, Lillapojkenpåön said:

But remember how I used to do coarse scroll when finescroll was 0 or 7, now I do it when less than 0, and bigger than 7, doesn't that create a fine scroll range of 9 between the coarse scrolls,

 

0 to 7 is the length of a single card: 8 pixels.  So you must do a coarse scroll on the boundary from 7 to 0, or 0 to 7, depending on the direction.

 

2 hours ago, Lillapojkenpåön said:

I remember that I was confused how it even worked, that also sounds like a "off-by-one" culprit, arrrrgh, so many culprits!


LOL!

 

By the way, my last two posts are based on my impressions of how the game behaves -- I haven't looked at the code, other than my initial overview early his morning, when I posted my first comment.

 

I think I'll wait until I analyze the code some more before commenting again. :)

 

   dZ.

Link to comment
Share on other sites

24 minutes ago, DZ-Jay said:


LOL!

 

By the way, my last two posts are based on my impressions of how the game behaves -- I haven't looked at the code, other than my initial overview early his morning, when I posted my first comment.

 

I think I'll wait until I analyze the code some more before commenting again. :)

 

   dZ.

Lol, hurry up before I do something stupid.. 🤣 My epic submission to this ludum dare jam will be "not solving a bug"

I'll paypal you twenty bucks if you figure it out 😅 keep in mind how the ladder tile looks, that you are overlapping it from the left when you are over the brown, and from the right when you are over the black outline.

I'll stay up all night and continue to lose my mind.

 

 

Link to comment
Share on other sites

45 minutes ago, Lillapojkenpåön said:

Lol, hurry up before I do something stupid.. 🤣 My epic submission to this ludum dare jam will be "not solving a bug"

I'll paypal you twenty bucks if you figure it out 😅

 

keep in mind how the ladder tile looks, that you are overlapping it from the left when you are over the brown, and from the right when you are over the black outline.

I'll stay up all night and continue to lose my mind.

 

I'll take a look on Monday.

 

   -dZ.

  • Thanks 1
Link to comment
Share on other sites

I looked at the value for "left" by following your video

temp3 = left, and then I looked at temp3 in the debugger

 

it was off by one as suspected, meaning when you are scrolling and stay centered on the screen this should return the same column, it didn't..

this does, it's one pixel wrong when you reach the end of the level but only because I scroll the level one pixel too far

 

DEF FN left   = (((#playerX / 256) - (8-fineScrollX))  - PF_DIFF) / TILE_WIDTH

 

we just need to look at right, alignLeft and alignRight too

Tired Tom And Jerry GIF

  • Like 1
Link to comment
Share on other sites

11 hours ago, Lillapojkenpåön said:

 

Why would it matter if the playerX fraction remains while climbing??? And why would it affect the position of the player which is in the upper integer byte??? It's just used to control the speed in an easy 8.8 way???

 

Going Crazy Will Ferrell GIF

 

I missed this comment last night, when I was reading it on my phone.

 

The fraction does not affect the climbing -- it works correctly, as the video shows: you remain snapped to the column going up and down.  However, when you reach either the top or the bottom, the fraction causes the sprite to be pushed to the next column, which is why you see the sprite going up and down on the column to the right of the ladder.

 

The problem is then that when the sprite is snapped to the ladder at the top or bottom rows, it does not move at all -- that is, its position does not change.  Yet, continuing to press against the wall will cause #playerX to increase fractionally.  This is obviously wrong since -- as mentioned -- the position has not changed.  In other words, accepting the input while snapped to the ladder and altering the #playerX variable incrementally, results in corrupting the logical position of the sprite.

 

When the sprite finally makes it out of the ladder, the program thinks it's somewhere else and -- boom! -- snaps it to the wrong column.

 

I hope that makes sense.  (I also hope that is right -- again, it is based purely on observation, deduction, and some educated guesses.)

 

     -dZ.

Link to comment
Share on other sites

It looks like that, but no that doesn't make much sense, I don't increment playerX fractionally while snapped to the ladder, only while blocked by a wall, which I could do all day long. And the sprite gets drawn in the climb loop too, so I don't see how the program could think it's somewhere else all of a sudden when nothing has changed.

You probably just pressed down/right/up while climbing down and the broken conversions made you snap to a non-existing ladder. The broken conversions are the source of all evil.

Edited by Lillapojkenpåön
Link to comment
Share on other sites

1 hour ago, Lillapojkenpåön said:

It looks like that, but no that doesn't make much sense, I don't increment playerX fractionally while snapped to the ladder, only while blocked by a wall, which I could do all day long.
 

 

Sorry, that's what I meant, blocked by a wall.  It is just that this wall blocks the base of a ladder, so when you try to climb, the fraction is not clear, leading to the broken behaviour.

 

I did a test:  in handleRight() and handleLeft(), I truncated the value assigned to #playerX by ANDing it with $FF00.

 

Go ahead and try it -- you will see that the "falling off the ladder" or "climbing on the wrong column" shown in the video, goes away.

 

That shows that the fraction causes a problem when you snap to a ladder without clearing it -- even if it wasn't the snapping that produced the fraction.  Although the precise mechanism is not clear to me (without analyzing the code), in the abstract it seems obvious:  the fraction causes some computation somewhere to interpret the current position as somewhere else.

 

1 hour ago, Lillapojkenpåön said:

And the sprite gets drawn in the climb loop too, so I don't see how the program could think it's somewhere else all of a sudden when nothing has changed.

 

See above.

 

1 hour ago, Lillapojkenpåön said:

You probably just pressed down/right/up while climbing down and the broken conversions made you snap to a non-existing ladder. The broken conversions are the source of all evil.

 

See above.


In the end, there are two separate bugs:  the off-by-one error that causes the back-and-forth shaking when you press down+right exactly 8 pixels away from the top of the ladder (your original problem); and the fractional position error that causes the sprite to climb in the wrong column.

 

I know how to fix the second one, as mentioned above, by truncating the position when snapping to the ladder.  (Although that itself is cheesy hack; there may be more elegant ways to solve it.)

 

I thought you found the off-by-one error that caused the first one, or are you still troubleshooting it?

 

   dZ.

Link to comment
Share on other sites

4 hours ago, DZ-Jay said:

 

Sorry, that's what I meant, blocked by a wall.  It is just that this wall blocks the base of a ladder, so when you try to climb, the fraction is not clear, leading to the broken behaviour.

 

I did a test:  in handleRight() and handleLeft(), I truncated the value assigned to #playerX by ANDing it with $FF00.

 

Go ahead and try it -- you will see that the "falling off the ladder" or "climbing on the wrong column" shown in the video, goes away.

 

That shows that the fraction causes a problem when you snap to a ladder without clearing it -- even if it wasn't the snapping that produced the fraction.  Although the precise mechanism is not clear to me (without analyzing the code), in the abstract it seems obvious:  the fraction causes some computation somewhere to interpret the current position as somewhere else.

Maybe, if the *256 is somehow done to the variable instead of to registers, we'll see if it remains after the conversion is solved.

 

4 hours ago, DZ-Jay said:

I thought you found the off-by-one error that caused the first one, or are you still troubleshooting it?

I thought so, but I don't think that was it.

However, moving handleLeftRight() from before to after the up/down check, made the stuck in a jittery loop bug dissapear,

and if I reduce the max speed to 3 I can't break it, it's faster than my game needs but it doesn't feel good because if something wasn't wrong it should be able to handle 7-8 I think.

 

 

 

climb3.bas

 

Edited by Lillapojkenpåön
Link to comment
Share on other sites

Ok, so this is the only thing that's wrong..

 

    DEF FN left    =  (((((#playerX AND $FF00) - $0800) - (fineScrollX *256))                / TILE_WIDTH) / 256)

    DEF FN right  = ((((((#playerX AND $FF00) - $0800) - (fineScrollX *256)) + $0700) / TILE_WIDTH) / 256)

 

It returns the correct columns aslong as fineScrollX is 0, but as soon as you scroll it's wrong, and it was only a coincidence that it would still catch the overlap sometimes.

 

The red box shows the column the white sprites rightmost pixel overlaps (the value from the right function above).

The green box is the column you would be moved to if the tile in the red box was a solid stone tile.

 

 

 

 

The red box hides behind the white player box as soon as you start scrolling.

 

Considering the green box (alignLeft()) works no matter what, it should be possible to figure out what needs to change, just not for me... ☹️

 

 

climb4.bas

Link to comment
Share on other sites

So, wait, let me understand something:  you found where the problem is ... but not what is the problem?  I'll try to help then.

 

And just so that I follow completely:  the red box is right() and left(), and the green box is alignLeft() and alignRight()?

 

       -dZ.

  • Thanks 1
Link to comment
Share on other sites

8 minutes ago, DZ-Jay said:

So, wait, let me understand something:  you found where the problem is ... but not what is the problem?  I'll try to help then.

 

And just so that I follow completely:  the red box is right() and left(), and the green box is alignLeft() and alignRight()?

 

       -dZ.

Exactamento, right() and alignLeft(),

left() and alignRight() are commented out if you want to check them instead


 

    #temp16 = alignLeft
    '#temp16 = alignRight

    temp4 = right * 8 + PF_DIFF
    'temp4 = left * 8 + PF_DIFF

Had to convert the last one back from column to pixels to display it as a sprite

Link to comment
Share on other sites

7 hours ago, Lillapojkenpåön said:

Exactamento, right() and alignLeft(),

left() and alignRight() are commented out if you want to check them instead


 

    #temp16 = alignLeft
    '#temp16 = alignRight

    temp4 = right * 8 + PF_DIFF
    'temp4 = left * 8 + PF_DIFF

Had to convert the last one back from column to pixels to display it as a sprite


OK, I'll check it out.

 

    dZ.

Link to comment
Share on other sites

  • 2 weeks later...

Hi @Lillapojkenpåön I revised your code and it is working fine.

 

However, the thing that is bothering you is logical.

 

My first test was to make sure your right macro was calculated correctly. To do this, I marked each floor tile as red as the square walks, using this code (just before SPRITE 2):

 

temp4 = right
#backtab(220 + temp4) = BG00 + FG_BLACK  + BG_RED 'stones

 

With this code I was sure your right macro is correct. You can see how each stone gets red in turn in the correct place.

 

The second test took me a little longer because a logical fallacy. The important things is: the background is affected by hardware scrolling counters, but MOB's aren't affected by hardware scrolling counters.

 

So this means that any position used for sprites is the real position in screen as if scrolling isn't happening, and that's why we need to adjust sprites with the scrolling offsets. However, if you are going to use a sprite to pinpoint a card on the screen, you need to use the real coordinate.

 

The correct code to make your red sprite to pinpoint correctly the card is this:

 

    temp4 = right * 8 + PF_DIFF
    'temp4 = left * 8 + PF_DIFF
    SPRITE 2,   temp4 + HIT + VISIBLE,    (#playerY AND 255) + ZOOMY2,    SPR16 + SPR_RED

 

Notice the removal of the fine adjustment.

 

So the code was always right. It was only the display code that wasn't right, but you weren't aware of the coordinate differences between the card background world and the sprite world.

 

Probably I'm not using the standard STIC language for describing these, but I'm sure @DZ-Jay can correct any of my non-sense :dunce:

 

 

 

  • Like 1
Link to comment
Share on other sites

6 hours ago, nanochess said:

Hi @Lillapojkenpåön I revised your code and it is working fine.

 

However, the thing that is bothering you is logical.

 

My first test was to make sure your right macro was calculated correctly. To do this, I marked each floor tile as red as the square walks, using this code (just before SPRITE 2):

 

temp4 = right
#backtab(220 + temp4) = BG00 + FG_BLACK  + BG_RED 'stones

 

With this code I was sure your right macro is correct. You can see how each stone gets red in turn in the correct place.

 

The second test took me a little longer because a logical fallacy. The important things is: the background is affected by hardware scrolling counters, but MOB's aren't affected by hardware scrolling counters.

 

So this means that any position used for sprites is the real position in screen as if scrolling isn't happening, and that's why we need to adjust sprites with the scrolling offsets. However, if you are going to use a sprite to pinpoint a card on the screen, you need to use the real coordinate.

 

The correct code to make your red sprite to pinpoint correctly the card is this:

 

    temp4 = right * 8 + PF_DIFF
    'temp4 = left * 8 + PF_DIFF
    SPRITE 2,   temp4 + HIT + VISIBLE,    (#playerY AND 255) + ZOOMY2,    SPR16 + SPR_RED

 

Notice the removal of the fine adjustment.

 

So the code was always right. It was only the display code that wasn't right, but you weren't aware of the coordinate differences between the card background world and the sprite world.


Thank you for that great analysis.  I haven't had a chance to look at the code (work is brutal!!!), so I'm glad someone with your experience had a chance to help @Lillapojkenpåön.  It all makes sense.

 

So, to recap, the only problem was when copying the position to the SPRITE command for display; the rest of the functions and variables were correct.  Right?

 

(That is apart from the problem of not truncating the fraction when the sprite is "snapped" to the ladder column.)

 

6 hours ago, nanochess said:

Probably I'm not using the standard STIC language for describing these, but I'm sure @DZ-Jay can correct any of my non-sense :dunce:

 


Nonsense? LOL! Said the guy who actually made IntyBASIC on his own!!! My little brain is not capable of something like that.  :dunce:

 

By the way, I don't know if there is a proper "STIC language" for this.  I think in his documentation Joe Z. calls it "MOB space" or "MOB plane" vs. "Display space" of "Screen space."  But I think the way you described it was fine.  :)

 

    dZ.

  • Thanks 1
Link to comment
Share on other sites

1 minute ago, DZ-Jay said:

 

So, to recap, the only problem was when copying the position to the SPRITE command for display; the rest of the functions and variables were correct.  Right?

 

(That is apart from the problem of not truncating the fraction when the sprite is "snapped" to the ladder column.)

 

Apparently yes. The mystery was why the red block wasn't shown the way it was supposed to.

 

Link to comment
Share on other sites

3 hours ago, nanochess said:

Apparently yes. The mystery was why the red block wasn't shown the way it was supposed to.

 

 

Ah, yes, in that example.  I'm going to guess that the code in the example was the same used in the game at the top post, which caused the bug illustrated in the first video.

 

    -dZ.

Link to comment
Share on other sites

On 5/12/2023 at 5:29 PM, nanochess said:

Hi @Lillapojkenpåön I revised your code and it is working fine.

 

However, the thing that is bothering you is logical.

 

My first test was to make sure your right macro was calculated correctly. To do this, I marked each floor tile as red as the square walks, using this code (just before SPRITE 2):

 

temp4 = right
#backtab(220 + temp4) = BG00 + FG_BLACK  + BG_RED 'stones

 

With this code I was sure your right macro is correct. You can see how each stone gets red in turn in the correct place.

 

The second test took me a little longer because a logical fallacy. The important things is: the background is affected by hardware scrolling counters, but MOB's aren't affected by hardware scrolling counters.

 

So this means that any position used for sprites is the real position in screen as if scrolling isn't happening, and that's why we need to adjust sprites with the scrolling offsets. However, if you are going to use a sprite to pinpoint a card on the screen, you need to use the real coordinate.

 

The correct code to make your red sprite to pinpoint correctly the card is this:

 

    temp4 = right * 8 + PF_DIFF
    'temp4 = left * 8 + PF_DIFF
    SPRITE 2,   temp4 + HIT + VISIBLE,    (#playerY AND 255) + ZOOMY2,    SPR16 + SPR_RED

 

Notice the removal of the fine adjustment.

 

So the code was always right. It was only the display code that wasn't right, but you weren't aware of the coordinate differences between the card background world and the sprite world.

 

Probably I'm not using the standard STIC language for describing these, but I'm sure @DZ-Jay can correct any of my non-sense :dunce:

 

 

 

Thanks for the help! I get it now that you spelled it out for me, I think I also just realised why it can only handle speeds bellow 4 instead of upto 7

 

it's because the scrolling and backtab doesn't get updated until the next frame, so there's a one frame delay with the background collission detection, you're allway comparing against the previous frame, not the one that's about to be drawn

 

so if speed is 4, and you are 4 pixels into a solid tile, collision detection checks backtab (that is not updated yet) and you are still next to the tile and good to go,

and the next frame you move another 4 pixels, it detects a collision, but now you have moved 8 pixels so the first three bits of playerX has rolled over so you align to the solid tile column, atleast that sounds like a reasonable explanation.

So I need to check collisions before moving/scrolling, not after.

Edited by Lillapojkenpåön
  • Like 1
Link to comment
Share on other sites

1 hour ago, Lillapojkenpåön said:

Thanks for the help! I get it now that you spelled it out for me, I think I also just realised why it can only handle speeds bellow 4 instead of upto 7

 

it's because the scrolling and backtab doesn't get updated until the next frame, so there's a one frame delay with the background collission detection, you're allway comparing against the previous frame, not the one that's about to be drawn

 

so if speed is 4, and you are 4 pixels into a solid tile, collision detection checks backtab (that is not updated yet) and you are still next to the tile and good to go,

and the next frame you move another 4 pixels, it detects a collision, but now you have moved 8 pixels so the last three bits of playerX has rolled over so you align to the solid tile column,

atleast that sounds like a reasonable explanation.

So I need to check collisions before moving/scrolling, not after.


That is correct.  The collisions register are updated by the STIC at the point when the video frame is composed, which is after a WAIT (when the interrupt arrives).  IntyBASIC then buffers the status of collisions in its own data structure and makes it available to your program.


Hardware sprite positions, GRAM picture updates, and hardware scrolling shift (i.e., the things that affect collisions) occur at the start of the video frame; but BACKTAB updates (which also can affect collisions) happen ad hoc, at any time later.

 

More importantly, the full screen shift at the 8th scrolling step is a BACKTAB update, so it occurs after the collisions are detected, and after the screen was shifted back eight pixels to position zero.

 

That means that by the time your game peeks at the collision registers, you are actually getting the state of the last frame update -- that is, the video frame that was rendered from the current state of the game at the time the WAIT occurred, and not at the precise moment you are trying to read it (which may be later).

 

That should be fine, provided you are aware of it and compensate; but it does mean that you are always one frame behind.


IntyBASIC does a great job of abstracting that complexity of handling the video blanking interrupt, and buffering access to the STIC, and all that; but sometimes you just can't get away from having to deal with that big mess.

 

These are some of the little tiny details that make the difference between a glitchy game and a more robust and polished one, at least in my opinion. :)

 

    dZ.

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...