Walls & Ceilings Collisions Disaster

23 posts (showing 1-20)
Arnas

Market Level 0Community Level 2
144 posts

Okay, so my game involves raising the speed skill for your character. The higher the speed skill, the higher the speed.

This is a tile based game.

To detect collisions with walls and ceilings, I use the while instead of if because they are significantly stronger against higher speeds. I use if only for floor collisions.

The Problem: It seems that my code has a limit to how many whiles can be run, apparently. Only so much of them can run at the same time, so I separated all the right and left collisions based on which arrow key is pressed.

That's fine and all, but I can't separate them from top collisions because you actually have to move and jump at the same time!

I have reduced the amount of tiles as much as I can. I'll show you my code in an image format.

If I swap the ordering around, they will behave differently. Right collisions have top priority right now and top collisions have low priority, therefore the character glitches through the ceiling. It seems like the while statements just die down the less priority they have. Right and Left collisions actually switch places depending on the key pressed. I can't do this for the top collisions too because you need to jump and move at the same time.

Note: The collisions seem fine at slower speeds, but at faster speeds they get really messy! If your jump power is 14 it's absolutely fine, but once it hits 31, it starts to get glitchy.

What do I do?

posted 2015-06-17T15:36:32-07:00 | edited 2015-06-17T15:38:23-07:00
danishgoel

Market Level 5Community Level 6
545 posts

Arnas said:

Okay, so my game involves raising the speed skill for your character. The higher the speed skill, the higher the speed.

This is a tile based game.

......

Note: The collisions seem fine at slower speeds, but at faster speeds they get really messy! If your jump power is 14 it's absolutely fine, but once it hits 31, it starts to get glitchy.

What do I do?

With this approach you will always get tunneling.
In my very first flash game, I faced the same issue with bullets passing through stuff.

Only 100% accurate way is to use continuous collision detection. Everything else will just be trying to push the problem away for now.

One possibility would be to use a fixed frame-rate approach, in which you only advance the time by a set amount every frame. And if the frame-rate drops everything moves in slow motion. This ensures that every frame will not exceed the time threshold, which is what normally happens with performance going down.

Another one would be to use a fixed-time-step approach. Which is better at handling fluctuations in frame rate. In this the main loop accumulates the frame time, and only runs the physics logic after a set frame time is accumulated.
My suggestion would be this approach, with accurate tolerances for jumps. That is, make sure that at the highest speed the character cannot completely pass through a tile in one time step.

A possible, rough implementation of this approach in AS3 (I don't remember AS2 well enough :P)

[as3]
var timeAccumulator:Number = 0;
var lastTime:int = getTimer();

stage.addEventListener(Event.ENTER_FRAME, onFrame);

function onFrame(e:Event):void {
    // get current time
    var currTime:int = getTimer();
    // add the frame time to accumulator
    timeAccumulator = (currTime - lastTime)/1000;
    // set last time for next loop
    lastTime = currTime;
    
    // only handle upto N frame loops per frame discard rest.
    // This avoids lockups due to slowdown
    var n:int = Math.min(N, Math.floor(timeAccumulator / TIME_STEP));
    
    // Run "n" game loops. Note: no game loop will run if n = 0
    for(var i:uint = 0; i < n; i++) mainLoop(TIME_STEP);
    
    // retain the fractional part of the TIME_STEP in accumulator
    timeAccumulator %= FRAME_TIME;
}

function mainLoop(dt:Number):void {
    // All game Logic
    ......
}[/as3]

The most accurate would be writing a continuous collision detection code for the game, which is definitely not trivial. I would advise against it unless you are trying to do this for educational purposes. If you go this route, we would love to hear about it ;)

The best way would be to use a Physics Engine! This alone will justify transitioning to AS3.
But since you asked to do this with AS2, above are the options I can see. Best of Luck!

posted 2015-06-17T17:10:05-07:00 | edited 2015-06-17T17:13:09-07:00
OceanBreezeGames

Market Level 7Community Level 2
119 posts

Many years ago I read this article:

http://www.metanetsoftware.com/technique/tutorialA.html

This goes into a lot of good stuff and if  you take your time and go through it you'll really get a handle on how to do your own collision detection... Well it really made me understand it.

The article is made buy the guys that made: http://www.thewayoftheninja.org/nv2.html

Might be overkill for what you want to do though, stepping through at fixed increments might be quicker to implement as explained above.

posted 2015-06-17T17:38:37-07:00 | edited 2015-06-17T17:51:39-07:00
Arnas

Market Level 0Community Level 2
144 posts

danishgoel said:

--------------------------

The two methods that you talk about, are they both continuous collision methods that you advised against? I tried the game with frame rate as low as 10 but the results were the same, so I don't think it's a lag issue. I think there's something wrong with the whiles.

I'll be honest, I don't really understand the code you provided, possibly because I have never used AS3 before, and my program that I use doesn't support AS3 either. Perhaps someone here knows the AS2 version of this method?

Physics Engine would be amazing, I'll have to check if one exists for AS2. Is this really the only way? Did you manage to fix your bullet collision problem on AS2 or did this happen with AS3?

