Game Development Community

We need an onCollision() callback thats called BEFORE rendering

by Vern Jensen · in Torque Game Builder · 09/12/2006 (1:18 pm) · 8 replies

I've been messing with a project based on the Mini Platform Tutorial for the last 4 or so days, and have come to the conclusion that we need a second onCollision() callback.

This callback would be different from the current one in two ways:

1) It would be called *before* anything is rendered to the screen in its current location, giving the user in the onCollision() callback a chance to change the location of objects that were colliding so they are no longer colliding, before anything gets rendered to the screen.

If you try to make a callback that does something similar to CLAMP right now, your sprite will vibrate constantly, as it's moved into the tile, then moved out by the callback. This happens visually on the screen, because the callback is called *after* the sprite is drawn in its new location that causes the collision. We need the ability to duplicate what the engine does behind the scenes for something like CLAMP (which has NO vibrating), so we can modify that funcionality further to meet our game's specific needs.

Why? Well, not all tiles should be "solid" in the same way. Some might allow the player to walk through them or jump up through them, but not fall down through them. So they act solid in certain situations and not others. The user could program these special cases into an onCollision() callback that duplicates the CLAMP style functionality, plus has extra special cases, but currently if you do this, you end up with a vibrating sprite, as it constantly moves in and out of the tile slightly each frame.

2) We should be able to call functions from within our onCollision() callback that duplicate the functionality of CLAMP, BOUNCE, STICKY, etc. That way, it's easy to write conditional code that invokes this behavior in certain situations, and not in others.

I'd love to hear if this will make it into the engine. I can wait a few months before working on my platform game, and if these features will end up in the engine, it would mean I could use the current Mini Platformer Tutorial method to do my game. If not, I'll have to basically reinvent the wheel, turning off Torque's collision stuff entirely and writing my own all by hand, since currently, Torque provides no way to have conditional collisions -- i.e. invoke CLAMP in certain cases and not others for the same two objects. And this functionality is absolutely necessary in a platformer game.

BTW, if you aren't convinced that Torque needs this, then I challenge *anyone* to modify the Mini Platformer Tutorial to allow tiles that behave as solid floors if you're falling, but otherwise allow the player to walk through them and jump through them. It's impossible currently if you want to use the Torque physics/collision engine, if you don't want vibrating characters.

#1
09/12/2006 (1:30 pm)
Oh yeah, here's another scenario where my suggestion above would be essential. Has anyone here played Zelda 2 for the original Nintendo? It was a 2D platformer game, and when Link jumped and hit the ceiling, he would "glide" along the ceiling until his jump time had expired, then he'd fall to the floor. Currently in Torque, the ONLY option when you hit a tile is to have your sprite's velocity reset to 0 for you. This happens automatically when using the CLAMP functionality. There is no way around it.

But if we could do our own onCollision() callback that did our own CLAMP-style funcionality, but in whatever custom way we needed to suit our needs, we could handle situations like this.

The problem is that currently, we can't duplicate CLAMP in onCollision() because this callback is called after the current frame is rendered that had the collision, so if we fix the sprite's position so they're not colliding, we get vibrating.
#2
09/12/2006 (2:48 pm)
You can do what ever you want.

Set the default Collision option to None and use the onCollision call back to do what ever you want.

To "fix" you vibrating problem the only other thing I could think of would be to do a cast collision when the scene updates but I'm not sure of the overhead (especially if you did it for a lot of objects.)

Jumping "through" floors has been another thing that people on the message boards have been trying to do for a fairly long time. Doing things like this really does mean you have to make the default collision handle None. The way I have been thinking about trying to do one way platforms is to set the collisions to none, then when you collide with a platform you get the vector and find out if the play is below the object. If it is then you store the object the player collided with in an array or group. The next time the scene updates, if your player is colliding with the object still you ignore it, if the player isn't colliding with the object you clear it out of the group / array. I haven't tested it at all but thinking about it sounds like a good idea.

