2

I'm trying to make a platformer that just uses pixel colors as a way to check for the ground/walls of a level, no sprite flags. At first it seems to work, the guy (stick) moves left/right and jumps on the initial ground just fine. But then when you jump up on the platform to the right and either walk or jump off back to the left, he sinks into the ground.

Cart #23455 | 2016-06-23 | Code ▽ | License: CC4-BY-NC-SA
2

See code below, but what I'm doing is checking the pixel immediately below the stick to see if it's a ground color and if so, stop applying the gravity. Seems simple enough...made sense to me but I'm clearly missing something.

I'm happy with the jumping action, it's nice and smooth and such but landing seems to be an issue. If anyone has suggestions for my code or just insight in general, I appreciate it. Making a platformer is new to me...I usually make shmup games :)

NOTE: Code as-is is not checking for left/right collisions, just ground for jumping.

 ```t=0 colors={wall=7,air=0,player=8} debug=false -- -- player -- positionX = 40; positionY = 89; velocityX = 2; velocityY = 0; gravity = 0.5; onGround = false; function _update() btnright=btn(1) btnleft=btn(0) btnjump=btn(4) --horizontal movement if btnleft then positionX-=velocityX end if btnright then positionX+=velocityX end if positionX>127 then positionX=127 end if positionX<0 then positionX=0 end --jump, apply velocity if btnjump and onGround then velocityY = -3.5; onGround = false; end --calc in gravity and add to Y velocityY += gravity; positionY += velocityY; --check pixel below player to see if it's a wall color local below=flr(positionY+1) if pget(positionX, below)==colors.wall then positionY = below-1; velocityY = 0; onGround = true; end debug=pget(positionX, below) t+=1 end function _draw() cls() line(positionX,positionY, positionX,positionY-2, colors.player) --draw stick up from foot pset(positionX,positionY, 10) --foot --ground rectfill(0,90, 128,128, 7) rectfill(100,82, 128,128, 7) print(debug,0,120,1) print(positionX..", "..positionY, 90,120,2) end ```

P#23457 2016-06-22 20:59 ( Edited 2016-06-23 03:48)

:: Danjen

The problem is likely from the velocity being a decimal, rather than a whole number. When falling from distances that are odd-numbered, you'll get fractional values and I assume rounding errors.

The typical way to do this is to take your current position and add the velocity as an offset, then scan from A to B and find the last valid position it could go to (so it doesn't clip through a wall). If you set up your methods correctly, it will be very easy to translate it from vertical logic to horizontal

I didn't have a chance to look at your code in depth, so I might be wrong here.

P#23459 2016-06-22 21:25 ( Edited 2016-06-23 01:25)
:: Felice

When you jump down, your VELOCITYY is probably exceeding 1 pixel/update when you fall past the ground level you started at, since you'll fall longer and build up more speed. That lets you embed yourself more than 1 pixel into the ground before you do your collision test. You then do your collision test, see that you've hit, and back up 1 pixel, which leaves you still in the ground.

Your collision test should really check each pixel between the old position and the new iteratively and stop when it hits ground. That, or limit your downward velocity to one pixel/update.

P#23461 2016-06-22 21:37 ( Edited 2016-06-23 01:44)

Hmmm...okay, I can try to give that a shot. So rather than doing X/Y changes directly, do them in a temp variable and check, then work back from there before the change is applied? I think I got it, I'll give it a try and see how bad I munge it up.

P#23462 2016-06-22 21:49 ( Edited 2016-06-23 01:49)
:: Felice

I wouldn't work backwards. Go forwards from the previous position. That way you collide with the first pixel that's in the way. Otherwise you have to see you've collided and then back up and look for the first clear pixel, which is double the work/code.

P#23463 2016-06-22 21:57 ( Edited 2016-06-23 01:57)
:: Felice

Also, don't manually back up when you hit a ground pixel. Just set your position to the last clear pixel you tested. Otherwise doing something like decrementing Y can put you off-trajectory and possibly inside a different ground pixel.

P#23464 2016-06-22 22:01 ( Edited 2016-06-23 02:01)

Here's what I came up with and it seems to be working. I jump all around and he never goes below the level, so that's good. Still no X collision checking yet. But please give what I figured out a review and let me know if it's worthy solution.

I'm not having it back up at all. If the destination is the ground color then I just skip adding it to the position.

Cart #23471 | 2016-06-23 | Code ▽ | License: CC4-BY-NC-SA

 ```positionX = 40; positionY = 89; velocityX = 2; velocityY = 0; gravity = 0.5; onGround = false; dx=positionX dy=positionY function _update() btnright=btn(1) btnleft=btn(0) btnjump=btn(4) --horizontal movement if btnleft then dx=positionX-velocityX end if btnright then dx=positionX+velocityX end if dx>127 then dx=127 end if dx<0 then dx=0 end --jump, apply velocity if btnjump and onGround then velocityY = -3.5; onGround = false; end --calc in gravity and add to Y if not onGround then end velocityY += gravity; dy=positionY + velocityY; --check pixel below player to see if it's a wall color if pget(dx, dy)~=colors.wall then positionY=dy else velocityY = 0; onGround = true; end positionX=dx debug=positionX t+=1 end ```

P#23468 2016-06-22 22:25 ( Edited 2016-06-23 02:28)
:: Felice

It's an interesting way to solve it (deleting code/work is generally the goal), but it does have a flaw.

What you're doing is basically stopping it at the previous position, resetting the velocity due to the collision, and then continuing. The next frame or two accelerates again towards the ground (since you're not on it) and you end up landing correctly since the new velocity is sufficiently small. That often produces a brief hiccup in the motion when you're just about to hit the ground after jumping down.