@OceanBreezeGames I remember this website. I paid little attention to it after reading some, but I'll read more deeper into it when I wake up. Hopefully this supports AS2

Thanks guys, I'm really hoping to see more answers after I wake up.

posted 2015-06-17T19:27:09-07:00
bluebox

Market Level 6Community Level 3
334 posts

oh sweet jesus what a piece of... code :D

hitTest is so slow that you schouldnt use it, but if you have to - limit your objects. Make pre-test of your tiles in given range - speed/frame - then you can guess which will be hited - no need to make hittest to be honest at all.

posted 2015-06-17T22:49:27-07:00
danishgoel

Market Level 5Community Level 6
545 posts

@Arnas

The two methods suggested in my post are NOT continuous collision detection. Those are discrete step methods. The second of those, fixed-time-step method can be adjusted as desired to account for smaller tile sizes (provided the computer can keep up with the load).

You need to first understand why the collisions are glitching.

The programming construct used, be it while or if, does not matter too much. In many programming languages, compilers do what is known as loop unrolling, which converts small while/for loops to series of sequential statements, since they can be faster!

So what is the real cause of these glitches? It is tunneling, i.e. object completely passing through another within a single time-step. This way the actual collision is never detected.

In above figure. T=0, and T=1 represent two consecutive frames or time-steps.

Case 1, the object moves but does not completely pass the wall in single time-step, and thus is properly detected in our tests.
Case 2 is the glitching one. Here the object is moving fast enough and thus completely passes the wall in single time-step. This way the object is not hitting the wall in either of the time-steps. Voila! Tunneling.

As shown above, larger the time difference between two tests, greater the chance of tunneling.

This is exactly what happens by reducing the frame-rate.
At 60fps, each frame is ~16ms, but at 10fps each frame is 100ms long! This increase in time step causes the glitches.

So, frame-rate reduction, be it due to lag or intentional will cause this issue. Only sure way to avoid this is to decouple your physics from frame-rate, and use a fixed time step approach.

The link provided by OceanBreezeGames explains the intricacies of collisions well. In section 5, it talks of fast moving objects, and alludes to 2 methods: sweep test (proper continuous collision) and multi-sampling (approximated approach). Code provided in my posts above is close to multi-sampling.

Best of luck!

posted 2015-06-18T06:16:43-07:00
Arnas

Market Level 0Community Level 2
144 posts

@danishgoel

I ran it at 60fps earlier and the result was still the same as 10fps, so it might be something else for me. The code also works fine when it's on it's own but when there are other codes working at the time, it seems to respond less, especially to higher speeds.

I just tried moving it to an enterFrame of it's own, but the same result happened. I guess if I made the collisions not hitTest as @bluebox suggested (Math?) then the results would improve.

I'll also try prediction collisions to see if that fixes anything, although this might drop performance.

I know that tunneling is the issue here, but the main problem I'm facing right now is that not all codes that prevent tunneling work at the same time as intended.

Thanks for the help so far, guys. Hopefully I'll find an unquestionable solution.

posted 2015-06-18T14:20:33-07:00 | edited 2015-06-18T14:22:08-07:00
bluebox

Market Level 6Community Level 3
334 posts

what I see:

myNextX=Mc.x+Mc.speed;

function searchForTiles(){'seeking tiles with X greater than my X but less than myNextX in short loop'}

DONE.

posted 2015-06-18T21:47:09-07:00
Arnas

Market Level 0Community Level 2
144 posts

bluebox said:

what I see:

myNextX=Mc.x+Mc.speed;

function searchForTiles(){'seeking tiles with X greater than my X but less than myNextX in short loop'}

DONE.

Hmm.. another nice method to add to my 'to try' list. Although, I would really appreciate it if you could write the code in full, due to my obsession with not wanting to make mistakes. If you can't, no worries, I'll experiment.

posted 2015-06-18T22:33:23-07:00
FGL_Porter

FGL AdminCommunity Level 16
427 posts

There are many approaches to fixing this, including some above. I didn't read them all, but here are two of mine:

Use Raycasting, that might be a bit advanced, but it works great. This will essentially shoot a ray in the direction you're traveling, and if you have a collision, you move up against the object you would go though.

Another solution, is to simply do incremental movement checks before you actually finalize the move. For instance, if you're moving at 80 speed, and that would move you 2.5 tiles over, you would recursively check each step up until that final distance. If your tile width is 32, it would be 31 per movement, because you don't want to move a full tile, or you can be up against one, and pass through. So if you're approaching a wall, and it's 1 tile thick, you would check currentX + 31 (tileSize - 1), and keep doing that until your "checked total" is greater than or equal to the total desired distance traveled. If you have a collision, move up against that object, if you don't, move the full desired distance.

posted 2015-06-19T06:27:09-07:00
Arnas

Market Level 0Community Level 2
144 posts

On Jun 19, 2015, FGL_Porter said:

There are many approaches to fixing this, including some above. I didn't read them all, but here are two of mine:

Use Raycasting, that might be a bit advanced, but it works great. This will essentially shoot a ray in the direction you're traveling, and if you have a collision, you move up against the object you would go though.

