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

Classic Physics: Slopes & Advanced Platforming #1808

Open nospoone opened 8 years ago

nospoone commented 8 years ago

I've been having this problem for a while, and I really think that having this built-in would benefit the community. @JoeCreates raised the issue in Slack, and I figured it was time to have a serious discussion about it.

The Problem

Flixel's non-NAPE physics work well when you have simple level geometry, such as what FlxTilemap offers. Things however get hairy when you try to adding more "advanced" platformer level elements, such as slopes, one-way floors, or even one-way slopes. As we can see from the FlxTilemapExt Demo, it works but doesn't feel as good as it should.

@JoeCreates has (long ago, in FlashPunk) created a demo which displays how slopes are expected to behave. The red floating slope is a one-way slope meaning that you can get in from the right side, but colliding properly on the left. Unrelated, but could also be implemented in FlxTilemapExt.

I am not qualified enough to dive into physics, but @larsiusprime and @Beeblerox have pointed out multiple resources that could potentially help:


Bounty

I know this is a big issue and a lot to think about (and also that I probably don't understand the implications), but I am offering a small 100$ bounty for this issue to get implemented/fixed.

The bounty is payable upon verifying that the classic HaxeFlixel physics work properly with slopes (the What's Expected list works), and that I am satisfied with the results.


(this is mostly a write up of a Slack conversation) cc @JoeCreates @Beeblerox @larsiusprime

larsiusprime commented 8 years ago

Also, any takers see this twitter convo for tips: https://twitter.com/larsiusprime/status/718825930085371904

This one in particular: https://twitter.com/raiganburns/status/718830593295802369

larsiusprime commented 8 years ago

Also for clarification purposes to anyone who takes this: by "physics" we mean flixel's "classic" "arcadey" physics, not actual realistic physics logics, the kind flixel alternatively supports by using full-blown physics libraries like NAPE. So this is just about getting the "classic" collision logic/gamefeel to get to a good place.

nospoone commented 8 years ago

I've updated the issue to clarify! Thanks!

MSGhero commented 8 years ago

I'm very familiar with this, so I'll ask a few clarifying questions:

Now, side note, if moving up and down slopes is what separates classic physics from nape physics, I've done that in nape before. You have to restrict rotation and modify your velocity when you're colliding with something whose normal is not flat (when you're on a slope). But yeah, that's not something a casual user would be able to figure out easily.

nospoone commented 8 years ago

In the same order:

It's not only slopes that makes them different. There are many other reasons.

MSGhero commented 8 years ago

I understand. Maybe a summer project for me, but not right now.

buckle2000 commented 8 years ago

If you want to implement it by yourself, using nape, check here. just remember replace the code in callback handler, store the normal of contact in callback. and then, use the direction of that "normal" to adjust the moving direction of your character also, you may need to Map different sprites with different physics bodies.

nape API doc

MSGhero commented 8 years ago

@buckle2000 Flixel I don't think even has anything to find the normal of contact. Like, there's no such thing as contact to find the normal of in the first place. All of the collision magic is hidden away in the quadtree class, which doesn't give bonus info describing the collision (and which no one understands). The FlxVector class is loaded with physics-y functions, but probably none of them actually get used right now. And callbacks are very limited.

The point is to add all of that by replacing or extending what currently exists. Then we can worry about one-way platforms, which are just a specific arrangement of all of those features.

buckle2000 commented 8 years ago

Sorry, what I mean is, there is a way to solve @nospoone 's problem, using nape. nothing to do with HaxeFlixel.

And callbacks are very limited.

errr, by callbacks I mean callbacks in nape, but not in HaxeFlixel.

Also, you are right, but do NOT expect HaxeFlixel's physics much, it is simple.

If you wish, See here. callbacks are used to determine whether a player is on the ground, check whether the direction of normal is facing "up", then the player can jump.

buckle2000 commented 8 years ago

OK, if you want to use flixel's "classic" "arcadey" physics, you can put all south-west facing slopes in one FlxGroup, and so on. If fact, HaxeFlixel has done this part for us. Then, check which kind of tile you are on by using FlxG.overlaps. (just before FlxG.collide) And then, move player according to the result.

The moving part of logic, however, should never be put in FlxTilemapExt.

JoeCreates commented 8 years ago

@buckle2000 I dont think anyone was suggesting moving logic should go in flxtilemapext. This demo simply highlights some classic platformer features we currently lack. On 10 Apr 2016 02:23, "buckle2000" notifications@github.com wrote:

OK, if you want to use flixel's "classic" "arcadey" physics, you can put all south-west facing slopes in one FlxSlope, and so on. If fact, HaxeFlixel has done this part for us. Then, check which kind of tile you are on by using FlxG.collide with callbacks. And then, move player according to the result.

The moving part of logic, however, should never be put in FlxTilemapExt.

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub

buckle2000 commented 8 years ago

@JoeCreates FlxSlope is a misspell. So I mean that since @nospoone and others can have it done in update(), this issue isn't really a issue.

JoeCreates commented 8 years ago

You could make a whole game from scratch in update. That doesn't mean its not useful to have common features ready implemented, especially seeing as these are so related to things flxobject already does.

Its also a pain to make the new physics reusable across many sprites due to flixels inheritence structure. You will find yourself having to reimplement it several times over if you have classes that already extend subclasses of flxobject or flxsprite, because you could not simply create your own subclass of flxsprite with the modified physics. For example, you could make your own ImprovedPhysicsSprite class, but then you realise you want to have that physocs work on a FlxNestedSprite (or any other existing subclass of FlxSprite).

An ideal solution would involve fixing the inheritence structure and using composition for physics and rendering, but thats a huge job and I dont know who is willing to do it. Until then, such features as these belong with the related logic. On 10 Apr 2016 02:40, "buckle2000" notifications@github.com wrote:

@JoeCreates https://github.com/JoeCreates FlxSlope is a misspell. So I mean that this issue isn't really a issue, @nospoone https://github.com/nospoone can have it done in update().

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1808#issuecomment-207894995

Beeblerox commented 8 years ago

this conversation goes to a point where we understand that inheritance isn't always good approach and we should use composition. But this will require rewriting some parts of the engine which will mean losing backward compatibility (and someone won't like it). I've been thinking about it for some time lately. And my approach is to break FlxObject into components, like in HaxePunk or Unity, or anything else component based engine. So FlxObject will have: transform (which will hold position, angle, scrolling etc. information), graphic (which will load graphical assets and will take position from transform and render on the screen), physics body (which will be update body's transform), and other components like path following or flickering. Plus i wanted to rewrite nested sprite groups through using transfrorm component so they will be similar to kiwi.js groups (this engine is cool looking for me and similar in some aspects to flixel, since it was based on it) When we will rewrite this part of the engine, we will be able to reimplement such classes as FlxSprite (as close as possible), but eventually we'll lose some of its features and lose backward compatibility with the price of better flexibility.

Beeblerox commented 8 years ago

and returning to actual topic of this issue: i think that Phaser do have better implementation of this feature - http://phaser.io/examples/v2/ninja-physics/ninja-tilemap So we can ask @photonstorm that he thinks about his implementation of ninja physics (what limitations it has, its strong and weak parts) and his permition to port this stuff/

Beeblerox commented 8 years ago

Phaser is licensed under MIT, so we can use its code as a basis (i guess). Let's try this out!

Gama11 commented 8 years ago

When we will rewrite this part of the engine, we will be able to reimplement such classes as FlxSprite (as close as possible), but eventually we'll lose some of its features and lose backward compatibility with the price of better flexibility.

Making huge breaking changes like that right now seems like a bad idea to me.. We just had a major release where we promised API stability. The changes you describe might be the biggest changes to date.

Beeblerox commented 8 years ago

@Gama11 i knew that you won't like it :) i know it's my fault that i've abandoned this project for a long time and hadn't made these changes before major 4.0 release. but i just can't see another way to achieve that. i was thinking about project structure for a while (that's the only thing i could do in my free time) and there are two ways: 1) we don't make major changes and engine will stay as we know it know, with known flaws (the main source of them is overusage of inheritance over composition). we still can fix minor flaws and bugs (for many of them i should be blamed, since i'm selftaught "programmer" and this was my way of learning things), but in the end it will stay the "same", with all of its childhood problems. 2) we will make major reconstruction of it and it could become much "better" (imho) engine. We can still maintain current architecture, like Phaser developers does. They maintain Phaser, but develop Lazer engine (which is the name of 3.0 version of the engine) at the same time, as they understand what things can be done with current codebase and what can't be done. That's hard decision and it forced by my incompetence in programming area and lack of involvement in engine's development, but this is how i see it right now.

