Legacy GM Platformer engine using collision_ functions

B

boomie

Guest
I'm having a lot of troubles with making a simple platformer engine which is flexible and has no bugs.
All the tutorials I found use place_meeting or instance_place, but these function are not good for me, because I want the player to be able to detect collision with the floor while standing in front of a two way platform.

I don't want to find a way to solve this problem using place_meeting because I will not feel like I have full control over my code and it will be harder for me to change the code and add more features. I really want to make it work using the old collision_ functions.

I was not able to make a flexible pixel perfect engine with collision_rectangle and collision_line. The main problem is that I'm not using a whole number for gravity, and all the systems for vertical moving I tried made the player either hover one pixel above the ground or sink one pixel into the ground.

It could be great if someone could share a tutorial, an engine or show me how to build it right. I can also share the engines I tried if someone would be willing to look at them and find the problem (It's not a lot of code).

Thanks!
 
W

Wild_West

Guest
If your worried about a 2 way platform wouldn't just turning off the collision masks when needed work?
 
B

boomie

Guest
No because I want also the mobs and possibly other players to use them. And I'm also worried about future features I will want to add which will be limited with this function.
 
W

Wild_West

Guest
No because I want also the mobs and possibly other players to use them. And I'm also worried about future features I will want to add which will be limited with this function.
well you say yo want to use the old collision functions as opposed to the others, which woud suggest that your familiar with them already so why aren't they working now?

I use place meeting and place free or empty and all that and don't have any trouble that's too hard to sort out. (Except when it comes to vertical carrying platforms :p)
 
B

boomie

Guest
I was actually working exclusively with gm8 and also there I was never able to build a perfect engine. I moved to gms only because of the place_meeting function which I think didn't exist in gm8. But as I said I don't like these functions anymore. They also have the problem that when your speed is bigger than the solid you can fall through a solid (which can be solved but still annoying).
And by the way place_free and place_empty are even more limited and not flexible.
 
W

Wild_West

Guest
I was actually working exclusively with gm8 and also there I was never able to build a perfect engine. I moved to gms only because of the place_meeting function which I think didn't exist in gm8. But as I said I don't like these functions anymore. They also have the problem that when your speed is bigger than the solid you can fall through a solid (which can be solved but still annoying).
And by the way place_free and place_empty are even more limited and not flexible.
I dunno I guess my game is just too simple, but I can't offer any answers for ya.
 
B

boomie

Guest
Thanks anyway. And by the way you can add complexity to your game in other ways also with a simple engine.
 
W

Wild_West

Guest
Thanks anyway. And by the way you can add complexity to your game in other ways also with a simple engine.
It's just my own spin on any kind of platformer game, using my series as a base.
There's the standard power ups via my character's magic property, changes his look and abilities for a short time, I got a few enemy variations and the monsters can increase their stats to suit what the player chooses to upgrade along th levels.
Other than some environmental hazards that's about all there is to it.
Sad as it sounds all that was over 2 years and I'm still not done lol
 
B

boomie

Guest
Sounds cool. How do you change the monsters' stats according to the player's choices? can you give an example?
 

TheouAegis

Member
placr_meeting has always been in GM.

If you want to get really old school, used collision_point or instance_position or position_meeting. If you don't want to check the entire bounding box at the same time, then check individual points around the bounding box. You only need a minimum of 4 points, on average you would use 6, sometimes 8. Using the entire bounding box for collision checking is faster, although much sloppier.
 
W

Wild_West

Guest
Sounds cool. How do you change the monsters' stats according to the player's choices? can you give an example?
I set a growth rate array then make it increment by 1 every time the player spends points to power up a stat permanently.

Like :

growth_rate[0] = 1;//Hp
growth_rate[1] = 1;//Atk
growth_rate[2] = 1;//Def

and in enemy creation code I do

hp = 100 * player.growth_rate[0];
atk = 50 * player.growth_rate[1];
def = 1 * player.growth_rate[2];

and each time you get enough points to upgrade you just increment the "exp level" by 1.
growth_rate[1] += 1;


so every time the enemies are created on room start they get the stat gains equal to the player's power in said category.

It's fun because you can try to boost like only attack and keep hp and def low and see how well you do lol
 

Mick

Member
I have had problems with this for my upcoming game Thy Sword. The game has a very low resolution (240x135) and the collisions need to be pixel perfect of course, also the game need one way platforms. I finally managed to create a stable system for this, I'll try to explain what I did below. :)

Setting up sprites etc.

(Look at the attached image)
- I set the the origins of all sprites that can stand on platforms to center bottom.
- The platforms have their y-origin set at the top.
- I manually set the width/2 and height of moving objects like player characters and enemies (This way the collision masks and bounding boxes can be different for all sprites used for an object).
- I use place_meeting and instance_place for enemy and hazard collisions only.
- For platform and wall collisions I use certain points and the function instance_position.
- When a moving character is on a platform the gravity is set to zero, only when it's in air it has gravity.
- Everything is drawn at floor(x) and floor(y).

Enemy and hazard collisions

For these collisions I use instance_place, for some sprites I use precise pixel collisions, like I mentioned earlier the bounding boxes can vary from sprite to sprite when using this system.

Wall collisions (horisontal)
For these collision I check the following points when character is moving:
position_meeting(x+sign(hspeed)*(width/2) , y, obj_platform)
position_meeting(x+sign(hspeed)*(width/2) , y-height, obj_platform)

Platform collision (character on platform)
To see if a character still has ground underneath i check:
position_meeting(x+width/2, y+1, obj_platform) || position_meeting(x-width/2, y+1, obj_platform)
If there is no platform under the character, the character is in air and now has a gravity value set to it.

Platform collision (character in air)
Since the platforms are one way I only check for collisions with platforms if vspeed > 0. So if vspeed > 0 I do this:
Code:
var inst_platform = instance_position( x-width/2, y, obj_platform);
  if(inst_platform == noone)
    inst_platform = instance_position( x+width/2, y, obj_platform);
  if( inst_platform != noone )
  { 
      var inst_platform_above = instance_position( x-width/2, yprevious, obj_platform);
      if(inst_platform_above == noone)
        inst_platform_above = instance_position( x+width/2, yprevious, obj_platform);
   
      if( inst_platform != noone && inst_platform_above == noone) {
        y = inst_platform.y;
        vspeed = 0;       
    }
  }
There is no need for complex systems that turn collision masks off for platforms etc. So you see from the code above, I check for platform collisions at feet positions only and if there is no collision at previous y-position the character has landed and now I set it's y-position to the y-position of the platform (platform has y-origin at top) and set gravity to zero.

I hope this helps, until now I haven't found any problems with this system. Some changes are needed if using sloping platfoms of course. There is a demo of Thy Sword available if you want to see how all this works in practice: http://www.gamephase.net/thy-sword/
 

Attachments

Last edited:
B

boomie

Guest
placr_meeting has always been in GM.
So I moved to gms for nothing /=
If you want to get really old school, used collision_point or instance_position or position_meeting. If you don't want to check the entire bounding box at the same time, then check individual points around the bounding box. You only need a minimum of 4 points, on average you would use 6, sometimes 8. Using the entire bounding box for collision checking is faster, although much sloppier.
I don't really get the difference between collision_point and instance_position. Is the only difference that collision_point has more parameters?
Anyway I used only collision_rectangle and collision_line for the player's movement. It makes more sense to me to check the entire area that is one pixel below the player when i check for ground and the entire area which the player is going to cover when I move the player. Are there any advantages for checking single points other than performance?
And what do you mean by using the entire bounding box? Do you mean place_meeting and instance_place?
 
B

boomie

Guest
I have had problems with this for my upcoming game Thy Sword. The game has a very low resolution (240x135) and the collisions need to be pixel perfect of course, also the game need one way platforms. I finally managed to create a stable system for this, I'll try to explain what I did below. :)
Thank you so much for the really detailed answer!
I played your game a bit and it looks awsome so far. I don't really like low res pixel art but I was looking for platformers which have some kind of battle system rather than getting damaged by touching the enemy. I will finish the demo later and tell you what I think.

- I manually set the width/2 and height of moving objects like player characters and enemies (This way the collision masks and bounding boxes can be different for all sprites used for an object).
So you use the height and width for movement and collision with platforms and wall, and the collision masks for interaction with enemies? By the way, isn't collision mask and bounding box the same thing?

- Everything is drawn at floor(x) and floor(y).
What do you mean by everything? Only the things you draw in the draw event, or also the sprites, or maybe you draw the sprites in the draw event?

Wall collisions (horisontal)
For these collision I check the following points when character is moving:
position_meeting(x+sign(hspeed)*(width/2) , y, obj_platform)
position_meeting(x+sign(hspeed)*(width/2) , y-height, obj_platform)

Platform collision (character on platform)
To see if a character still has ground underneath i check:
position_meeting(x+width/2, y+1, obj_platform) || position_meeting(x-width/2, y+1, obj_platform)
If there is no platform under the character, the character is in air and now has a gravity value set to it.
Why do you use position meeting and not collision line? It will probably not cause you problems since you probably don't have any platforms thinner than your characters, but still, it seems more complicated.
 
B

boomie

Guest
I set a growth rate array then make it increment by 1 every time the player spends points to power up a stat permanently.

Like :

growth_rate[0] = 1;//Hp
growth_rate[1] = 1;//Atk
growth_rate[2] = 1;//Def

and in enemy creation code I do

hp = 100 * player.growth_rate[0];
atk = 50 * player.growth_rate[1];
def = 1 * player.growth_rate[2];

and each time you get enough points to upgrade you just increment the "exp level" by 1.
growth_rate[1] += 1;


so every time the enemies are created on room start they get the stat gains equal to the player's power in said category.

It's fun because you can try to boost like only attack and keep hp and def low and see how well you do lol
So when the player upgrades a stat the enemies also upgrade the same stat?
 

TheouAegis

Member
So I moved to gms for nothing /=

I don't really get the difference between collision_point and instance_position. Is the only difference that collision_point has more parameters?
Anyway I used only collision_rectangle and collision_line for the player's movement. It makes more sense to me to check the entire area that is one pixel below the player when i check for ground and the entire area which the player is going to cover when I move the player. Are there any advantages for checking single points other than performance?
And what do you mean by using the entire bounding box? Do you mean place_meeting and instance_place?
Yes, place_meeeting/instance_place use the entire bounding box. It's a fast collision algorithm, but it has its drawbacks if not used correctly. And of course, the biggest issue with them is that they check the whole bounding box, which makes little sense in many cases. If you want the instance to be able to walk through a low ceiling (like in many old video games) but you want a bullet to hit it in the head, then you'd need to constantly toggle the player's collision mask every step and check for the collisions yourself rather than using the built-in collision events. Or use a point-based collision system, in which case the issue becomes moot.

collision_line() is fine for ground collision, but I did have one issue with it that right now I can't remember (I think I fixed it, but it gave me some headaches for a while). If you'd check one foot for ground underneath and then check the other foot if there was no ground detected, then it does make sense to check along a line and just find any ground under either feet at the same time. However, you don't need to check along the whole line. In a collision_line called between (x1,y) and (x2,y) where x1 is behind the player and x2 is in front of the player, then as long as abs(x1-x2) is less than or equal to the width of your ground, checking just the point (x1,y) will suffice if there is ground there, then check (x2,y) only if there isn't.

You can do the same with overhead to prevent jumping into ceilings, or you can just use the point directly over the instance's head and allow some wall overlap and trust the other collision functions from preventing getting stuck in the ceiling (this is a tricky scenario, though).

The rule for the feet applies to the direction of travel. You don't care about collisions behind the instance, so you only need to check in front. You can use collision_line unless you wanted to code something like the enemies in Castlevania which would walk through low ceilings (except the axe knight, who turned around) but turn around at walls. If you use a line collision from (x,y1) to (x,y2) where y1 is at the head and y2 is at the feet, how would you know if there is a wall or a low ceiling? You couldn't - you'd only know there was an obstruction between those heights. So long as abs(y1-y2) is less than or equal to the height of your ground, then you'd only need to check the points (x,y1) and (x,y2) directly. If the enemy can walk through low ceilings but always turns around at obstacles near its feet (the skeleton in Castlevania), then you only need to check (x,y2). If the enemy can jump over an obstacle near its feet but not if there's a wall, then you'd check both (x,y1) and (x,y2). If the enemy turns around at either obstacles near its feet or low ceilings (like the axe armor), then you only need to check (x,y1) if there is no collision at (x,y2).
 
W

Wild_West

Guest
So when the player upgrades a stat the enemies also upgrade the same stat?
Yep, helps for replayng old levels too since I figured eventually the player's stats would be so high the enemies would get completely owned lol but if I made them too strong right off the bat it'd be too hard maybe. So this is a nice balance for that

This wouldn't apply to you if you used this, but my only issue is my player also has an energy limt for how many times he can shoot before running out, as well as a magic attack power for when he's changing nature powers, (fire, water, earth and air) and my enemies only have the physical atk def and hp stats. So I need to think how to stop the player upgrading his magic stat to a point where he can fireball everything too easily by choosing to upgrade only magic or energy supply lol
 
Last edited by a moderator:

Mick

Member
I played your game a bit and it looks awsome so far. I don't really like low res pixel art but I was looking for platformers which have some kind of battle system rather than getting damaged by touching the enemy. I will finish the demo later and tell you what I think.
Thanks! Feedback from fellow developers is always welcome! Just ask if you need to know anything a bout the battle system but in short there are different invisible objects for different collisions, the weapons have their own, also there is one object in fron of character when blocking also, if the weapon of the enemy hits that then the attack is blocked. The collision masks for the player and character sprites are used for taking damage so the one for the player can be made as small enough so it's generous for the player and the collision masks for the enemies can be generous on the bigger side.

So you use the height and width for movement and collision with platforms and wall, and the collision masks for interaction with enemies? By the way, isn't collision mask and bounding box the same thing?
If you use a rectangle for the collision mask then bounding box and collision mask is the same, but if you have precise collision detection or ellipse then they are different, the bounding box defines in what area of the sprite the collision mask should be created so to speak.

What do you mean by everything? Only the things you draw in the draw event, or also the sprites, or maybe you draw the sprites in the draw event?
I just mean that any objects that can have coordinates with decimals is drawn to floor x and y, so for a lot of objects there is just a
draw_sprite( sprite_index, -1, floor(x), floor(y) ) in the draw event. Drawing stuff to decimal coordinates in a low resolution game creates distorted graphics.

Why do you use position meeting and not collision line? It will probably not cause you problems since you probably don't have any platforms thinner than your characters, but still, it seems more complicated.
Good point! :) I notice that for the player characters I'm still using instance_place for wall collisions (old code) so it's working because of that, also the only walls are at the edge of the screen. I will consider changing these to collision_line (the wall one at least).
 
