Update
I've discovered that rigidbody doesn't cast to rigidbody2d. I've tried manually casting, but get errors saying that it can't be done... So my new question is, how can I get joints to work with rigidbody2D?
OP
Learning Unity and am now playing with physics. I've got a small game running and it's all working lovely, but what I'm having issues wrapping my head around is the 2D physics.
I've got various "crates" and each have their own physics values (gravity etc).I've also got a "crate mover" which will (in theory) move crates from one place to another.
However, due to my movers having defined positions they can move to in game space, I'm having terrible trouble getting the crates to "stick" to the movers when they're moved.
So, I did some digging around and found Joints - Specifically FixedJoint - I figured that would solve it, if I attached a joint to the mover and set it's body to the crate? Right? No.
I get this error:
NullReferenceException: Object reference not set to an instance of an object
RobertMover.OnCollisionEnter2D (UnityEngine.Collision2D coll) (at Assets/Scripts/RobertMover.cs:29)
Which relates to the following code:
void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log (coll.gameObject);
FixedJoint j = (FixedJoint)this.gameObject.AddComponent ("FixedJoint");
j.connectedBody = coll.gameObject.rigidbody; // problem line
}
Seeing as I'm still learning Unity, I'm a little unsure as to what is null. My crate has a rigidbody. As does my mover, as I read that joints require them. The object isn't null (checked with the Debug.Log...). The only thing I can think is that the Joint itself is null, which is very odd!
Can anyone explain what I'm doing wrong?
2d physics only works with "2d" classes and methods, you should be using FixedJoint2D or a comparable "2D" joint class if that particular one doesn't exist
Related
so I've been struggling with a problem for a while, not sure how to approach it.
I'm trying to simulate a magic system similar to The Force used in Star Wars in Unity, and have ran into some troubles. I'm trying to simulate pushing and pulling on objects appropriately. This means that when the player pushes an object, both the player and the object get a force applied to them. If the object is light enough, the player shouldn't be affected in any noticeable way, and the object should be pushed away. If their masses are similar, both should be pushed away at some rate, and if the object is heaver, the player should be mainly pushed away. The same goes with pulling. The problem is when objects are anchored against something. If a player pushes a light object into a wall, the player should start receiving enough force to start pushing them backwards, since the combined mass of the wall and the object are pushing the player back.
Currently, I'm able to do the first part with the following code when a key is pressed:
Note that the force is determined based off the distance from the player to the object and the mass of them.
// dir: push or pull (-1 or 1)
Vector3 directionToPlayer = (dir * (player.transform.position - transform.position)).normalized;
rb.AddRelativeForce(directionToPlayer * f * Time.deltaTime);
player.GetComponent<Rigidbody>().AddRelativeForce(-directionToPlayer * f * Time.deltaTime);
As it is, the code works fine when the objects are just by themselves just by relying on Unity's Physics system. However, it does NOT work when an object is being pushed against a wall, or something really heavy. This is pretty clear as I'm just applying the same force to both the object and the player, and letting Unity decide whether to move the entity based off its rigidbody mass.
My question is, how can I detect if an object is anchored, and if it is combine the mass of the object and the object which it is anchored to, and apply that force to the player? I was thinking how to do this, and I know that I need to figure out the direction of which the force is being applied from, and then determine whether the object that's being pushed or pulled is colliding with anything in that direction, and if so apply a force to the player based off the combined masses. This gets a little tricky however when pushing an object at an angle that's against a wall. For example consider the following scenario:
There is both a horizontal and a vertical component of the force being applied on the cube, and so that should be considered when the cube+wall combined object pushes back on the player. How could this be accomplished or approached? I'm really struggling coming up with how to do this without hard coding direcitons.
Any help is appreciated, and I'll gladly clarify if anything is unclear.
NOTE The system is really based from a book series called Mistborn, but the concept is really close to The Force in Star Wars, and so I'll run with that as more people are familiar with it
This is not a complete solution, but you can use my idea below to acquire the nearby objects and then apply force to your objects and player in accordance with that.
The script should be placed on the object you are pushing or at least use a sphere collider from the object you are pushing.
public List<string> _ValidTargetTags = new List<string> { "Wall" };
public void CheckNearbyArea()
{
//Each of the nearby items will be checked to see if they are a wall or other valid target.
Collider[] ObjectsStruck = ScanForItems(GetComponent<SphereCollider>());
foreach (var o in ObjectsStruck)
{
if (_ValidTargetTags.Contains(o.gameObject.tag))
{
//If wall or other valid target
//Check where wall is placed
//Act according to wall position.
}
}
}
///The method below should find a list of all items inside a spherecollider of the object you are pushing.
Collider[] ScanForItems(SphereCollider sphereCollider)
{
Vector3 center = sphereCollider.transform.position + sphereCollider.center;
float radius = sphereCollider.radius;
Collider[] allOverlappingColliders = Physics.OverlapSphere(center, radius);
return allOverlappingColliders;
}
With this solution you will be able to check the players location relative to any nearby walls. This you can use to calculate what his direction is compared to the wall, relative to the object he is pushing.
I have multiple enemies that move toward the player. I am trying to stop them from merging into each other, i.e maintain some type of minimum distance between each other. What I'm trying is this (from unity3d forums):
enemy1.transform.position = (enemy1.transform.position -
enemy2.transform.position).normalized * distance + enemy2.transform.position;
However, when I have >= 3 enemies they still seem to bunch up even when I apply this to every enemy combination.
I need a better method as this one does not work and does not scale.
What you do around your enemy prefab is place a quad box which in effect is a trigger element, then on you script for the enemy you set that if another enemy (using tag types, I imagine) comes within touching of the quad box then to run appropriate code to stop the enemy getting closer in and to prevent the enemy actually overlapping with this trigger box.
Your code you example in your question looks like it is referencing the enemy units specifically rather than as instance entitites which is very probably a bad way of coding, as you're finding, it's very inflexible dealing with not-specifically-named reference entities.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
private Transform otherEntity;
public float distance = 50.0f;
private Transform thisEntity;
void OnTriggerEnter(Collider other)
{
otherEntity = other.GetComponent<Transform>();
thisEntity = GetComponent<Transform>();
thisEntity.position = (thisEntity.position - otherEntity.position).normalized * distance + otherEntity.position;
}
}
I have not tested the above code but using the code you reference the values for the transform are loaded from the Game Component for the referenced entities, as this has changed ALOT in Unity since release of version 5.1 and your source for your code was an answer given in 2012!!
thisEntity is the object that the script is attached to, typically one of the enemy. The otherEntity is the object that comes within the quad trigger (please remember the quad needs to be referenced as a trigger element.
The values of the Entity variables need to be set once the trigger is entered, so that it always effects the correct other element.
(I may be totally wrong with my methodology but I hope this helps.)
I'm trying to drive a configurable joint to the same rotation as another game object. Basically I'm trying to get one marionette to shadow another.
Im using the following code:
public GameObject master;
public GameObject slave;
void Update (){
ConfigurableJoint cj = slave.transform.GetComponent(typeof(ConfigurableJoint)) as ConfigurableJoint;
cj.targetRotation = master.transform.rotation;
}
However, I don't get any rotation out of the slave. Can anyone explain what I should be doing?
Are you sure you are getting the right joint ? Is cj null ?
Maybe try this line instead :
ConfigurableJoint cj = slave.GetComponent<ConfigurableJoint>();
When you are dealing with physics you can't apply rotation to a Rigid Body. What you can do is copy and paste the local transform to another non-static game object in relationship with its perent that does not contain a Rigid Body.
So basically the configurable joint has so so many options and parameters to set it up to your need that you need to take a course 2hrs course. There is no space here for a simple answer to set it up. I recommend this free old course because is the only one that at the moment explains in deep: This is more a general answer but works. There is an old tutorial in Unity3 that explains the setup:
https://archive.org/details/3dbuzz-archive/unity-fundamentals-part-04/020-physics/013-13-configurable-joint.mp4
I'm attempting to simulate a ship/space station with internal gravity.
To accomplish this, I'm making the player and all contents of the ship children of the ship. The ship itself has colliders, but no rigid body components. The idea is that as the ship moves, so will all of its contents. Pretty straightforward so far.
To simulate gravity in the ship, the player controller and all rigid bodies have the default gravity turned off. Instead of the standard, each frame a force is applied along the negative up vector of the parent ship.
This sort of works, but there is one major problem that I have to sort out before this thing is solid. All rigid bodies slide around the interior of the ship very slowly.
I'm aware that this is probably due to the updated position of the floor combined with the gravity force resulting in some kind of shear force. The objects always slide against the rotation of the ship.
I've tried mucking around with all of the physics properties from Physic materials to drag to mass, etc. None of these have worked, and I'm pretty sure it's due to the fundamental fact that the floor is moving, even though the RBs are children of the object that the floor is a part of.
Anyone have a solution to this that isn't some kind of duct tape? I could try to make everything kinematic and only "wake up" when certain external collisions occur or something, but that could get very cumbersome. I need for this to work in as much of a general purpose way as possible.
Some code:
On the ship
void Update ()
{
transform.Rotate(new Vector3(Time.deltaTime * 0.125f,Time.deltaTime*0.5f,0));
}
void FixedUpdate()
{
Vector3 tempVec;
foreach(Rigidbody rb in rigidBodies)
{
//Gravity!!
tempVec = transform.up * -9.81f * rb.mass * Time.deltaTime;
rb.AddForce(tempVec, ForceMode.Acceleration);
}
}
I've also worked on a version where the ship was following the movements of a rigid body. I couldn't do direct parenting, so I had to simply set the transform manually each frame to match the physics proxy. This still had the same effect as above, though it's probably ultimately how I want to move the ship, since that will tie into the flight mechanics more properly.
If you equate this to a real world scenario, the only thing that stops us from sliding around on the floor is friction.
Does the Physics library correctly apply friction based on the contacting materials? If not applying a certain amount of friction (or a minimum amount of force applied required to overcome it) should have the effect of preventing you from sliding around on the floor.
Although this is pretty much "duct tape" as above, it could neatly fit in and expand your physics engine if it doesn't already contain a way to enforce it.
As suggested above, the issue is because of how the physics engine applies friction. If I'm not mistaken, there will be some other forces acting on objects in a rotating frame (some of which are very unintuitive - check out this video: https://www.youtube.com/watch?v=bJ_seXo-Enc). However, despite all that (plus likely rounding errors arising from the engine itself and the joys of floating-point mathematics), in the real world, static friction is greater than moving (kinetic) friction. I don't think this is often implemented in game physics engines, which is why we so often see "wobbly" near-static objects. Also, you may run into the issue that even if this is implemented, the physics engine may be interpreting two contacting rotating bodies as non-static (even though their contact surfaces are static from a local perspective, the engine may be thinking globally)... [Insert joke about Newton and Einstein arguing].
https://i.stack.imgur.com/AMDr2.gif shows an idealised version of what friction actually looks like in the real world: until you overcome the static friction, nothing moves.
One way you would implement this (if you can access the physics engine that low-level) would be to round all movement forces below a certain threshold to zero - i.e. force < 0.001* is set to 0 (or possibly velocity < 0.001 is set to zero - whichever is easier).
*Some threshold - you'll have to work out what this is.
Otherwise, maybe you could instruct those objects to stop calculating physics and "stick" them to the parent surface, until such time as you want to do something with them? (This is probably a bad solution, but most of the other ideas above rely on hacking the underlying physics code).
I have an object with a mesh collider and a prefab with sphere collider. I want the instance of the prefab to be destroyed if the two collide.
I wrote the following in a script:
private void OnCollisionEnter(Collision c)
{
if (c == target)
Destroy(transform.gameObject);
print("something"); // Doesn't get printed
}
But it is not working. I have tried toggling isTrigger on both the objects.
I had the same problem of OnCollisionEnter not being called and found this question.
For me, the problem was that I was making a 2D game so the answer is to use the OnCollisionEnter2D function instead.
Have a look at this table
If you want your OnCollisionEnter to be called make sure:
(a) Both objects have a collider attached.
(b) None of the objects is a trigger collider (this will issue OnTrigger function & not OnCollisionEnter)
(c) One of the objects (doesn't matter which of them) is a rigid, non kinematic & non static object (the second don't have to be a rigid body).
(d) Due to computational difficulties MeshCollider might have hard times colliding with other mesh collider, use them with caution.
(e) Make sure both the objects are in the same layer (or at least that they collide in scene settings).
(f) If you are working in 2d - OnCollisionEnter2D will be called, rename your function.
Make sure one of them has a non-kinematic rigidbody attached. Taken from the Unity docs:
When a collision between two Colliders occurs and if at least one of them has a Rigidbody attached, three collision messages are sent out to the objects attached to them. These events can be handled in scripting, and allow you to create unique behaviors with or without making use of the built-in NVIDIA PhysX engine.
From here: Unity3D MeshCollider
I had a similar problem. The box collider wasn't as big as the collision object. Setting the x and z values to 2 units fixed the problem!
Have you tried using the OnTriggerEnter() method and setting a collider on the object to a trigger?
If it doesn't need to tell what object its colliding with you could do a simple
void OnTriggerEnter(){
Destroy(transform.gameObject);
}
Edit:
Also I have done OnCollision like this
private string hitobject;
void OnCollisionEnter(UnityEngine.Collision hit)
{
hitobject = hit.gameObject.tag;
if(hitobject == "Plane")
{
isgrounded = true;
}
}
None of the objects are triggers and they don't need rigid bodies to work.