Gama11 commented 8 years ago

We definitely can't just abandon 4.0 right now. And I doubt that any of these restructures help @nospoone, since they will take a long time to develop and he probably isn't willing to rewrite his entire game to fit the new API just for slope physics.

This issue seems to be getting way off-topic. We have issues like "component system for FlxObject" already: #1063

Tiago-Ling commented 8 years ago

I know that mantaining 4.0 is a priority and it should continue to be, but:

1) It's a great idea to create a new branch and experiment with a new structure imho (composition for example) 2) A lot of frameworks mantain more than one architecture at a time for big breaking changes, besides Phaser a good example is OpenFL with its legacy and next architecture 3) The new stuff from openfl (e.g. openf.display.Tilemap, per-sprite shaders, etc) will require flixel to do a major refactor to its rendering part if we want to use it (maybe even Tilesheet would eventually be removed?) 4) Even HaxeFlixel is used to this modus operandi, before 4.0.0 there were two architectures: 3.3 and dev

Tiago Ling Alexandre Tel: +55 41 8819-3191

2016-04-10 6:38 GMT-03:00 Gama11 notifications@github.com:

We definitely can't just abandon 4.0 right now. And I doubt that any of these restructures help @nospoone https://github.com/nospoone, since they will take a long time to develop and he probably isn't willing to rewrite his entire game to fit the new API just for slope physics.