B

boomie

Guest
The rule for the feet applies to the direction of travel. You don't care about collisions behind the instance, so you only need to check in front. You can use collision_line unless you wanted to code something like the enemies in Castlevania which would walk through low ceilings (except the axe knight, who turned around) but turn around at walls. If you use a line collision from (x,y1) to (x,y2) where y1 is at the head and y2 is at the feet, how would you know if there is a wall or a low ceiling? You couldn't - you'd only know there was an obstruction between those heights. So long as abs(y1-y2) is less than or equal to the height of your ground, then you'd only need to check the points (x,y1) and (x,y2) directly. If the enemy can walk through low ceilings but always turns around at obstacles near its feet (the skeleton in Castlevania), then you only need to check (x,y2). If the enemy can jump over an obstacle near its feet but not if there's a wall, then you'd check both (x,y1) and (x,y2). If the enemy turns around at either obstacles near its feet or low ceilings (like the axe armor), then you only need to check (x,y1) if there is no collision at (x,y2).
If I understood the mechanic you talk about (I didn't play castlevania) you can still use collision_line for that, but you should change the height of the top and bottom points of the line. If you want the enemy not to turn at low ceilings you'll lower the top point, and if you want the enemy not to turn at obstacles you'll raise the bottom point.

And I do want to use it for characters whose width is bigger than the ground's, and characters who are taller than the walls, so I think collision line is the best option
 

TheouAegis

Member
When the enemy turns around at any obstacle in front, you can use collision_line, yeah. The enemies I actually had in mind when I was writing that up (but obviously messed up on the wording) were the enemies that hopped over a low wall but turn around at high walls. With collision_line, you wouldn't know what kind of wall is obstructing the enemy.

And when I was talking about the distance between two points, I meant the distance between x1 and x2 is less than or equal to the width of the ground and the distance between y1 and y2 is less than or equal to the height of the ground. Rarely in a lot of old games is the bounding box the full width and height of the sprite. When checking in front of the instance for walls, you rarely need to check the full height of the instance. Often times, checking half the height of the ground up from the bottom of the instance and then the full height of the ground up from there will suffice.

I'm not dissing on collision_line, since it cured a lot of the headaches I got trying to work with GM's other collision handling. But understanding how to properly collide with points is almost necessary if you ever want to move away from an object-based collision system. I know that's not your case, but I mention it to every body.
 
Top