Edit: It also allows you to jump again before you actually hit the ground. Hold down the jump button while running around and you'll note that you seldom actually touch the ground.

P#23474 2016-06-22 22:38 ( Edited 2016-06-23 02:41)

But isn't that the last clear spot?

I just added some X collision stuff (locally) and am finding that the dude won't jump up at all if he's right next to a wall. It's weird. The dy variable should just be whatever is above him, which is nothing; same with dx.

And found that if you happen to jump just right, you'll stick to the wall above the ground...highlighting your point that it just stops and doesn't apply any more gravity.

Hmmm...well I'm closer, at least. So frustrating because it's so close, been trying to figure this thing out most of the day too. Thanks for the insight, hopefully something will click for me soon.

P#23476 2016-06-22 22:50 ( Edited 2016-06-23 02:50)
:: Felice

It's the clear spot you were in during the previous frame, but if your speed this frame exceeded one pixel, then it might not be the last clear spot before the collision.

P#23477 2016-06-22 22:56 ( Edited 2016-06-23 02:56)

How do you check space in between if the dx/dy is all you have and it's greater than 1px/frame?

I'm calculating the next position into dx/dy, which is based on a speed greater than 1px/frame, like you said. That dx/dy is the next position the player will land, which could be the ground, which is bad. So dx/dy isn't what I want, and I don't want to stop the dude at his current x/y because it's not at the ground yet...so what other option do I have? How would I know what the next clear spot is if all I have a speed bigger than 1?

P#23480 2016-06-22 23:14 ( Edited 2016-06-23 03:14)

Well, here's where I ended up after more playing around. Only weird thing I notice is one pixel weirdness when he jumps into a wall, he dangles 1px above the ground...I know why, kinda, but not sure how to solve it, and not sure if that 1px bothers me enough or not. I think I'll take this and run with it for my game and then if it bothers me see what I can do.

Thanks for all the help and direction...meant a lot and got me this far :)

This does now have X collision checking for walls. I also reduced the player speed to 1px rather than 2px. Probably helps the math a little bit too.

Cart #23482 | 2016-06-23 | Code ▽ | License: CC4-BY-NC-SA

 ```t=0 colors={wall=7,air=0,player=8} debug=false -- -- player -- positionX = 40; positionY = 89; velocityX = 1; velocityY = 0; gravity = .5; onGround = false; dx=positionX dy=positionY function _update() btnright=btn(1) btnleft=btn(0) btnjump=btn(4) dx=positionX --horizontal movement if btnleft then dx=positionX-velocityX end if btnright then dx=positionX+velocityX end if dx>127 then dx=127 end if dx<0 then dx=0 end --jump, apply velocity if btnjump and onGround then velocityY = -3.5; onGround = false; end --calc in gravity and add to Y if not onGround then end velocityY += gravity; dy=positionY + velocityY; local pxcheck=pget(dx, dy) local pxbelow=pget(positionX, flr(dy)+1) --check pixel below player to see if it's a wall color if pxcheck==colors.wall and pxbelow==colors.wall then velocityY = 0; onGround = true; else positionY=dy end if pget(dx, positionY)~=colors.wall then positionX=dx end debug=pxbelow t+=1 end ```

P#23483 2016-06-22 23:48 ( Edited 2016-06-23 03:50)