It is currently Thu May 23, 2019 2:29 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Thu Nov 29, 2018 5:20 am 
Offline

Joined: Sun Nov 25, 2018 9:13 am
Posts: 2
I am programming a metroid clone in C, and need some help with handling slopes.

A little info:
The player has a top-left origin, and a collision rectangle given as an x, y offset, width, and height. He's about
2 tiles tall and 1 tile wide. The TILE_SIZE is 16 pixels. Only whole pixel movement is possible.

The method I currently have for background collision is taken from what I have read on this forum.
It is the basic step x before y eject if solid algorithm, checking along the edges of the collision rectangle,
though I have included the psuedo-code of the version I use below,
just in case you have ideas for improvements.

BG collision algorithm (pseudo-code)
Code:
1. Add x velocity to x position.
2. Compute corners of collision rectangle.
3. Define a point p as the top-right (or top-left for neg. velocity) corner.
---4. Is the tile at point p solid? If so, eject the player along x-axis and go to 7.
---5. Otherwise add TILE_SIZE pixels to the y-coordinate of p.
---6. If p is below the collision rectangle snap it to the bottom side then set a flag that this is the last horizontal check. Go to 4.
7. Add y velocity to y position.
8. Re-compute corners of collision rectangle.
9. Define a point p as the bottom-left (or top-left for neg. velocity) corner.
---10. Is the tile at point p solid? If so, eject the player along y-axis and go to 13.
---11. Otherwise add TILE_SIZE pixels to the x-coordinate of p.
---12. If p is to the right of the collision rectangle snap it to the right side then set a flag that this is the last check. Go to 10.
13. Return.

This algorithm seems to work fine for ordinary solid, rectangular blocks and speeds less than TILE_SIZE.
But whenever I try to introduce 45 deg. slopes I always get buggy / game-breaking results...

Q:
Should I check along x-axis before y-axis if I am adding slopes?
Do I ignore slopes in the horizontal step and snap the y-position if colliding with slope in the vertical step?
What x position should I use as how far up/down the slope you are?
Do I need an entirely new algorithm? (like stepping x and y at the same time with smaller increments?)

Comments:
So far the most stable result I have been able to get is to increment vertical-position during the horizontal step if colliding with a slope,
and skip the vertical step entirely if a slope was encountered in the horizontal step.
However if you stop moving left or right you are just ejected up from the slope this way (floating "in air" over it), and there is
no way to walk down a slope. I have no idea how to do sloped ceilings.

Thank you for your time.


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 8:12 am 
Offline
User avatar

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 610
Location: Central Illinois, USA
I don't have much time to reply right now, so instead of answering your question directly, I'm going to recommend this guide. http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/. It's the best resource I've found for advice about how to implement platformer physics/platforms/slopes/ladders/etc.

_________________
My games: http://www.bitethechili.com


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 9:57 am 
Offline
User avatar

Joined: Wed Sep 07, 2005 9:55 am
Posts: 364
Location: Phoenix, AZ
I'm not sure how one would do it with just four collision points, I used eight. These will hold the values of the metatiles at the points top-left, top-middle, top-right, mid-left, mid-right, bottom-left, bottom-middle, bottom-right for the object being tested:

Code:
   unsigned char mt_tl, mt_tm, mt_tr;
   unsigned char mt_ml,        mt_mr;
   unsigned char mt_bl, mt_bm, mt_br;


My system defines slope heights per x pixel for each sloped metatile to allow for things like curves.

LEFT, RIGHT, TOP, BOT are macros that test if that side of a metatile tile is solid from that direction. This allows for metatiles that can be jumped through, but not fallen through. SLOPE is a macro that tests if that metatile is sloped or not. Here's the basic pseudo-code of it:


Code:

add vel_x to pos_x

get mt_bm

if (going_right)
{
  get mt_tr, mt_mr, mt_br
  if ( LEFT(mt_tr) || LEFT(mt_mr) || (!SLOPE(mt_bm) && LEFT(mt_br)) )                       // cancel out left ejection if bot-mid is in a slope, allowing right movement
    eject_left
}
else if (going_left)
{
  get  mt_tl, mt_ml, mt_bl
 
  if ( RIGHT(mt_tl) || RIGHT(mt_ml) || (!SLOPE(mt_bm) && RIGHT(mt_bl)) )                   // cancel out right ejection if bot-mid is in a slope, allowing left movement
    eject_right
}

add vel_y to pos_y

if (falling_down)
{
  get mt_bl, mt_bm, mt_br
 
  if (SLOPE(mt_bm))
  {
    x_pix = object->mid_x() % 16;                     // translate object mid-x pos to the x pos within the metatile
    dy = s_slopetbl[INDEX(mt_bm)][x_pix & 0x0F];      // get the height of the metatile at that position
    y_bits = object->bot() % 16.0f;                   // translate object bot-y pos to the y pos within the metatile

    if (y_bits > dy)                                  // if the player has sunk into the slope
    {
      object->add_to_y(dy - y_bits);                  //   set player at top of slope
      m_vel.y = 0;
      if (m_acc.y > 0) m_acc.y = 0;                   //   ***this allows negative y acc for jumps, but not positive for falls***
    }
    eject_up                                          // normal upward ejection
  }
  else if (TOP(mt_bl) || TOP(mt_bm) || TOP(mt_br))
    eject_up

}
else if (rising_up)
{
  get mt_tl, mt_tm, mt_tr
 
  if (BOT(mt_tl) || BOT(mt_tm) || BOT(mt_tr))
    eject_down
}


