Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411490 Posts in 69371 Topics- by 58428 Members - Latest Member: shelton786

April 24, 2024, 08:12:51 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Coliding slopes
Pages: [1]
Print
Author Topic: Coliding slopes  (Read 1469 times)
lyon
Level 0
***



View Profile
« on: April 29, 2015, 09:04:37 PM »

I have been having... mixed results trying to implement simple 45° slopes in a tile-based game. It seems like every problem I manage to tackle creates another one.

The biggest issue I can't seem to sort out is related to slopes that are in succession, such as in the image below:



Everything works great unless the player happens to land right here:



At which point the character goes right through the level or bounces off of the slope as the game is trying to get the player's position to the correct tile.

I'm checking to see if the bottom right corner collides with any tile that is a slope, and then I am checking to see if it has reached y = mx + b. The code's a little messy because I've been trying to tweak just about everything and anything to trick it into not slipping through the cracks there.

Code:
 52                         if (map.hitTest(this.rect.x+1-this.ax,this.rect.y+this.rect.h) || map.hitTest(this.rect.x+this.rect.w-1-this.ax, this.rect.y+this.rect.h)) {
 53                                 if(map.checkTile(this.rect.x+this.rect.w, this.rect.y+this.rect.h)== 3 || map.checkTile(this.rect.x, this.rect.y+this.rect.h)== 3){
 54
 55                                         if (this.rect.y > Math.floor((this.rect.y-1)/map.tileHeight)*map.tileHeight - (map.tileHeight - this.rect.h) + (-(((this.rect.x+map.tileWidth-this.rect.w-1)%map.tileWidth) - map.tileWidth))){
 56                                                 this.rect.y = Math.floor((this.rect.y-1)/map.tileHeight)*map.tileHeight - (map.tileHeight - this.rect.h) + (-(((this.rect.x+map.tileWidth-this.rect.w-1)%map.tileWidth) - map.tileWidth));
 57                                                
 58                                                 this.ay = 0;
 59                                                 this.jumpBoost = 0;
 60                                                 this.jumping = false;
 61                                         }else if (this.rect.y+ (-(((this.rect.x+map.tileWidth-this.rect.w-1)%map.tileWidth) - map.tileWidth))< Math.floor((this.rect.y+this.rect.h-1)/map.tileHeight)*map.tileHeight - (map.tileHeight - this.rect.h) + (-(((this.rect.x+map.tileWidth-this.rect.w-1)%map.tileWidth) - map.tileWidth))){
 62                                                 this.rect.y = Math.floor((this.rect.y-1)/map.tileHeight)*map.tileHeight - (map.tileHeight - this.rect.h) + (-(((this.rect.x+map.tileWidth-this.rect.w-1)%map.tileWidth) - map.tileWidth));
 63                                         }
 64                                 }else{  
 65                                         this.jumpBoost = 0;
 66                                         this.ay = 0;
 67                                         this.jumping = false;
 68                                         this.rect.y = Math.floor((this.rect.y)/map.tileHeight)*map.tileHeight + (map.tileHeight - this.rect.h);
 69                                 }      
 70                                
 71                                        
 72                                 if (game.input.up){
 73                                         this.jumping = true;
 74                                         this.jumpBoost = jumpBoost;
 75                                         this.ay = -jumpBoost;
 76                                 }      
 77                                
 78                         }else{          
 79                                 this.jumping = true;
 80                         }      

Another problem is that the player won't move onto the slope from the left if it's on a normal ground tile. Here's a gif that shows off some of all of this bad behavior. (Not sure why the gif is flashing like that)



Should I just be scrapping everything and figuring out a better way of doing the collision detection? This has been ruining the past week for me in terms of productivity
« Last Edit: April 29, 2015, 09:09:42 PM by ttsub » Logged
Endurion
Level 2
**



View Profile WWW
« Reply #1 on: April 29, 2015, 10:05:16 PM »

For slopes I usually use the center bottom position as the pixel that actually stands on ground. Yes, this means, the red box would partially go into the sloped ground.
Logged
ProgramGamer
Administrator
Level 10
******


aka Mireille


View Profile
« Reply #2 on: April 30, 2015, 04:56:20 AM »

Screw slopes right?
Logged

lyon
Level 0
***



View Profile
« Reply #3 on: April 30, 2015, 11:28:02 AM »

Screw slopes right?

Nooo kidding haha.

For slopes I usually use the center bottom position as the pixel that actually stands on ground. Yes, this means, the red box would partially go into the sloped ground.

I just tried implementing something like that, but problems persist when this.rect.x+this.rect.w/2 winds up landing on the tile in-between which doesn't contain a slope. Ultimately I feel like this whole thing boils down to my collision-detection not being ideal for slopes, which is a shame since it is working so well for the regular tiles  Concerned and/or how I'm snapping the player into position on collision.
« Last Edit: April 30, 2015, 11:49:20 AM by ttsub » Logged
RandyGaul
Level 1
*

