- Home /
Workarounds for Higher Control When Using Physics2D?
It's been a very long while since I've been on here asking for help. I've come a very long way in terms of my skills as a programmer, and I wouldn't have made it so far without the community to help jump start me. (Or at least not as quickly.) Cheers! :D
ANYWAY, I am working on a top-down 2D physics game where the main mechanic is bumping enemies into environment hazards. Right now I am trying to just make the prototype.
I keep having this re-occurring problem where I can't quite get the right feel in terms of balancing:
Collisions.
Sliding. (After being 'bumped back'.)
Player (and AI) input control.
I thought I fixed it a few days ago (after many experiments) but then I introduced a few walls and then a character collided with the another character, which bumped them into the wall, bounced back, then hit the original character at even higher speeds, and they both go flying off into oblivion at insane speeds. Also occasionally, collisions will cause one or both characters to react to the collision 'wrongly', such as moving perpendicular to the original velocity. I haven't been able to pinpoint what exactly is causing this.
('Character' refers to AI or the Player)(Note that scripting aspects are shared between characters)
Here's my current setup:
Rigidbody2D and CircleCollider2D on all characters. Linear Drag = 7.5, Angular drag = High number, Gravity = 0, Interpolate = Extrapolate, Collision detection = Continuous, Mass = 7.5 on the player, 2 - 4 on AI. (This is to make it easier for the player)
OnCollisionEnter2D: This frame's velocity MINUS last frame's velocity. Normalize the result and feed it into the other character's 'Knockback' function.
Knockback(direction, duration): Initialize a new knockback, based on direction and duration. The variables set in this will cause linear drag to be reduced. We do a delayed AddForce so that we know drag is reduced first. See #5: StartCoroutine("Push", direction) This combined with the fact that this is being applied upon top of the collision knockback is what is probably causing our massive velocity.
Update(): Set rigidbody2D drag to a percentage of our original drag. An input percentage multiplier does the same to our input. The percentage of both of these values is based on the time since the last knockback happened, and our knockback duration. A zero to one value is created between these two. I call this function 'ReverseLerp'. :D The zero-one value is then fed into AnimationCurve.Evaluate() to help smooth out the recovery. Increasing drag over time is a good way to speed us up in the beginning and then slow us down near the end, but there may be a better method. PROBLEM WITH THIS: Further collisions that happen with this cause additional force to be applied to the object by the physics engine. Oh, also after all of this, we do AddForce( input inputPercentage 1.5f * mass, ForceMode2D.Force )
Push(direction): WaitForFixedUpdate(), then do AddForce(direction * 2.5, Forcemode2D.Impulse) Remember this function was called earlier from Knockback().
Also in FixedUpdate(), we limit our velocity if it exceeds a certain magnitude. Velocity = velocity.normalized * maxVelocity; maxVelocity is shared between characters. This was added to try to fix the huge velocity problem. It helps a bit but not enough.
This is pretty much my setup that's giving me problems.
I've researched and considered some other solutions and possible methods of giving a more reliable balance...
Detect before the actual collision, which object has more force, and then give it 'dominance'. When the actual collision happens, make the non-dominant object take the full force of the collision somehow, and completely or mostly stop the 'dominant' object. I don't really know how I could override the physics engine's collisions like this without using isKinematic and doing this manually for both objects, which could cause some unrealistic looking physics, especially if a third object is involved.
Detecting collisions before they happen could be detected using a larger collider, as a trigger. Could cause problems if an object just barely misses an actual collision, as well as if we have very fast-moving objects.
Just completely create my own physics simulation using isKinematic, which I am not sure I have the mathematical knowledge and skills to do, even for 2D...
Questions:
What is a method of getting what force (as velocity) was gained or lost from a single rigidbody involved in a collision? (JUST the collision, and not the changes in force caused by other means, such as ApplyForce, or possibly drag?) If I could find this out, I could effectively 'remove' the change, normalize it, then re-add it at whatever magnitude I wanted, giving increased control.
What are your ideas on how to approach this problem? Any other workarounds that might be useful? Experiences or similar problems you've had? Solutions? I'm looking for any and all possible options at this point.
I just need this all to work well; It is the core gameplay mechanic, after all.
Offtopic sidenote: I swear every time I come on here to ask something, I end up writing this over-detailed long thing even though I tell myself that I won't this time. Sorry.
I didn't see you mention anywhere the physics2D materials that you use. I'd try to get the effect I wanted without writing any code at all first using the rigidbodies, colliders, and materials. I think you could solve a lot of your collision issues by manipulating the friction and bounciness parameters of the physics material.
Your answer
Follow this Question
Related Questions
How to check place on empty for placement polygon Rigidbody2d? 0 Answers
useAutoMass and child objects 1 Answer
Can a collider be solid along one axis only? 2 Answers
Trigger is not executed 1 Answer