I have a Gameobject called ball and another called floor. As can be seen in the code, when the ball hits the floor, a printout shall be made.
void OnCollisionEnter2D(Collision2D collision)
{
bg = GameObject.Find(bg_name);
if (collision.gameObject.tag == "floor")
{
//bg.GetComponent<ControlGame>().deleteBall();
//bg.GetComponent<ControlGame>().recreateBall();
print("Ball hit floor");
}
if (collision.gameObject.tag == "rope")
{
bg.GetComponent<ControlGame>().ToggleIsShot(false);
}
}
The problem is that I have moved the floor now, such that the ball and the floor has different depth. Still, the printout is made although the two Gameobjects are not touching. See the screenshots below:
The print is in the lower left corner. Why is that?
According to the comment below, the z-value does not have an effect. But I have also a collision detector for the rope, which is a Bezier-curve with an EdgeCollider2D attached to it. When the rope passes the floor, nothing is triggered in onCollisionEnter2D.
void OnCollisionEnter2D(Collision2D collision)
{
bg = GameObject.Find(bg_name);
if (collision.gameObject.tag == "floor")
{
print("floor collision");
bg.GetComponent<ControlGame>().ShootBall();
}
}
Well, these are Collider2D.
You only changed the Z (depth) position of the floor which basically is completely ignored in a 2D game / by 2D physics.
As you can also see in the GameView for the Physics 2D the objects are still aligned and colliding.
Why isn't it also working for collision between rope and floor?
Please checkout the Collision Action Matrix for which collisions/trigger can be detected.
→ At least one of the objects has to be a Rigidbody2D.
If the rope is e.g. moved by script then it has to be a Kinematic → in this case also the floor would need to be a Rigidbody2D and not Kinematic.
The reason I guess it worked just fine for the ball is because it already is a non-kinematic Rigidbody2D so able to detect collisions with static colliders.
Related
I'm creating a top down 2D game, where the player has to break down trees. I made it so the player casts a ray toward the mouse, and when the ray hits a tree, it should lower the tree's health. I don't get any errors when I run the game or click, but it seems like the tree isn't detecting the hits.
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit = Physics2D.Raycast(playerRb.transform.position, mousePosition - playerRb.transform.position, 2.0f);
if (hit.collider != null)
{
if (hit.collider == GameObject.FindWithTag("Tree"))
{
hit.collider.GetComponent<TreeScript>().treeHealth--;
}
}
}
}
Still pretty new to coding and I'm teaching myself, so please make your answer easy to understand to help me learn.
Input.mousePosition is equal to the pixel your mouse is on. This is very different than the location your mouse is pointing at in the scene. To explain further, Input.mousePosition is where the mouse is. Think about it. If the camera was facing up, the mouse positon would be the same, but where they are clicking is different.
Instead of using Input.mousePosition, You should pass this into a function called Ray Camera.ScreenPointToRay();
You just input the mouse position and then use this new ray to do the raycast.
ANOTHER EXTREMELY IMPORTANT THING 1: Do not use Camera.main in Update(), as it uses a GetComponet call, which can cause perormance decreases. Store a reference of it in your script and use that.
Extremely important thing 2: I notice you are using GetComponent to change the tree's health. This is fine, but do not use GetComponent if you don't have to.
Like this:
Camera cam;
void Start()
{
cam = Camera.main; //it is fine to use this in start,
//because it is only being called once.
}
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray);
...
}
}
You need to convert your mouse position from screen point to world point with Z value same as the other 2D objects.
Vector3 Worldpos=Camera.main.ScreenToWorldPoint(mousePos);
Also use a Debug.DrawRay to check the Raycast
Debug.DrawRay(ray.origin, ray.direction*10000f,Color.red);
Source
I need grip between two objects actually small cube is a player having rigid body and big cube is an object that helps small cube to jump on it and keep jumping on other big cubes to reach to the destination. I need when the player jumps and land on rotating cube so there should friction between them by default the player should rotate with big cube cause its on the big cube.
The expected result was that the small cube having rigid body should also rotate with big cube cause big cube is rotating and is on the big cube:
You can set the small cube gameobject as child of the big cube gameobject. This should to the trick.
----EDIT AFTER COMMENTS
If you need to change the child hiearchy (because the small cube can move away), then you need a script that add and remove the child when required.
=> When player (small cube) is on the big cube you much child player to the big cube.
=> When player (small cube) moves away of the big cube you much de-child player to the big cube.
If you're using rigidbodies you may use OnCollisionEnter and OnCollisionExit.
You may attach this monobehaviour to the big cube.
public class BigCubeScript : MonoBehaviour
{
private void OnCollisionEnter(Collision other)
{
//check if the colliding object is player (here I'm using a tag, but you may check it as you prefer)
if (other.gameObject.tag == "Player")
//change the parent of the player, setting it as this cube
other.transform.SetParent(this.transform);
}
void OnCollisionExit(Collision other)
{
if (other.gameObject.tag == "Player")
//remove the player from the cube
other.transform.SetParent(null);
}
}
You can also apply a force to the rotation of the player until he stays on the cube. In this case it's quite important to balance the rotation force well (you can try it in the editor).
public class BigCubeScript : MonoBehaviour
{
//you may change this to add or remove the force
Vector3 _rotationForce = new Vector3(0, 5, 0);
private void OnCollisionStay(Collision other)
{
var rigidbody = other.gameObject.GetComponent<Rigidbody>();
Quaternion deltaRotation = Quaternion.Euler(_rotationForce * Time.deltaTime);
rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);
}
}
Further info in OnCollisioEnter and OnCollisionExit in this Unity Tutorial
Further info on the Tags in this Unity Tutorial
You could try to constrain position and rotation on Rigidbody of the small cube. After that you could call constrains.none so that you could allow jump again and do that every time the small cube collides with the big one. Hope it helps :)
So, as the title implies, my OnCollisionEnter is not being called. I'm not sure why. The objects are bouncing off surfaces they contact.
Here's the relevant code:
static Rigidbody m_ProjectileRigidbody;
internal void FireProjectile(GameObject projectile, float speed)
{
projectile.transform.position =
State.PlayerTransform.position + State.PlayerTransform.forward;
projectile.transform.rotation = State.PlayerTransform.rotation;
m_ProjectileRigidbody = projectile.GetComponent<Rigidbody>();
m_ProjectileRigidbody.AddForce
(State.PlayerTransform.forward * speed, ForceMode.Impulse);
if (State.PlayerState.Consumes)
{
State.PlayerState.ConsumeCellEnergy(EnergyConsumption);
State.PlayerState.GenerateCellHeat(HeatProduction);
}
}
void OnCollisionEnter(Collision collision)
{
Debug.Log("Collided With: " + collision.gameObject.name);
}
If you are working with 2D colliders and rigidbodies, use OnCollisionEnter2D instead of OnCollisionEnter.
And make sure in Edit -> Project Settings -> Physics the collision matrix is properly set.
And also, double check that:
Both objects have collider, rigidbody properly set up.
Both objects are active.
You do not accidentally disable collider, rigidbody or set
isKinematic, isTrigger from your script.
I am have some difficulty with what is probably a very silly thing. I have an enemy gameobject that depending on where it is hit (collision) - either it, or the play dies. I think the simplest way to describe this is by using the classic Super Mario Bros. game as an example.
As you all know, if the player runs into the enemy - the player will lose - UNLESS he jumps on top of the enemy's head, in which case the enemy should die.
My initial idea was to create two colliders on the gameobject:
Blue border represents a BoxCollider2D - that if collided with - will cause player to lose (notice it is slightly lower from the top)
Green border represents a BoxCollider2D on a child gameobject - that if collided with - will cause the gameobject to die.
The following is a simplified version of the code I used:
// Collider #1
public void OnCollisionEnter2D(Collision2D collision)
{
// Trigger 'Game-Over' logic
}
// Collider #2
public void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
Destroy(this.gameObject);
}
}
This kind-of works, however momentarily after colliding with Collider #1, Collider #2 is also trigger - and while the enemy is destroyed, the player also loses.
I have been playing with the RigidBody2D values to prevent the player from entering the 2nd collider when hitting the enemy from the top - but apparently with that force / speed, the colliders may be slightly inaccurate (or maybe I'm just doing it wrong?).
I have looked into RayCasts but this seems too complex for something that me appears rather trivial (casting rays on all four sides and four vertices of the player - assuming that the player has a box collider).
What I have resorted to 'for the moment' is a a single collider with a simple piece of code that I am unhappy with, and doesn't always work:
public void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
float yVelocity = collision.gameObject.transform.rigidbody2D.velocity.y;
if (yVelocity < 0)
{
Debug.Log("Enemy will lose..." + yVelocity);
Destroy(this.gameObject);
}
else
{
// Trigger 'Game-Over' logic
}
}
}
I'm currently working in 2D mode, but solutions for 3D mode (while maybe more complicated than necessary for my question) will also be considered.
Thanks guys.
as a game developer you always have many ways to solve a problem or make a gameplay.
first of all i have to say you should make a polygon collider 2d fo you objects and chracters. just colliding pictures is not very good as i see you used box cilliders in your game.
a good choice can be that you attach and empty object ot you player and set its position under foots of you player and check of enemy hit that enemy dies else if enemy hit main character object, player dies.
another choice can be when o objects collide check y position of 2 objects. of player was higher he kiils, else enemy kills the player.
if you think more you will find more answers.
you have to examin diffrent ways and find most efficient.
I think it will be easy to disable the other collider when one is triggered. You can easily enable/disable colliders with collider.enabled = true; or collider.enabled = false;
// Collider #1
public void OnCollisionEnter2D(Collision2D collision)
{
// Trigger 'Game-Over' logic
// collider2.enabled = false;
}
// Collider #2
public void OnCollisionEnter2D(Collision2D collision)
{
// collider1.enabled = false;
if (collision.gameObject.tag == "Player")
{
Destroy(this.gameObject);
}
}
This way it will be pretty lightweight and easy to implement.
One way of implementing what you want is to put each collider in its child own game object and use the IsTouching() method.
void OnTriggerEnter2D(Collider2D other){
if(GameObject.Find("Top Trigger").GetComponent<BoxCollider2D>().IsTouching(other)){
Destroy(transform.gameObject)
}
if(GameObject.Find("Bottom Trigger").GetComponent<BoxCollider2D>().IsTouching(other)){
Destroy(other.gameObject)
}
}
I have rigidbody2D on arrow and enemy. both are at 0 z coordinates. I don't want to use colliders as I want the enemies to be able to stack on top of each other. When I turn colliders on, the code works and the objects get destroyed. Is there another function I could use that works with rigidbodies only? I thought OnCollicionEnter worked with rigidbodies.
arrow
function OnCollisionEnter2D(coll: Collision2D) {
Debug.Log("I hit something");
coll.gameObject.SendMessage("ApplyDamage", 10);
Destroy (gameObject);
}
enemy
var health = 20;
function ApplyDamage (damage : float)
{
health -= damage;
if ( health <= 0)
{
Destroy(gameObject);
}
}
Collisions require one Rigidbody to happen. In your OnCollisionEnter you could check if the coll parameter has a rigidbody attached. And only then apply the damage.
I just added a box collider to the enemy and set rigidbody2D to "is kinematic." This allowed the enemies to group up on top of each other while I could still collide. Also used OnTriggerEnter2D(coll: Collider2D) instead of OnCollisionEnter2D(coll: Collision2D).