~~~


View Profile WWW
« Reply #4 on: April 30, 2015, 11:51:58 AM »

You're going to need to allow the player to partially intersect slopes, or you will need to ignore the square tile between two sloped tiles (or some other code to handle your numeric case).

Currently you just sort of naively let the player walk along the slopes without handling the numeric case of when the corner of the player touches the block that is completely land-locked by two sloping tiles.
Logged
Cheezmeister
Level 3
***



View Profile
« Reply #5 on: April 30, 2015, 04:20:59 PM »

Should I just be scrapping everything and figuring out a better way of doing the collision detection? This has been ruining the past week for me in terms of productivity

I'd seriously consider that at this juncture, but it really depends on the kind of physics you're going for. Going from right angles to 45° seems like it should be simple but it might be quite a leap if your collision was naive until now. Here's some questions to ask yourself in no particular order...

* Do you want objects to rotate (i.e. apply torque)?
* Do you want objects to slide?
* Bouncing? What kind?
* Sticking?
* Destructible environment?
* Ghosting/phasing through stuff?
* 30° angles? 54.123° angles? Circles? Arcs?

Collision detection is a common issue with lots of algorithms to steal, if you're careful not to go overboard. Overengineered < Underengineered < Just Right(TM)
Logged

෴Me෴ @chzmstr | www.luchenlabs.com ቒMadeቓ RA | Nextris | Chromathud   ᙍMakingᙌCheezus II (Devlog)
lyon
Level 0
***



View Profile
« Reply #6 on: April 30, 2015, 05:34:46 PM »

You're going to need to allow the player to partially intersect slopes

That does solve the problem of the player going through the floor while moving upwards.

I think the way I'm doing the collision detection is causing a lot of the problems. When moving down the slope, it's unable to detect that there's a slope tile underneath when the tile in-between is hit. It can detect that there's a tile underneath, just not a slope, and it clips to it. Also I think there's a problem with how I'm detecting the x collision, because there's a range of about half the width of the character that breaks the collision detection as well.

Should I just be scrapping everything and figuring out a better way of doing the collision detection? This has been ruining the past week for me in terms of productivity

I'd seriously consider that at this juncture, but it really depends on the kind of physics you're going for. Going from right angles to 45° seems like it should be simple but it might be quite a leap if your collision was naive until now. Here's some questions to ask yourself in no particular order...

* Do you want objects to rotate (i.e. apply torque)?
* Do you want objects to slide?
* Bouncing? What kind?
* Sticking?
* Destructible environment?
* Ghosting/phasing through stuff?
* 30° angles? 54.123° angles? Circles? Arcs?

Collision detection is a common issue with lots of algorithms to steal, if you're careful not to go overboard. Overengineered < Underengineered < Just Right(TM)

Really all I'm concerned about is the basic collision detection, and simple 45° slopes.

Until I sort out these problems, I've simplified it a little so that the second it touches a slope tile, it just clips right to it.

Code:
 53                         if (map.hitTest(this.rect.x+1-this.ax,this.rect.y+this.rect.h) || map.hitTest(this.rect.x+this.rect.w-1-this.ax, this.rect.y+this.rect.h)){
 54                                 if(map.checkTile(this.rect.x+this.rect.w/2-this.ax, this.rect.y+this.rect.h-1)!= 3) {
 55                                         this.ay = 0;
 56                                         this.jumpBoost = 0;
 57                                         this.jumping = false;
 58                                         this.rect.y = Math.floor((this.rect.y)/map.tileHeight)*map.tileHeight + (map.tileHeight - this.rect.h);
 59                                         if (game.input.up){
 60                                                 this.jumping = true;
 61                                                 this.jumpBoost = jumpBoost;
 62                                                 this.ay = -jumpBoost;
 63                                         }      
 64                                 }else if(map.checkTile(this.rect.x+this.rect.w/2-this.ax, this.rect.y+this.rect.h-1)== 3){
 65                                         this.ay = 0;
 66                                         this.jumpBoost = 0;
 67                                         this.jumping = false;
 68                                         this.rect.y = Math.floor((this.rect.y-1)/map.tileHeight)*map.tileHeight - (map.tileHeight - this.rect.h) + (-(((this.rect.x+this.rect.w/2)%map.tileWidth) - map.tileWidth));  
 69        
 70                                 }
 71                                
 72                         }else{
 73                                
 74                                 this.jumping = true;
 75                         }