Another solution, is to simply do incremental movement checks before you actually finalize the move. For instance, if you're moving at 80 speed, and that would move you 2.5 tiles over, you would recursively check each step up until that final distance. If your tile width is 32, it would be 31 per movement, because you don't want to move a full tile, or you can be up against one, and pass through. So if you're approaching a wall, and it's 1 tile thick, you would check currentX + 31 (tileSize - 1), and keep doing that until your "checked total" is greater than or equal to the total desired distance traveled. If you have a collision, move up against that object, if you don't, move the full desired distance.

I wrote down your suggestions. Thanks

posted 2015-06-20T19:34:15-07:00
Arnas

Market Level 0Community Level 2
144 posts

I'm not sure if double posting is against the rules in this forum, I apologise in advance.

I just figured out the main problem. The whiles work just fine.

What happens is that my left and right colliders go inside the same block that the top collider is meant to collide with. Meaning that if you jump too deep inside the block, the right and left colliders get affected too! Which means that I have to somehow move the right and left colliders down, or shrink their height.

That doesn't seem to be a very good solution, though. It's just running away from the problem. Any ideas how I could do that? Certain people might suggest removing left and right collisions while you are jumping, but you have to move and jump at the same time, therefore it doesn't solve the issue.

Help would be very appreciated.

posted 2015-06-23T18:22:30-07:00
FGL_Porter

FGL AdminCommunity Level 16
427 posts

While I totally recommend diving into these issues head first to understand them, have you looked into Flashpunk or Flixel? Both handle this kind of collision out of the box, and use pretty standard (and very solid) solutions. You could try digging through their implementation to further understand the issue, or even consider using either framework as they're both quite great! (I've used both)

posted 2015-06-23T18:56:00-07:00
FGL_Dave

FGL AdminCommunity Level 4
319 posts

Programming 101: Don't (unnecessarily) reinvent the wheel :)

posted 2015-06-23T21:23:21-07:00
RTLShadow

Market Level 1Community Level 2
140 posts

I would also suggest that you load all those instances in your loop into an array and loop through that. Dear Lord. Not sure if anyone has suggested that yet- I didn't see it mentioned.

posted 2015-06-26T07:44:55-07:00
pepperpunk

Market Level 3Community Level 11
2401 posts

Not sure what is going on with the code, but it could really benefit from tidying up with arrays and for loops unless you really want to copy and paste every block object in every level into the hit-test code four times.

posted 2015-06-26T19:00:47-07:00
Arnas

Market Level 0Community Level 2
144 posts

pepperpunk said:

Not sure what is going on with the code, but it could really benefit from tidying up with arrays and for loops unless you really want to copy and paste every block object in every level into the hit-test code four times.

What if I just group it all into one function?

@Dave, I'm not exactly sure what you mean. Using an existing provided code?

posted 2015-06-27T03:20:05-07:00 | edited 2015-06-27T03:22:04-07:00
keybol

Market Level 9Community Level 13
2990 posts

On Jun 24, 2015, FGL_Dave said:

Programming 101: Don't (unnecessarily) reinvent the wheel :)

Yes he means use existing engines. It's ok to learn about it to understand the concepts but to perfect it, would be time consuming. 

posted 2015-06-27T04:27:37-07:00
FGL_Dave

FGL AdminCommunity Level 4
319 posts

Absolutely what Keybol said. In addition, in the beginning stages it can be offputting to get trapped in the doldrums of doing all this kind of basic collision stuff - you just want to get on and make a game!

Later on, once you have a better understanding of the higher level concepts involved, you can dig down and start learning how the deeper stuff works (and eventually you'll maybe make your own engines!).

There's no shame in that either, AAA games companies use other people's engines also. It's rare these days that you really _need_ to have knowledge or experience of building that kind of thing from the ground up. In fact, I tend to find that the best games are made by those who have spent their time learning about the finer points of making a game, rather than learning how to make the perfect collision testing algorithm (which someone, somewhere has already done and made available for you to use for free in all likelihood) :)

posted 2015-06-27T04:37:01-07:00
Arnas

Market Level 0Community Level 2
144 posts

FGL_Dave said:

Absolutely what Keybol said. In addition, in the beginning stages it can be offputting to get trapped in the doldrums of doing all this kind of basic collision stuff - you just want to get on and make a game!

Later on, once you have a better understanding of the higher level concepts involved, you can dig down and start learning how the deeper stuff works (and eventually you'll maybe make your own engines!).

There's no shame in that either, AAA games companies use other people's engines also. It's rare these days that you really _need_ to have knowledge or experience of building that kind of thing from the ground up. In fact, I tend to find that the best games are made by those who have spent their time learning about the finer points of making a game, rather than learning how to make the perfect collision testing algorithm (which someone, somewhere has already done and made available for you to use for free in all likelihood) :)

I understand. Although there's a little bit of a difference involved. Every time I looked up a physics engine, a lot of them didn't cover really high speed stuff, only the basics, and even so, my program only supports AS2 and there's not many engines on that, or do you happen to know any good ones for AS2? Thanks in advance

posted 2015-06-27T05:20:53-07:00