HaxeFlixel / flixel

Free, cross-platform 2D game engine powered by Haxe and OpenFL
https://haxeflixel.com/
MIT License
1.96k stars 432 forks source link

Rethinking the collision/separation system #1307

Open danim1130 opened 9 years ago

danim1130 commented 9 years ago

Since there have been a few issues popping up with the collision system flixel uses (see #1301, #1270, #1078), and seeing how the next version of Flixel will be 4.0.0, this seems like the perfect time to rewrite the collision system. I would be glad to try my best in doing this after we have decided what the most optimal solution should be. Here's what I think now:

I think that the base of flixel shouldn't contain any separation logic whatsoever, only overlap checking. For that, I think integrating hxcollisions would be the best soulution. Haxepunk uses the same (or at least, it uses the same theorem), it's already well-written, and probably bug-free aswell. For the separation/physics, I think Phaser has an interesting, and maybe one of the best approach to this: they provide three different engine. One basic, something like flixel has now, one more advanced, with Circle hitboxes included, and one full-blown physics engine. Following this, we could have two different engines for flixel: one basic, something like we have now, and one with nape. For them to work with flixel, we could either provide an interface (hard to do, but more OOP, easier to integrate custom engines after), have different Flx classes (easier, but more classes, like FlxState and FlxNapeState, FlxSprite and FlxNapeSprite, what happens if we add a NapeSprite to a basic state?), or rewrite the classes so that their functionality depends on what engine is currently in use (so if you add an FlxSprite to a state, either an FlxBasicSprite, or an FlxNapeSprite gets added, depending on the engine the state uses). Nape integration is somewhat done, and the basic engine could use the same separation flixel has now, but it would have continuous collision detection (you wouldn't have to call FlxG.collide()), and masks. I personally like the third option, but the first could be manageable as well.

So what do you guys think?

Tiago-Ling commented 9 years ago

My 2 cents:

hxcollisions seems to be the best choice for the default system for flixel. As far as separation goes, there should be an easy way for the user to roll their own besides using the current system (which should be revised, since it's very buggy and unpredictable in certain situations). I'm against creating a lot more classes, for the user, changing the collision system should be more transparent and hassle free than having different kinds of states (no more FlxNapeState or other kinds, instead set the collision system through haxedefs or during FlxGame instantiation).

Nape integration is very nice, we have seen people using it with great results, but since using it means plugging the entire physics system, it should be optional to use and not the default method. I also have seen that some people using HaxeFlixel + Nape have their own custom integrated sprite classes. FlxNapeSprite is kind of limited in this regard and could be expanded to allow more control of the Nape's features.

Finally, the most important thing about the new system in my opinion is having polygon-based hitboxes. If i had to choose just one thing to implement that's what i'd do for sure.

Tiago Ling Alexandre Tel: +55 41 8819-3191

2014-09-28 10:47 GMT-03:00 danim1130 notifications@github.com:

Since there have been a few issues popping up with the collision system flixel uses (see #1301 https://github.com/HaxeFlixel/flixel/pull/1301,

1270 https://github.com/HaxeFlixel/flixel/issues/1270, #1078

https://github.com/HaxeFlixel/flixel/issues/1078), and seeing how the next version of Flixel will be 4.0.0, this seems like the perfect time to rewrite the collision system. I would be glad to try my best in doing this after we have decided what the most optimal solution should be. Here's what I think now:

I think that the base of flixel shouldn't contain any separation logic whatsoever, only overlap checking. For that, I think integrating hxcollisions would be the best soulution. Haxepunk uses the same (or at least, it uses the same theorem), it's already well-written, and probably bug-free aswell. For the separation/physics, I think Phaser has an interesting, and maybe one of the best approach to this: they provide three different engine. One basic, something like flixel has now, one more advanced, with Circle hitboxes included, and one full-blown physics engine. Following this, we could have two different engines for flixel: one basic, something like we have now, and one with nape. For them to work with flixel, we could either provide an interface (hard to do, but more OOP, easier to integrate custom engines after), have different Flx classes (easier, but more classes, like FlxState and FlxNapeState, FlxSprite and FlxNapeSprite, what happens if we add a NapeSprite to a basic stat e?), or rewrite the classes so that their functionality depends on what engine is currently in use (so if you add an FlxSprite to a state, either an FlxBasicSprite, or an FlxNapeSprite gets added, depending on the engine the state uses). Nape integration is somewhat done, and the basic engine could use the same separation flixel has now, but it would have continuous collision detection (you wouldn't have to call FlxG.collide()), and masks. I personally like the third option, but the first could be manageable as well.

So what do you guys think?

— Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1307.

MSGhero commented 9 years ago

Polygonal hitboxes are good, but how far should this system go? What is something that nape can do that flixel shouldn't be bothered with (arbiters, fluid interactions, polygon decomposition)?

Tiago-Ling commented 9 years ago

All the advanced features should be left for Nape imho, but nevertheless flixel should have a polygonal hitbox overlapping system as its default. I think this system should be minimum, concerned with overlaps and polygon representation only.

Tiago Ling Alexandre Tel: +55 41 8819-3191

2014-09-28 11:24 GMT-03:00 Nick Johnson notifications@github.com:

Polygonal hitboxes are good, but how far should this system go? What is something that nape can do that flixel shouldn't be bothered with (arbiters, fluid interactions, polygon decomposition)?

— Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1307#issuecomment-57087026.

Gama11 commented 9 years ago

More classes doesn't seem like a good approach to me. It creates issues like "What if I want to mix a FlxUIState with a FlxNapeSprite (which is why FlxNapeState has been refactored into a plugin). We also have a ton of classes that extend FlxSprite in the addons.

danim1130 commented 9 years ago

Yeah, I also think that we can throw out the multiple classes idea, I just wanted to list as many possibilities as I could. The next question is then, how should we go about choosing our engine in-game. Phaser can manage different engines running in a single state (for more, look here : http://www.html5gamedevs.com/topic/4518-explaining-phaser-2s-multiple-physics-systems/ ) Altough this looks really complicated, this also seems like the best solution. Other solutions would be to have a flag set at compile-time (but then we have Nape running during a simple menu screen), or have it set during state creation (but then we don't have compile-time error detecting when using for example nape functions while in the basic engine).

sruloart commented 9 years ago

You can have a FlxCollisionBase that will "translate" Nape functionality into the current basic collision stuff, so the user won't have to dig into Nape if he doesn't want to, but may still be able to extend it to get the more advanced stuff while actually using the Nape API.

Everything else sounds pretty complicated and time consuming. I mean, most of this functionality is already there to be taken (Nape Space, Nape Sprite, Nape Map...), so, why not use Nape for the most basic stuff as well?

danim1130 commented 9 years ago

At first, I also suggested to deeply integrate Nape and let it be the default engine, but to quote Gama11, "I don't think it should be mandatory to use a physics engine. A ton of games don't need that.". And while there probably wouldn't be a difference for PCs, a little mobile puzzle game might start to unnecessary lag on a slower phone if Nape becomes mandatory. Btw, is there a time-frame for when 4.0.0 gets released to the master branch?

sruloart commented 9 years ago

I'm not going to argue with gama11 ( I know better than that :) ) but Nape is excellent for low-end mobile devices, so a developer of a little mobile game will be thrilled to have Nape instead of the current system, even for the most basic stuff like hitboxes. Especially if it still looks like and feels like HaxeFlixel on top (so he doesn't actually need to know he's using a physics engine, if that matters).

The executable file size will become a bit bigger but that's the most horrible thing that will happen from a Nape-HaxeFlixel integration AFAIK.

Tiago-Ling commented 9 years ago

The problem is not Nape's performance i think, it's the changes needed in flixel to keep the same behavior for sprites and objects when using Nape.

I don't know what or how many things would need to be changed, but i don't think it would be simple to emulate flixel's simple "physics" on top of Nape.

Tiago Ling Alexandre Tel: +55 41 8819-3191

2014-09-28 15:07 GMT-03:00 Sruloart notifications@github.com:

I'm not going to argue with gama11 ( I know better than that :) ) but Nape is excellent for low-end mobile devices, so a developer of a little mobile game will be thrilled to have Nape instead of the current system, even for the most basic stuff like hitboxes. Especially if it still looks like and feels like HaxeFlixel on top (so he doesn't actually need to know he's using a physics engine, if that matters).

The executable file size will become a bit bigger but that's the most horrible thing that will happen from a Nape-HaxeFlixel integration AFAIK.

— Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1307#issuecomment-57094125.

danim1130 commented 9 years ago

After looking a little more at Phaser's code, I think I will try to implement their method to flixel, along with hxcollision. Although it will take time, I think ultimately this is the best solution.

EDIT: Although right now I have no idea how I should add a body to an FlxSprite. The two engines would have different bodies (obviously Nape's body would have more functions, properties), and I don't know how to store them in a single body variable. Phaser got around this by having un-safe typing, which I don't really like, but might have to use that here.

gamedevsam commented 9 years ago

I don't really like any of the ideas proposed so far. I'm currently in favor of leaving the limited collision system as-is and allow developers to use Nape if they need a physics API.

I'm big fan of Phaser, but I don't think it's appropriate for us to try and duplicate the way it handles collision systems. If anything, we could try to replicate the "arcade" physics of Phaser in HaxeFlixel, but still allow users to use Nape for more complex physics based games.

I don't want to add any additional dependencies to the core engine, and I think that any integrated collision system should be fast (high performance), simple (easy to use), and integrate well with the rest of the API (mostly FlxGroups).

Tiago-Ling commented 9 years ago

I don't care at all for physics integration. Imho we can just leave it to Nape as it is now (a little more options for Nape sprite wouldn't hurt though). But two things:

I don't really like any of the ideas proposed so far. I'm currently in favor of leaving the limited collision system as-is and allow developers to use Nape if they need a physics API.

I'm big fan of Phaser, but I don't think it's appropriate for us to try and duplicate the way it handles collision systems. If anything, we could try to replicate the "arcade" physics of Phaser in HaxeFlixel, but still allow users to use Nape for more complex physics based games.

I don't want to add any additional dependencies to the core engine, and I think that any integrated collision system should be fast (high performance), simple (easy to use), and integrate well with the rest of the API (mostly FlxGroups).

— Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1307#issuecomment-57117854.

SeiferTim commented 9 years ago

Whoa... I agree that there could be some tweaks and improvements to the built-in flixel collision, but I am NOT a fan of physics-engines like Nape... it doesn't 'feel' right for certain types of games... It would be fine to leave that as an optional add-in - if someone really wants to use a physics engine in their game, they can, but I wouldn't want to be forced to make my games work like that...

In the original 'design' of Flixel, everything was meant to be as simple to use and as basic as possible: You want something to move? Give it velocity/acceleration, you want something to collide? Just call FlxG.collide(obj1, obj2); and it should just work - you shouldn't need to do anything more than just loadGraphic on a sprite, either, to have all those things already working. I could have a working game with a jumping/moving sprite that collides with walls up and running with 5 lines of code.

danim1130 commented 9 years ago

The way I imagined, I think, you wouldn't have any problem with it. We would still have the same collision system we have now, only moved to a more logical place. Every sprite would have a body property, through which you can control it's physical properties. So instead writing player.velocity, you would write player.body.velocity. And after setting some mask flags (like player.body.collide(WALLS), you wouldn't even have to write FlxG.collide(), the system would take care of that. But under the hood, the same simple collision and separation system would work if you choose to use the basic, simple engine. The real difference would be in implementing nape, so that we wouldn't need another state class for nape, we would only have to add the player.body to a nape space.

Gama11 commented 9 years ago

I think @cwkx made a mockup of some sort of FlxBody class, that'd be very relevant here... Can't find the link to it it in slack though as the 10k message limit has been reached.

Tiago-Ling commented 9 years ago

@danim1130: Would it work in the exact same way as the current system? For example, setting sprite.body.velocity would result in the same behavior as using the "old" sprite.velocity? I think that's the main concern from @Tim, since doing the same thing (for example, variable height jump) in Nape differs greatly from doing it in flixel.

Tiago Ling Alexandre Tel: +55 41 8819-3191

2014-09-29 10:18 GMT-03:00 danim1130 notifications@github.com:

The way I imagined, I think, you wouldn't have any problem with it. We would still have the same collision system we have now, only moved to a more logical place. Every sprite would have a body property, through which you can control it's physical properties. So instead writing player.velocity, you would write player.body.velocity. And after setting some mask flags (like player.body.collide(WALLS), you wouldn't even have to write FlxG.collide(), the system would take care of that. But under the hood, the same simple collision and separation system would work if you choose to use the basic, simple engine. The real difference would be in implementing nape, so that we wouldn't need another state class for nape, we would only have to add the player.body to a nape space.

— Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1307#issuecomment-57158700.

Gama11 commented 9 years ago

@gamedevsam I don't think dependencies are that big a deal - we shouldn't always reinvent the wheel (see FlxTween, FlxSignal...). The current collision system works poorly, let's experiment with hxcollision and see how well it works.

danim1130 commented 9 years ago

Yes, if someone decides to use the basic system, then the only difference they would see is everything moving related (like velocity, acceleration, last, mass) would be in flxsprite.body, and instead of calling flxg.collide, you would assign masks to the objects about which should collide with which one (or at least this is what I hope to do).

Tiago-Ling commented 9 years ago

@danim1130: So, sprite.body would be a Nape body only if the user choose it to be (by setting the physics backend) - if not it would act as a simple container for the properties related to the current flixel movement/overlap/collision logic?

Tiago Ling Alexandre Tel: +55 41 8819-3191

2014-09-29 10:45 GMT-03:00 danim1130 notifications@github.com:

Yes, if someone decides to use the basic system, then the only difference they would see is everything moving related (like velocity, acceleration, last, mass) would be in flxsprite.body, and instead of calling flxg.collide, you would assign masks to the objects about which should collide with which one (or at least this is what I hope to do).

— Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1307#issuecomment-57162373.

MSGhero commented 9 years ago

Could you do an #if nape tag which sets sprite.body (and the state's stepPhysics() method) to its proper class at compile?

Collision exclusion is good, but honestly that just looks like nape code. We shouldn't rewrite nape minus the complicated stuff, it would be better to just use nape.

Gama11 commented 9 years ago

@MSGhero Nape is much more than just collisions. Obviously the API has to look similar for easy compatibility, but that doesn't mean we're rewriting Nape.

sruloart commented 9 years ago

Whatever you eventually decide, don't make a unique collision system, unique is bad m'kay?

And on that note, If we can have a FlxBody can we have a FlxMesh and a FlxTexture as well? since everything should now be separated and all of that :)

Gama11 commented 9 years ago

@sruloart What do you mean by "unique" exactly?

sruloart commented 9 years ago

A physics body that is written from scratch. A polygonal collision system that you make up.

gamedevsam commented 9 years ago

hxcollision is interesting. However I would prefer to keep the collision system native to Flixel. Perhaps we could port some of the hxcollision code?

Gama11 commented 9 years ago

@gamedevsam Any particular reason for that? Control over object creation etc?

gamedevsam commented 9 years ago

Whether we use hxcollision directly or not, we're going to have to do a significant refactor of some core engine classes. If we're going to do that, might as well replace the current system with a simple yet flexible collision system that lives in the core classes, and functions very similarly to the current system.

This approach would allow us to offer a less buggy alternative to the current system, without radically changing how it works.

We could bring in the separation elements of hxcollision, but still provide basic AABB (and maybe circle) collision handling in HaxeFlixel.

danim1130 commented 9 years ago

@gamedevsam hxcollision doesn't have any separation function, it's only for overlaps. I'm still not sure (and I don't think I ever will be before I start to actually work on it) if I want to copy the whole library, and add a common interface, or if I want to rewrite the whole thing inside flixel. I will probably do the first, since that's easier, and would reduce the chance of random bugs appearing.

@Tiago-Ling I'm also thinking about how to handle bodies. The main reason for this is because nape bodies have their x,y calculated by the center of their body, and this could cause problems with flixel's upper-left local coordinate system ,hence why in FlxNapeSprite's update, they have

        x = body.position.x - origin.x;
        y = body.position.y - origin.y;

Currently what I'm leaning towards is having a base body class (or interface), which has basic things like velocity, acceleration, velocity etc., and have bodies extend/implement this basic body class, where they could have other special properties (like FlxNapeBody having a material property). I would like this idea if not for the fact that if we had a Sprite whose body is in Nape space, then we would have to downcast from the base Body to NapeBody to call a special function (I like to avoid downcasting as often as I can). Nevertheless, since polygon hitboxes seems to be more important, I will start with that.

@sruloart I would be one of the happiest person in the world if I could write a unique collision system from scratch. :D

gamedevsam commented 9 years ago

"hxcollision doesn't have any separation function" Really? What about this demo?

danim1130 commented 9 years ago

That's a custom separation, which were only written for the demos, the library doesn't contain any. They are even more simpler than what we have now.

danim1130 commented 9 years ago

I've started implementing hxcollision. The question I've come upon is do we need CollisionDatas? Like where the two shapes intersect, the normal of the line segment etc. Calculating these sometimes doubles the performance, and I don't even think it would be that useful. Your opinions?

gamedevsam commented 9 years ago

Start simple, add if it makes sense or is necessary.

danim1130 commented 9 years ago

I'm almost finished with the hxCollision implementation, just have to solve a bug with raycasting. Should I make a pull request after I've documented everything, or should I make the physics engine separation and then make the pull request?

gamedevsam commented 9 years ago

You can make a pull request as soon as it's working how you intended it to. But this should be done in a separate branch.

danim1130 commented 9 years ago

Yeah, I was thinking that maybe there should be another branch for this. The only reason why I thought that a pull might do aswell was because the way it's implemented now (it's due to change when I rewrite the FlxQuadTree to work with this) nothing get's removed, so in theory, there wouldn't be any backward-compatibility issue. If someone could create a hitbox/overlap/collision refractoring branch, I would happily make the pull requests there.

gamedevsam commented 9 years ago

I think you just make changes on a new branch locally, and when you make a pull request a new branch will be created on our repo as well. The branch name should be collision_refactor.

gamedevsam commented 8 years ago

I wanted to contribute something related to this discussion, and other physics related issues. Recently, the development team of Lazer (Phaser's successor) have converted their physics engine to be data based (all object data is contained in contiguous typed arrays, with getters and setters on object references). You can see the beginnings of their refactor on this commit: photonstorm/lazer@219b17d

They created a benchmark comparing the two approaches (object-oriented, vs data-oriented) with dramatic results: http://perftestlazer.azurewebsites.net/

I believe the core physics engine of HaxeFlixel should be as fast and light as possible (since Nape already provides a more complex and feature filled alternative), and any major revisions to the physics API / implementation should move towards a data-oriented approach.