This issue seems to be getting way off-topic. We have issues like "component system for FlxObject" already: #1063 https://github.com/HaxeFlixel/flixel/issues/1063

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/HaxeFlixel/flixel/issues/1808#issuecomment-207950952

MSGhero commented 8 years ago

@Nospoone soooooo... If you want to use nape now, you can hit me up for tips on how to change the feel of the engine

photonstorm commented 8 years ago

Hi all - just to add some thoughts here: I've been looking to implement slopes into Phaser's tilemap system for a while now (so under Arcade Physics, ala Flixel physics). If someone wants to work with me on this we could cross-share the results, so both projects would benefit.

larsiusprime commented 8 years ago

@photonstorm Raigan from metanet (N, N+, N++) is going to send me some code samples, I'll share my findings.

Beeblerox commented 8 years ago

@photonstorm i'd really like to participate, but can work only on weekends. Do you have any directions/ideas to start from?

Beeblerox commented 8 years ago

@photonstorm the only thing i found about your plan is "I want to get a proper SAT system into Arcade Physics" from http://phaser.io/news/2016/04/phaser-is-3-years-old

photonstorm commented 8 years ago

Nah that's unrelated to this really. I'm just looking at a nice way to handle slopes in tilemaps, so am starting with research into that. There are various methods, but it doesn't require a full-on SAT implementation (that's just something I'm putting in Phaser 2.5)

Beeblerox commented 8 years ago

@photonstorm ok, i think that you are going to implement SAT only for slopes then and stay with AABB for everything else. is this correct?

larsiusprime commented 8 years ago

@photonstorm @Beeblerox, So Raigan just sent me the stuff!

Here's the email for context:

hey, Here's the collision code from N v2.0.. it could definitely be improved, but the basic idea is that the world is described as a bunch of line segments and circular arcs, added to a grid to speed up queries. The two queries are distance and raycast.

In hindsight this might not be totally suitable in general since it means dynamic objects must all be circles (i.e since all the queries are distance-from-point-to-geometry). If you get rid of the circular arc geometry, it shouldn't be too hard to add support for dynamic capsule and rectangle shapes -- you just need to write distance-from-shape-to-linesegment.

The other main gotcha is that it's a bit complex to actually generate the surface geometry from a set of tile shapes, this code is in tiles.rar.

I don't know how performant our implementation of a "virtual grid" is.. mostly it's simple/straightforward, just a 1d list of cells which we map to a 2d grid. To look something up from the grid, you transform a worldspace x,y position into the corresponding 2d grid cell u,v coordinates, and then you transform the u,v coordinates into a 1d index into the actual list of cells. If you want to lookup a rectangular region, you get the 2d grid coords for min/max corners and then iterate across those.

Finally, I don't have any good examples of code that actually uses the collision system to perform collision detection+response.. sadly that's buried in a mess of other code and not easy to pull out. The basic idea is that for each dynamic object, you get the nearby geometry and then iteratively do: -find the single closest point on the geometry -push object out of that collision, and repeat

Right now I'm working on a revised collision system which will support more shapes and hopefully be even easier to understand.. no idea when it will be done though, lately there's not much time.

Please let me know if you have any questions.. I might be a couple days replying, stuff is busy :/ But, I would imagine there will be lots of questions since I haven't spent enough time explaining things nicely.. sorry!!

Cheers, Raigan

Here's the source that was generously attached to said email:

collision.rar: https://gist.github.com/larsiusprime/ced7c520203c40591a3937ba84cc8839

tiles.rar: https://gist.github.com/larsiusprime/eeead2179393bc8bd8276f991e94bdef