There is no support for sloped ceilings, but I guess I would just handle them the same as slopes but in reverse.

_________________
. That's just like, your opinion, man .


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 1:46 pm 
Offline

Joined: Sun Nov 25, 2018 9:13 am
Posts: 2
never-obsolete wrote:
I'm not sure how one would do it with just four collision points, I used eight.


I don't use 4 collision points specifically, instead I sample points along one side of the collision rectangle with spacing at most equal to TILE_SIZE, and clamp the result so the sampled point is always on the line. Your idea about LEFT/RIGHT/BOTTOM/TOP solidity sounds very good, and storing the tile heights seems like a very good system too. I think I will at least need BOTTOM/TOP solidity for one-way platforms.

I got OK results by completely ignoring the slope tiles in the x-step and y-step of the collision routine, and instead doing another check afterwards specifically for slope tiles using only the corners, were I eject the sprite upwards on the y-axis if its below the slope line, or for ceiling slopes eject the sprite downwards. It does mean a slope without any solides near it you can walk right through however... How do you make the sprite stick to the slope? Do you use gravity?


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 6:37 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2507
Location: DIGDUG
If I were going to check a point on a slope, I would have a Y array (8 bytes, or maybe 16) of collision points for every Y level.

Example \ = 0,1,2,3,4,5,6,7
(solid bottom left)

So you know which block the point is in, the low nibble of Y position should tell you the exact X point is collision. Let's say the Y pos. of point is $45, we check the 5th byte, which is 5. If the X position is °< $x5, collision. If it is > $x5, no collision. You adjust up.

Similarly, you could think of the BG as vectors (points and lines), and have arbitrary angles. To check collision, you just need to decide which to points you are between, and generate the Y array on the fly with a trigonometry LUT.

Possibly the NES is too slow for this sort of thing.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 7:32 pm 
Offline
User avatar

Joined: Thu Aug 13, 2015 4:40 pm
Posts: 405
Location: Rio de Janeiro - Brazil
This totally reminds me of the famous article https://games.greggman.com/game/programming_m_c__kids/

The way I understand it, they made it so you have an "onground" flag. If the player is onground, just set the Y position based on the X position by looking in the correct table for the tile the player is walking on. That way you can have the ground on any shape, even pretty curves (curves may make it harder to detect a landing).

_________________
https://twitter.com/bitinkstudios <- Follow me on twitter! Thanks!


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 8:14 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11348
Location: Rio de Janeiro - Brazil
This is another great source of ideas on how to implement slopes: http://info.sonicretro.org/SPG:Solid_Tiles

Sonic had quite advanced physics for the time, but its collision system is pretty straightforward, specially if you disregard rotation. Sonic sticks to the floor, and every slope has an array of heights, that's used to control the Y position of objects that are on the ground, and to detect when objects collide with the floor coming from above so that their state switches from "off the floor" to "on the floor". Each slope also has an angle value, which can be used to accelerate or slow down objects (most objects ignore this, only Sonic/Tails/Knuckles really react to the different angles).

Slopes in M.C. Kids are kinda poorly implemented IMO, you can code a more robust/versatile system without necessarily making things any more complex. Both Sonic and M.C. Kids have bugs in their slope collision systems though, and those are mentioned in the respective articles. I've come up with my own solution to solve Sonic's problem: when walking off pointy edges (i.e. the leading sensor point that was making contact with the floor has lost contact), remember the height of the last column of the slope and its X coordinate, and keep using that as the height of the floor until the trailing sensor point crosses the X coordinate of that column, when you can go back to checking the floor height normally.


Top
 Profile  
 
PostPosted: Thu Nov 29, 2018 8:57 pm 
Offline
User avatar

Joined: Wed Sep 07, 2005 9:55 am
Posts: 364
Location: Phoenix, AZ
Quote:
How do you make the sprite stick to the slope? Do you use gravity?


Yes. Gravity moves the object down, causing bottom-middle to register a slope has been hit. Then the slope handling code snaps the Y coordinate to the top of the slope if Y is considered to be in the solid part of the metatile at that particular X. Then the normal collision code causes the object to be ejected up and out of the solid tile.

_________________
. That's just like, your opinion, man .


Top
 Profile  
 
PostPosted: Fri Nov 30, 2018 2:20 am 
Offline
User avatar

Joined: Thu Sep 15, 2016 6:29 am
Posts: 896
Location: Denmark (PAL)
nesrocks wrote:
The way I understand it, they made it so you have an "onground" flag. If the player is onground, just set the Y position based on the X position by looking in the correct table for the tile the player is walking on. That way you can have the ground on any shape, even pretty curves (curves may make it harder to detect a landing).


That's absolutely the way to do it if you are going for a classic video game design. Remember playing those games where walking down stairs or steep slopes let you occasionally drop down a pixel, making it impossible to jump if you mistimed your input while falling? Yeah, you don't want that. :P
Of course if you want to make really steep slopes that you want the player to be able to run off of, those should be an exception, or the movement would be weird (which it is in a lot of games).

I mean you could go for a realistic physics simulation, but why do that? It's a video game.
I'd imagine most platformers already have an "onground" flag anyway, for jumping purposes.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 15 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group