Not logged inGosu Forums
Forum back to Help Search Register Login
Up Topic Gosu / Gosu Exchange / 2D platform collisions in non-tile-based game
- - By allcaps Date 2013-08-12 19:12 Edited 2013-08-12 21:14
I'm at a junction where I need to decide if I want to use Chipmunk or Chingu, or go all-in on figuring out a custom 2D collision system.  You can see what I have so far at github:

God Must Answer

I need the usual platformer stuff.  Need to know when I'm grounded, walk smoothly between blocks with different bounding boxes, need to be able to stop the player from jumping up through a platform, or jumping into the side of one.  For the game's purpose I'll also need to know when I'm touching the bottom or side of another block, not just that I've hit another block, detecting what edge I've collided with is important.

I've rolled my own Vector2 and Box2D classes, and I'm using those to do the thing.  So far they calculate the bounding boxes based on the gameobject's graphics, though for the game's purpose that will work fine.  Only the player will need a custom bounding box, and that'll be easy enough to specify and tweak manually.

I've got platform grounding working pretty well.  Can walk along multiple platforms that don't quite touch without sinking down for falling between by using two "feet" points on the box.  This is working pretty well, but I'm not sure if I want to go all-in on rolling my own methods for checking other types of collision.  I'm also having an odd issue where the bottom box of the player sinks into the other collider one or two pixels before collision happens.

There will be no other gameobjects checking collision, just the player.  There will be no bullets, though there will be moving colliders to contend with, including platforms the player will need to "stand" on and move along with.
Parent - - By allcaps Date 2013-08-13 01:52
Tried to make some progress on it, but still facing some issues.  In particular I'd like someone who has done this before to look at ball.rb, box2d.rb and tell me what I'm done wrong.  I'm running into a couple issues.

-My box "lags" behind the graphics when they're moving, I'm rendering the graphics at the box's origin (it's top left vertex) and movement methods move the box, so I don't know why this is happening.  The location the box uses to render its debug lines and the location the graphics render should always bee the same at any given time.  Unless I've spaghetti'd somewhere and don't see it.
-My box must sink into another box by a pixel before collision registers.  I have a gravity method that applies a one-pixel downward force on the ball, checks to see if it's grounded, then does it again a certain number of times each update step.  The ball's bounding box always sinks one pixel lower than the platform's origin before it stops.

I'm guessing these two issues are related to a core issue, but I'm a little lost on how to fix it.
Parent - By ml Date 2013-08-13 03:48
Looks like you're making solid progress on a large project. As a bonus, I was able to load it on the first try.

I am not too experienced with collision detection - or programming in general - otherwise I would provide a bunch of suggestions.

You've probably already checked out CptnRuby, but I'll mention it, just in case you haven't... It is a tile-based platformer, while yours in non-tile-based, but it deals with gravity and collisions, and might be worth taking a look if you haven't already done so.

The original version by jlnr can be found inside the Gosu gemfile on your hard drive, along with the other Gosu examples. CptnRuby with Walljump, by Maverick, can be found at this URL:
Credit goes to Dahrkael for providing the link, and to Maverick for adding Walljump, and to jlnr for creating the original.

Other than that, your questions are mostly beyond my experience level, and I hesitate to say anything because I'll probably be wrong...... That being said, I wonder if part of the reason the ball sinks 1 pixel into the box before stopping is because the box in ball.rb - def generate_box - extends one pixel beyond the dimensions of the ball itself...
Parent - - By allcaps Date 2013-08-13 04:19 Edited 2013-08-13 04:42
I'm very glad to hear it ran on the first try!  My least favorite part of using Ruby is how it's always a gamble if your code is going to work for someone else as it does for you.  It sometimes makes me want to go back to Java. (Sometimes.)

I think I've solved/worked around the issue by just making the bounding boxes one pixel bigger than the graphics, so that if the box is one pixel in the other box, the graphics will be setting on  top of each other perfectly.  If nothing else I'll call it good enough until it proves to not be good enough.  In any case it means I can work on other, more fun parts. 

I'm actually really proud of the level editor.  Gosu::Images don't Marshal well (and by not well I mean at all) so you can't directly marshal an array of gameobjects.  So instead I gather only the information needed to recreate the gameobject, and store that info in an editorobject, which contains nothing but strings and vector2s, which marshal fine.  Then when loading the .map (which is an array of these editorobjects) the gamestate can recreate the objects array I wanted using that info.  It works perfectly.
Parent - - By ml Date 2013-08-13 05:18
Sounds pretty sophisticated. I'm trying to figure out how to look at your .map files. In a text editor, they just look encoded.

Ruby is the first programming language I've ever experimented with, so pretty much everything is new to me.
Parent - - By allcaps Date 2013-08-13 05:29
The .map files are Marshal'd blobs.  Each one contains an array of EditorObjects.  Each editor object is very simple, just two variables, "type" and "origin".  Type is just a string, like "block", or "door".  Origin is a Vector2, which is a type I created/implimented myself, it's also very simple, just two integers, an X and a Y.  With those two pieces of info, I can recreate the level using the "load" method in the gamestate.rb class.  It sounds like I'm splitting the atom I'm sure, but it's really simple.  Elegant almost.

Marshal produces files that aren't readable outside of being de-Marshal'ed by Ruby.

In general you'll want to create your own save format if you have special needs, but for simple things Marshal works very well.
Parent - By ml Date 2013-08-24 09:50 Edited 2013-08-24 10:12
Thank you. This information is highly useful for me.

btw, I just checked out the latest version on github. Looks like it's coming along.
Parent - - By lol_o2 Date 2013-08-13 08:51
If you don't store Images inside objects, but somewhere globally and then only refer to them, you can simply dump whole gamestates.

And to make bounding boxes not to sink, you can move them temporary by one pixel while checking collision.
Parent - - By allcaps Date 2013-08-13 18:14
I think I like the object re-creation approach more.  This way if I change the way a particular object works (such as making a block wider, or making spikes taller, or changing the way somethings box works) that change will be reflected when the gamestate generates the level.  If I just dumped the state, the objects would be in the state they were in when they were dumped, so I'd have to re-create the level to see the updated objects, or more likely just crash if I'd refactored something major.  This also helps because objects will be created with their "game" variable correctly referencing the gamestate that loaded the map, and they'll be placed into the state-wide @objects array for access by other objects.  Also sidesteps having to use globals, or an image manger/dispatch class to hold graphics.
Parent - By lol_o2 Date 2013-08-13 19:30
I meant that dumping gamestate may be used to create a checkpoint or suspend playing session.
Dumping actual objects in levels I used only once. It's not so bad solution, because there's less work to define new objects. Normally you have to make this object display in editor and initialize proper class while loading map. When you use only the classes, they appear in editor as in game and are pushed into state's objects automatically. But trouble is when you want to change their variables. Anyway, I don't recommend it either.

Global resource storage is good idea as the resources are easy to access and they are loaded only once, so map loads faster and game uses less memory.
Parent - By jlnr (dev) Date 2013-08-14 10:48
I would suggest not using a physics engine for a platformer, mostly because it's fun to roll your own algorithms and it's no fun to bend a complex engine to do exactly what you want.

What I did to handle uneven grounds was basically this: I'd move objects one pixel left or right (if possible), then move them up by 5 pixels or so, and then move them down as far as possible, but at most 10 pixels. That way they could climb slopes and would stick to the ground when moving down a slope, instead of displaying a "falling down" animation.
Up Topic Gosu / Gosu Exchange / 2D platform collisions in non-tile-based game

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill