I'm looking for a little newbie advice on gamedev strategy and/or approach. I'm working on a game that uses Rigidbody physics in Unity and I've got a character interacting nicely with physical objects in the game world. The thing I'm trying to work through is that there are certain physical interactions that I want to control, but my own attempts to control them are conflicting with what Unity is already (correctly) doing.
For simplicity, let's just say I've got a Rigidbody-based player, and when certain Rigidbody-based objects collide with that player, I want to override where they deflect to. When I detect the collision and apply my own force with rb.AddForce(myForceVector, ForceMode.VelocityChange), Unity is also applying it's own force as a result of the same collision. I also tried setting the velocity directly with rb.velocity = myForceVector, which mostly works, but there are still situations where Unity applies force after I set the velocity so it's glitchy at best.
Other options I've considered are:
Use an additional, larger IsTrigger collision mesh to detect and handler the special type of collision I'm looking for before the actual collision occurs. That might work for slower speed projectiles, but likely will have the same issue for faster collisions.
Change the player to not being Rigidbody-based, which might work, but would require me to code a lot of the other interactions that are already working out of the box with Rigidbody physics.
Use RayCasting to detect when these special collisions might occur next and handle them before the actual collision. This is where I'm leaning currently.
Anyone have a recommended best practice for this kind of thing?
Thanks in advance!
The easiest way might just be to take full control. On the correctly timed press, disable the RigidBody and the Collider. Then just move it yourself to the target location. It's really hard to get precise control over a RigidBody -- every FixedUpdate(), it might be picking up force from collisions, and there can be many FixedUpdate() calls between Update() calls.
You could write a pretty simple coroutine using a Lerp() or Slerp() between the object's current and target position. That way, you could fully control how the object moves toward its target.
Just to follow up... I attempted to "take full control" as suggested in Alex M's answer above, but that ended up making a number of other things complicated in my specific situation. However, his comments about disabling the collider in the original question led me down a different path that ended up working well...
I ended up disabling the collider for the deflecting rigidbody upon impact and setting the velocity of the deflected body directly. That way, I was able to avoiding any additional force(s) applied from Unity while the collision was active. Once the deflected object was on it's way, I just had to reenable the collider.
Thanks, Alex!
Related
I am trying to make some kind of simulation program with Unity. The simulation includes a missile launched from an aircraft and a terrain.
I get the coordinate data required for the movement of the missile from another program using a socket connection.
I created an explosion effect for the missile to explode as soon as the missile and the terrain collided. But the explosion effect is not triggered in any way.
I used the OnCollisionEnter() method to detect the collision, but this method does not seem to work.
The missile has its own rigidbody and collider and The terrain has Terrain Collider, but still no collision is detected and the missile passes through the terrain.
What could be the cause of this error?
EDIT :
I thank everyone for their help, but none of the solutions worked. I solved the error using the OnTriggerEnter method. For this, I also had to enlarge the object's collider a little more.
As mentioned in the comment section above (I dont have enough rep to contribute to the discussion but will provide a solution), you need to enable continuous collision detection. Once you have done that we can move onto the next step.
It is generally bad practice to interact with rigidbodies in update and it can lead to all sorts of strange bugs so I wouldn't recommend it. That being said I dont think it's the cause of your issues. As #HumanWrites mentioned, you are manually moving the position each frame which causes your missile to never actually collide with your mesh. the solution to this is:
rb.MovePosition(Vector3.MoveTowards(...))
The reason for this is that by using the method on the rigidbody, you inform the physics engine that you want to move from one position to the other and you would like the physics to take care of this instead of you doing it directly. This allows it to "sweep" between the current position and target position and detect any collisions that would have happened along the way.
Your missile is moving too fast to ever actually touch the mesh within a frame so you need to rely on the physics engine doing that sweep check.
I am working on a 2D game that involves many blocks that stack and collide on eachother and the player. I am currently using Rigidbody2D on the blocks for dynamic collisions but I am not a fan of how the dynamic physics include the "bounciness" in the elastic collisions. Also, there is an inherent push-force as well as other unfavorable push physics that are too "realistic".
I am wondering what is the best way to handle my predicament to remove the bounciness and push elements of the rigid bodies. I've tried adjusting the block's masses and bounciness physics but no luck. Is there a way to set them all as kinematic or disable these realistic effects somehow and still have them collide via rigidbodies? (Kinematic would be great if they were able to collide with each other) Or will I have to create some sort of raycast based block physics handling script? Or is there an even better solution to creating this very primitive physics structure that I am not seeing?
Thanks for any and all help!
The only way I could think of solving your problem, such that you have complete intuitive accuracy, is to write your own Rigidbody controller. Of course you can still reuse the Box colliders.
Once you've decided on a collision detection method and manifold generation working (raycasting maybe), this link details the impulse resolution you need.
So, I'm working on a game and I've run in to the problem that.. I'm trying to detect the collision of two objects, and at first I assumed I needed two colliders. Then I found out I needed a rigid body, now I've come to find both object need a rigid body and this is a lot of cpu usage and the rigid bodies serve only to detect these collisions. It vastly limits how many objects I can have in a scene.
The only solution I can thin of is to be cast small rays from each side. Are there any other industry standard solutions that are more optimal?
Thanks in advance
There's no way to do exactly what you want. As you did not describe what you are planning to do (not even if 2D or 3D), here's a generic solution:
1) Attach a Rigidbody to only to one of the objects (out of two which could collide)
2) Tick in IsKinematic on Rigidbodyso it won't react on Physics
3) Tick in isTrigger on the other object's Collider (so it won't need a Rigidbody yet fires away trigger events when hits another object with a non-trigger(!!!) collider (and a Rigidbody)
(Or use Rigidbody on all your GOs, yet tick in IsKinematic on all of them)
As of your own collision detection, see #Hellium's comment.
I would add that, if you code your own collision detection, at the end of the day you'll most probably end up with a code eating more calc. time (and probably being at least a bit more sloppy).
Simply because you'll code in script, not C++ and the engine's Collision Detection is C++. (Your .net script will compile to native via il2cpp, so not a native implementation == must be slower than the code having similar nature, yet supported by the engine, i.e. coded in c++)
Side note: If you find your app. running slow, that's not necessarily because of collision detection. It's not impossible it's your code, what you do when you detect collision is running slow.
I highly recommend using the profiler to see what slows things down in your application.
If it really is your code, post a question on how to make that run faster.
I have a gameobject with two sphere colliders attached. One has IsTrigger checked and the other not.
I want to execute different set of statements when collision occurs with different colliders. For example I want to play different sound for both different collisions. Is there any way to achieve it?
I tried OnTriggerEnter() but unfortunately it is called for both type of collisions since other colliding objects have triggered colliders. I just thought if we could somehow find out on which collider of the gameobject the collision has taken place we will be able to achieve it.
So is there any way to get through with this?
I have been using Unity for years and faced tons of problems like this, related to bad software design. I hope Unity guys will handle physics more carefully in future releases.
In the mean time, you can use Physics.OverlapSphere and Physics.CheckSphere to manually check if there is something that collides with your object. Remove the collider that you are using as a trigger and use these methods instead of OnTriggerEnter. This is a bit hacky, but this will do the job I think.
Make your colliders visible in the inspector (make them public or add [SerializeField] before it) and then tie in the colliders to the code that way.
Then, in your collisions, compare the colliding objects against your variables that are holding the colliders for you to keep them separate.
To detect for source trigger in OnTriggerEnter, you must use workaround with multiple gameobject hosting trigger and satellite scripts.
Allow me to link to my answer on gamedev SO:
https://gamedev.stackexchange.com/a/185095/54452
I have my "player" gameObject standing atop a platform. He press a combination of keys, I verify that he's standing on the right kind of platform, and I run this code:
Physics2D.IgnoreLayerCollision(playerLayer, plataformLayer);
The intention being that he'd drop down from the platform. Instead, nothing happen immediately. The player is still atop the platform and can move around - only if he gets out of it and tries to get back to it, only at that point will he fall down from it.
So I made a temporary ugly workaround:
Physics2D.IgnoreLayerCollision(playerLayer, plataformLayer);
rigidbody2D.AddForce(transform.up * jump / 1.5f);
This will force the player to jump, making Unity "recalculate" the collisions and the player will, as I want to, pass through the platform. The even weirder part is: if the jump isn't high enough (100 force at 1 mass with 0.5 gravity scale seems to be the minimum), the player will still land on the platform, even though Unity is supposed to be ignoring those collisions.
I also tried pushing the player downwards, both with force and direct velocity, but no luck - he still collides with the platform, he only stops colliding with it after being away from it once.
Also, my player Rigidbody2D Detection Mode is set to Continuous, and I tried setting the platform up in many different ways, with and without a Rigidbody2D.
Any ideas on how to make the player instantly fall down from the platform as soon as collisions start being ignored? Thanks in advance.
I had been having the exact same issue. I have an alternative solution that you may find to your liking.
Rather than disabling or moving the terrain to be ignored, temporarily set the rigidbody2D of your player gameObject to kinematic. This will not cause you to 'drop' through the platform as you would like - but it will allow you to create the illusion that you are, by briefly using transform.Translate (or Vector3.Lerp, if you like) to move your character down via code.
This will disable Rigidbody2D.AddForce, but will still allow for set movement via rigibdody2D.velocity, if that is preferable to manipulating the transform directly.
Ensure the downward velocity lasts only as long as you are Kinematic, and try to let it match the gravity of your game, and it looks pretty seamless.
If you turn the rigidbody back on too quickly, it can (even with ignoreLayers :/ ) still jump back up to the platform - but if you leave it on too long, you can drop through more than one intended one-way platform, or even :O through the bottom of the stage!
This is easily avoided if you can be careful - personally I used both MonoBehaviour.Invoke to set a very short time limit on how long the player would remain Kinematic (about 0.5 seconds), AND I disabled Kinematic as soon as they moved 0.5 units from the point where the 'hopDown' was initiated.
If your gravity / platforms / character scale are vastly different than my own, you may have to experiment with some different numbers.
This has been my first attempt at an answer on stackoverflow, so I hope it has been helpful!
One easy way to do this is after calling
Physics2D.IgnoreLayerCollision(playerLayer, plataformLayer);
You reset the player's layer:
player.gameObject.layer = playerLayer;
It's sounds like you have covered a ton of possible solutions to this problem before coming here so, good job there. I listed a few alternative ideas below. I hope they help. Good luck!
Remove the collision object from the platform itself.
Offset the collision object to be in some remote location so it will not interact with the player. Offsetting the object may cause the collision to have a similar reaction to the jump you mentioned.