In the tutorial I have been working on I have been playing around with ways to get around various platformer issues that are player related (which is one of the reasons the 2nd Core tutorial hasn't been released yet). It's still a toss up wether or not I am going to custom handle collisions, but either way the mini platform tutorial does have a number of down sides. The original Platform tutorial which was all script based IMO handles things a little better.

When I get the player functions planned out a bit better and do some testing on some things I'll try and share what I find. It doesn't really seem all that hard BUT thing snever work the way they should :-P
#3
09/12/2006 (3:09 pm)
BTW, it's not impossible at all. Do a castCollision before all of your movement, and turn collision on/off based on the result and your gameplay scenario.
#4
09/12/2006 (3:15 pm)
@Glenn
RE: One way platforms
There are currently 2 solutions for this.
Core Code change = here
Script only = here

They might give you some ideas to start on your solution, or they might solve your problem...
#5
09/12/2006 (3:29 pm)
Yeah, I saw those resources. The only problem with those two are firstly, I don't really want to modify the code, specially for the tutorial. The second one is a really painfull way to do one way platforms if you want ALL your platforms one way (aka contra). They are both handy ways to do it though. The other way I thought about doing it was having any one way tiles with a added script call. In the end though, it would be a lot better if the game handled one way platforms without any extra work for each tile, and I can't see it being a big issue to do it that way.

I'm rambling now, but basicly it's a thanks for the heads up :-P
#6
09/13/2006 (1:00 pm)
Thanks for the replies guys. Regarding the suggestions:

1) Modify the source code

I'd rather not. Like Glenn, I'm looking for a script-only solution. Something to handle one-way platforms *needs* to be built-in to Torque if it really is going to be the best 2D engine ever. You shouldn't have to modify it to get basic 2D game functionality.

2) Use triggers

That won't work for moving platforms, such as the wood beams that Mario jumps on in Mario 3, or falling platforms -- the ones you can ride down. These all work in a way that you can move through them left/right/up, but you hit them if you're falling down. In addition, you need to "know" you're on the platform, so it affects the velocity of whatever is riding on it.

Triggers, as far as I know, are locked to a specific location, so they wouldn't be practical for something that's moving around.

3) Do castCollision before all movement.

That won't work. Sounds like it would on the surface, but when you try to do it, you realize that castCollision does not provide you with all of the information that the onCollision() callback does. Specifically, it does not give you the row and column of the tile you collided with as on Collision does. This makes it next to impossible to get information about that tile (what kind of a tile is this? A wall? A platform? Something else?) and react to it appropriately. Been here, tried it, didn't work.

I still stand by my suggestion to have either a 2nd onCollision() callback, or a function we can call, like setOnCollisionTime( beforeRendering ) that allows us to get the collision callback to be called before rendering occurs, so we can "fix" any collisions by repositioning sprites, before they are drawn in their colliding locations, thereby avoiding the vibrating I mentioned in my first post. This *would* solve the problem, and would do it cleanly, and you wouldn't have to do lots of castCollision calls.

It just requires the addition of something to the engine... how about it guys?

If this is something people on the boards have been trying to do for months, and all the "solutions" so far either inadequate (triggers) or require code changes to the engine (and check the other thread... it seems like a potentially inadequate solution as well), isn't it time to add some new functionality to the engine to handle this?

It seems that a simple callback that's called before rendering takes place would be the cleanest, easiest, simplest way. (In addition to a function we could call from within that callback that would perform the CLAMP collision if we want it to, but WE have the choice of calling this function or not.)
#7
09/13/2006 (2:52 pm)
Vern,

The very first "number" returned by castCollision is the object ID. I can't see any reason why you can't then use that object ID to get other information about the thing you collided with including, but not limited to, the X/Y coord, graphGroup, class etc.

Thinking about this more and more it looks like the way I am going to handle it is via custom collision code, specifically setting most collision default responses to none, testing what the player is colliding with, what his current movements are and reseting them as nessesary. I guess the other "method" is setting most collision default responses to none and using cast collision to see where the player is, but that seems to be a little more overhead then I would like.
#8
09/13/2006 (4:55 pm)
Glenn,

When it comes to Tile Maps, the Object ID returned is of the *tile Layer*. This is because all tiles in a layer are one giant object. Each individual tile is not its own object... they're part of one big one, the layer. You still need to know the row and column of the tile within the layer if you want to get information about that tile. Otherwise, all you know is, "My sprite collided with some tile in this layer", which is obviously pretty unhelpful.

As I mentioned before, the onCollision() callback DOES pass you the tile row and column, but the castCollision method does not.

I feel that I've already tinkered with this thing to death and exhausted my options. I welcome you to try to implement what you're thinking of doing. It's one thing to have an idea, but it's another to try it, and then run into problems you didn't anticipate. My guess is that after you've toyed with it enough, you'll come to the same conclusion as me... that we need some simple additions to the Torque engine in order to be able to handle basic 2D platforms, unless we want to write *everything* from scratch. (That is, code to manually move sprites each frame, check for collisions manually, and fix their positions manually.... the collision/physics that Torque provides would be "turned off". This is the ONLY option I see right now for handling both static and moving platforms in a 2D platformer.)