tanis2000 commented 8 years ago

If you're going for SAT you might as well look at luxe's code: https://github.com/underscorediscovery/luxe/blob/master/luxe/collision/sat/SAT2D.hx

It does pretty much what you guys need and it's Haxe code already.

But if I were you I'd also stick a spatial hash grid as the first check to avoid doing all the math each cycle.

danim1130 commented 8 years ago

So back in the days I went through the QuadTree code to solve a bug unrelated to this topic, and I can say with full confidence, that implementing slopes with the current system is nigh impossible, and even if you succeeded with something like that, it would probably really buggy (even the current system has it's problems) and break lots of legacy code. On the other side, one-way platforms might be doable, but can't say anything for sure with this.

greysondn commented 6 years ago

Came looking for a canonical solution today for slopes. Found this instead. So what I know may be of use -

What about Sonic's (classic) physics? (There's way more but most of what we seem to need is in how he interacts with slopes, which is in that portion.) Perhaps a special sprite class that is capable of such detections as Sonic's typically were is necessary, and if you want loops you might be better off checking into an insane asylum or leaving that as an end user exercise.

I know a lot of games with per-pixel motion (Earthbound, famously and easiest to examine if you'd like) used subtile tables for lookup. Such tables could perhaps be based on image, and the player sprite given a "step" it's allowed to cross (like "a vertical step of two per-pixel" or "a vertical shift of 5 per 20 pixels"). Speed would then be a matter of "gravity" + "slope".

A "real, honest to goodness" slope you could bounce balls off of all night like it's (a rebound table's back rails)[https://boardgamegeek.com/boardgame/3059/rebound], I don't know; I am willing to see what calculating the surface of a slope does and playing with it does if that's what people would like to see done, per pixel. It still would require new classes and perhaps a nice and neat way to merge surfaces (otherwise clipping the very corner edge of a tile may have unusual results).

From what I know of poking memory in emulators and reading papers on various games physics, I don't think there's a silver bullet, but I do think classes could be made that could be mostly general to this.

Better minds than me have been here before, I've no doubt; it's what I can offer other than the fact that I want this bad enough that I'm willing to try implementing what I'm talking about and see what comes of it.

danim1130 commented 6 years ago

Glad to see there's still some interest in these topics. It has been a long time since I looked at Flixel's source code, so what I say in this topic might be outdated (but it looks like not much has changed in these regards).

Just to give a little context: a while back I wanted to reimplement the physics engine inside (more can be seen in the #1307 issue). To make it short, there was an issue about the overlap callback being called multiple times, which I wanted to solve in a satisfactory manner. As it turned out, the issue was because of the way FlxQuadTrees work, and cannot be solved in the current system effectively. That's why I started working on a new engine.

Now the reason I wrote this is because if you want to complete this issue, I would advise you to not do it in the current engine, especially if you want it to be merged in. Maybe there could be some hacky solution in the current collision system (though it would be nothing short of a miracle making it work IMO), but that would probably cause bugs in older source files (the current system is really sensitive to the input parameters, like the order the objects are in the collision list). That would break backwards compatibility, meaning people with experience wouldn't be able to use their experience with the current system.

This is why it would be a good idea adding a new physics engine, and let that handle sloped tiles better. However, Flixel currently doesn't have any kind of support for this: physics parameter, like velocity and position are set at the FlxObject level, making it very bloated and rigid. You can see how this is handled with the Nape extenesion, which while definitely works, is more of a workaround than a good solution. A new engine would allow us to remain backwards compatible while providing a newer, cleaner system with slopes things like this handled.

Back when I was working on this, I got to the point where it was possible to switch out the physics engine easily, but unfortunately gave up when I found how FlxTile is handled differently in the current system, which made generalizing it really hard. But who knows, maybe I will give this another go when I have a little more time for hobby projects.

If at anytime you would like to give this a try, feel free to hit me up either at Slack (though it seems like it died out since), Discord (under the name Lasent), or here.

greysondn commented 6 years ago

I parted the HaxeFlixel discord deliberately; it may make sense if this is a tangible problem to make an alt-physics branch or do something else. Drop-in physics systems make sense, with default being "classic", but... I'unno. There's a certain point there where I get lost quickly. (Logic was more my strength, I failed Trig 7 times in Uni.)

I am available here trivially. If you really need my attention and I'm not checking in, have the email greysondn@gmail.com and it's attached to several of my professional accounts so I do check it at least once a week.

I'm always happy to do what I can. Well, there are limits; see why I parted the server. I don't see any obvious problems though.