Here's a couples gifs of the behavior the middle collision point. I removed a tile just to make sure that it wasn't somehow interfering with things (it doesn't seem to).



Logged
RandyGaul
Level 1
*

~~~


View Profile WWW
« Reply #7 on: April 30, 2015, 06:58:51 PM »

Okay this is good! You removed the middle tile and can now really debug your algorithm. I don't have time to take a look at your code, but I really liked how you took a good debugging step and posted up good gifs of your problem.
Logged
lyon
Level 0
***



View Profile
« Reply #8 on: April 30, 2015, 07:17:09 PM »

Okay this is good! You removed the middle tile and can now really debug your algorithm. I don't have time to take a look at your code, but I really liked how you took a good debugging step and posted up good gifs of your problem.

Thanks! Yeah the last couple of weeks has been a nightmare of running various things through the console to try and get a good feel for what is actually happening and I'm slowly narrowing down every last problem (you should have seen it a week ago Facepalm)

One thing I am not sure is clear from these gifs is that if you approach the bottom of the slope tiles from above (the point where you see that little hopping occuring), the player gets caught as well, so it's not necessarily a problem with approaching the tile from the right as far as I can tell, I seem to be messing up the x position in the map.checkTile() function.
Logged
lyon
Level 0
***



View Profile
« Reply #9 on: May 01, 2015, 08:05:00 PM »





I figured out what was causing it to bounce up at the bottom of the slopes. It was not factoring in the horizontal acceleration of the player when sorting out what the y position of the slope should be. Because of this, it was figuring that the y displacement should go back to 0 (as it would if we were onto the next tile). I simply added the horizontal acceleration to the formula (ie: y = m(ax+x) + b) and that does the trick.

This of course causes the player to shift position when moving on the slope, creating a sort-of leaning in effect on the slope. I'm not sure I like this, so rather than factoring in the horizontal acceleration, I'm just going to include a conditional statement that checks against the acceleration before changing the y position instead. But for now, this is what it looks like:



Aside from the "leaning in" on the slope (which I'm sure I know how to fix), the only remaining problem is the behavior in between the tiles. Ideally, it would keep moving consistently, but it gets sort of caught on the corner. When moving quickly, it looks smooth and isn't as noticeable, but it's pretty obvious when moving slowly.
Logged
JWK5
Guest
« Reply #10 on: May 01, 2015, 09:47:59 PM »

Don't have a lot of time here so I will have to explain it through doodles, but how I usually go about it is along these lines:

Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #11 on: May 02, 2015, 12:59:42 AM »

JWK5 - that looks really interesting, but I don't quite see how it works. Won't that mistake waist high fences for slopes?
Logged
oahda
Level 10
*****



View Profile
« Reply #12 on: May 02, 2015, 01:17:51 AM »

I just mark slopes as such and give them special treatment.
Logged

gimymblert
Level 10
*****


The archivest master, leader of all documents


View Profile
« Reply #13 on: May 04, 2015, 10:04:37 AM »

JWK5 - that looks really interesting, but I don't quite see how it works. Won't that mistake waist high fences for slopes?
I think his collision happen at sub tile, which mean the tile themselves are the minimal height

BUT we can look at teh master of slopes ... sonic
http://info.sonicretro.org/SPG:Solid_Tiles

http://info.sonicretro.org/Sonic_Physics_Guide

Logged

JWK5
Guest
« Reply #14 on: May 05, 2015, 08:33:54 AM »



Obviously you would want to base the move distance from the origin point where X is concerned, and either the top of the character or the bottom where Y is concerned. Even when on the ground the vertical check can extend as far down as is equal to the fall speed.

I usually manage the check as a for loop sweep.

Code: (pseudocode)
for (H=move_speed_x; H>0; H-=1)
{
   for (V=fall_speed; V>0; V-=1)
   {
      check_for_collision(H,V);
      if (no_collision) { move_to(x+H,y+V); }
   }
}
« Last Edit: May 05, 2015, 08:46:59 AM by JWK5 » Logged
lyon
Level 0
***



View Profile
« Reply #15 on: May 11, 2015, 01:35:15 PM »



Obviously you would want to base the move distance from the origin point where X is concerned, and either the top of the character or the bottom where Y is concerned. Even when on the ground the vertical check can extend as far down as is equal to the fall speed.

I usually manage the check as a for loop sweep.

Code: (pseudocode)
for (H=move_speed_x; H>0; H-=1)
{
   for (V=fall_speed; V>0; V-=1)
   {
      check_for_collision(H,V);
      if (no_collision) { move_to(x+H,y+V); }
   }
}

This has all been incredibly helpful. I can already see your method of using a loop to check for a collision is much more effective than my strategy of sort of snapping the character to the nearest tile (which is what is causing the majority of the problems). Of course now I want to rewrite a lot of how my collision detection is working, so I will spend tomorrow sorting that out and report back here.

Thanks a million folks Smiley
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic