GameMaker: Studio

GameMaker: Studio

View Stats:
Why do my horizontal collisions act weird?
I'm still working on just trying to make a general purpose collisions block, which would act at least as walls and floor.
My problem is, the block (named Floory), works fine as a floor, but as a wall, my player collides with it, and loses all speed. Basically, it sticks for a full second, and then comes loose and falls.
Help!
< >
Showing 1-15 of 23 comments
Sera Jun 27, 2013 @ 2:41pm 
Are you simply checking for a collision after movement? That can cause some issues.

You may want to, alternatively, see if a position is free before moving to it, or somehow reposition the object after movement if a collision has occured (if moving right, move back left until no longer colliding via a quick loop, for example).

If the issue is the player loses vertical speed upon hitting a wall horizontally, though, that could simply be a problem with the bounding boxes on whatever sprites your using.

It's a bit hard to say based just off of what you're giving me here, but those are my initial three guesses.
Spce General Jun 27, 2013 @ 2:51pm 
Lemme rephrase:

I use the same blocks for walls and floors. Landing on floors works fine, and horizontal momentum is preserved while doing so.

Colliding into a wall (Whether or not that particular directional button is pressed) has a very high tendency to freeze a few pixels short of the wall, robbing the player object of horizontal AND vertical momentum, before the step gravity check takes over and it just falls, usually after a full second or two.

My current method of collision checking is to use the "collision with floory" event (Floory, again, is the name of my general purpose collision block for walls and floors), and then run a check to see what side the collision was on (If there's a collision at (1,0) or (-1, 0) then stop horizontal movement; if there's a collision at (0,1) then stop vertical movement), before stopping the appropriate movement.

WHen I used a collision check every step, (With those same rules), my player object would end up sinking halfway into whatever it was supposed to stop on, and at this point, I'm running out of ideas.
Sera Jun 27, 2013 @ 3:22pm 
If you're simply stopping movement when a horizontal collision occurs, then the vertical collision will likely be true as well. if you hit a wall sideways and simply stop, you're still technically "colliding" with that object, and it's very rare that would be different if the player instance was shifted down one pixel. This can also cause problems if you hit the floor at an awkward speed, because the position the player "lands" at could be slightly inside the floor, making the collision checks to either side remain true because, technically, your feet are inside the floor.

generally, the easiest things to do will be reversing a player's movement if the collision occurs, or making sure the position to be moved to is open BEFORE the move action takes place; in the latter case, you may want to move the player as far as possible so the game feels natural instead of leaving the player four pixels from a wall and unable to get any closer, but either way it may be wise to look into do loops. As a general example:

if place_meeting(x, y, floory) and x > xprevious then { do x -= 1 until not place_meeting(x, y, floory) } else ...

I don't have GM open atm so forgive me if the syntax isn't perfect, but this is attempting to use GM's built in variables to check a few things, while assuming that the palyer has moved before the check.

1) If there is a collision at the moment with any instance of floory
2) If the player has moved to the right this step (x has increased since the last step; this assumes you're using GM's built in movement functions, so if you're not you'll have to replace some things, but the logic would get easier and have fewer steps likely)

If those conditions are both true, it scoots the player back to the left until it's not colliding any more. This has flaws but to start with it should help with your wall-sticking issue. I think. This all also assumes you've double-checked any sprites and subimages involved to all have the same collision box size and relative origin position; precise collision can really screw you up when it's not needed, and GM may still be leaving it on by default like it has in previous versions, I'm not sure.

Also, in the event you're just using the drag and drop functions, I'm actually less aware how to do this, so I apologize for that. Hopefully this helps somehow either way.

EDIT: As an afterthought, and something that has vexxed me before, if you're by chance flipping your sprite to change directions and your origin isn't properly centered with the collision region, there's also the slight chance a character's arse can get stuck in a wall, so mind that too I guess. I don't think that's the problem here, but it may prevent future headaches a bit.
Last edited by Sera; Jun 27, 2013 @ 3:24pm
Spce General Jun 27, 2013 @ 3:46pm 
Well right now my sprite is just a 32x32 ball and origin is set to the center.
So I should use this place_meeting function in conjuction with xprevious, and this is going to basically say "If you collide here, and your x coordinate is headed towards the wall, then we're going to rebound you"?

And I assume then I'm going to set hspeed to zero afterwards?
Spce General Jun 27, 2013 @ 3:50pm 
Also I assume I'm replacing place_meeting(x,y, Floory) with place_meeting(player_obj + 1, player_obj, Floory), or does placing the code within the player object automatically make the x,y coordinates relative?
Sera Jun 27, 2013 @ 4:06pm 
Any time you call a variable in an object, it references itself. To reference a specific object's position from a different object, you would use, say, obj_Target.x to get its x position, though this has a definite fault, in that "obj_Target" will reference any and all instances of obj_Target in the room. There's a number of ways to get a specific instance id (ie. instance_nearest() returns the instance of a specified object closest to a given position) and those can prove really helpful down the line as well.

You probably do either want to set hspeed to 0 (or invert it, if you're going bouncy), but not doing so would simply result in the wall collision running again the next step, resetting the ball anyway, so unless it causes some visual faults that's entirely optional.

Since you ARE using hspeed, tho, instead relying on my shady knowledge with x > xprevious, you could alternatively use hspeed > 0 for moving to the right, or hspeed < 0 for moving left (in which case you'll want to do x+=1 to move the ball back right instead of -=1 to move it left).

If you come across the floor issue I've brought up, the same applies to vspeed and the do loop; if you're hitting a floor, y-=1 until that's not the case, and inverted for the ceiling. Mind, either of these can hit a problem if you hit a floor and wall at the exact same time when used together, but for now it should at least get things going in the right direction.

NOTE: I could be mistaken, but I'm fairly certain GM handles any built-in movement just before executing the Step event. Begin Step may let you work before the movement occurs, I'm not sure! That would give you more logic options, but so does writing your own movement variables and code. It's all very pro-con.
Spce General Jun 27, 2013 @ 4:47pm 
Well I tried that code, and I'm sure I've done something wrong because I'm just dropping throuhg the floor now.

if place_meeting(x,y, Floory) and (y > yprevious)
{
do
{
y = y - 1;
}until (not place_meeting(x,y, Floory))
vspeed = 0;
gravity = 0;
}

Is my floor-collide code, not even getting to the wall collide yet.
Sera Jun 27, 2013 @ 5:29pm 
Okay, let's compare notes, then.

I tried this with relative success:

if place_meeting(x, y, obj_Floor) and vspeed > 0 then { do y-=1 until not place_meeting(x, y, obj_Floor); vspeed = 0; gravity = 0; }

the only key difference I see here (besides what we're calling the floor) is that we're using yprevious, which... I honestly thought should be working, unless I'm missreading something here. Fundametnally, we're doing the same thing save some slight inconsequential formatting.

  • I'm assuming we're both doing this in the step event.
  • We both use place_meeting to check for the collision.
  • we both are checking the y position, though since you stated you're using vspeed and gravity, I changed it to checking if the yspeed is greater than 0, implying a downward motion.
  • we're both backing y up, just by different means (y -= 1 is the exact same as y = y-1; the -= just increments the given variable by a set amount)
  • we're both using the same loop format and telling it to stop when a certain condition is not true.
  • We both then reset the vspeed and gravity.

I'm a bit baffled why mine is working when yours isn't, thus. My only ideas are odd things like "is it floory instead of Floory?" or "maybe yprevious is broken," as I looked it up and it should be behaving exactly as expected. It's not unprecidented for GM to behave a bit oddly from time to time, but... hm.

Try plopping mine in yours and see if it works with some noun changes, I guess. There's only one real difference and they sh-oh snap I figured it out maybe.

REAL TIME COMMENTARY - the sign of a true professional!

OKAY.

The difference is that yprevious always refers to where you were in the last step. Technically, even after the do loop, your y position is still greater than it was the previous step. I did not think of this and thus your troubles this time are entirely my fault. Oh my! But because of this, that condition is always true, even though the player is always descending. That's why vspeed and yprevious would have such different results!

I feel simultaniously smart and dumb since it was my idea to use yprevious in the frist place.
Spce General Jun 27, 2013 @ 6:44pm 
so in response to that, I should change the condition from yprevious to vspeed > 0?
Spce General Jun 27, 2013 @ 7:10pm 
Oh snap wait, this seems to work:

if place_meeting(x,y+2, Floory) and (vspeed > 0)
{
do
{
y = y - 1;
}until (not place_meeting(x,y + 2, Floory))
vspeed = 0;
gravity = 0;
}
Spce General Jun 27, 2013 @ 7:12pm 
Well, that sorta works. I applied the same logic to my horizontal collision code, but now I shoot to the top of walls I hit when I go faster than mildly slow...
Spce General Jun 27, 2013 @ 7:37pm 
Hmm...Would it be prudent to make the floor check take place on the backside of the object? Like, if it's moving in +x direction, then have the floor check take place at (-1, 1)? That might stop the front of the object detecting the wall as a floor and jumping to the top of it, right?
Sera Jun 27, 2013 @ 9:01pm 
And this brings us to why I don't much care for using GM's local variables, as it results in the movement all occuring at once and complicating checks like this.

Something you could do is do both checks at once in the do loop, but it's prone to getting a bit complicated. Effectively, move it back diagonally, but the exact logic is eluding me at the moment as my mental focus is getting a bit scattered. Regardless, maybe that will help you out a bit until I've the clarity to point you more properly.

... Thinking about it...

I have an odd solution we could try? Let's see...

  • on collision, revert the player's position (x -= hspeed, y-=vspeed)
  • using the do loops, move along each axis in the proper direction, if applicable, until there's a collision at that position + 1

So, in pretend-code, because I think you're getting this enough that I don't need to spell every last thing out (which is awesome and good on you):

if collision { if hspeed != 0 then x -= hspeed same with yspeed then, if hspeed > 0 move right until doing so again would hit a wall (ie. place_meeting(x+1, y, Floory); if < 0 move left repeat for vertical movement reset speeds and gravity }

In theory, this would move you as close to the wall as you could be without hitting it and get things all set up properly. I'm not sure!

I swear when it comes to the most simple-sounding of things (platformer code) there's always new things to try and figure out even for the simplest of tasks to make it as fool-proof as possible. It's easy to make a platformer, but damn hard to make a good one.
Spce General Jun 27, 2013 @ 9:13pm 
This is a dumb, basic question, but I'd never encountered the operator -= before. Is that basically (variable * -1)?
Spce General Jun 27, 2013 @ 9:59pm 
Funny, if I wasn't interested in preserving momentum on collision, I'd be leaps and bounds ahead of this point by now :P

Anyways, I popped my best translation of your pseudo code into my collision event (At least that's what I think you meant by if collision) and my ball's just kinda hovering above the ground. I'm gonna play with the ground detections for move events and see if I can't get this ball running.

EDIT: WAIT forgot to reset speeds after collision
Last edited by Spce General; Jun 27, 2013 @ 10:01pm
< >
Showing 1-15 of 23 comments
Per page: 1530 50

Date Posted: Jun 27, 2013 @ 1:13am
Posts: 23