I'm creating a 2d game and I want to make it so that tiles are destructible whenever a projectile collides with a tile. The problem is I don't know how to get the tile that the projectile is colliding with, I would like to make it so that it area of damage.
However for now I want to make it so that once the projectile reaches the ground it destroys the tile it's sitting on I've made a collider2d to help me with that but I still have no idea how to get the tile that's the projectile is sitting on.
IEnumerator OnCollisionEnter2D(Collision2D collision)
{
//Projectile has reached the ground and is in collision with some tile
Vector2 hit = gameObject.transform.position;
Debug.Log("y" + hit.y);
hit.y =- 3; // i have no idea what y i should put in order to get the tile
if (x.gameObject.tag != "Player")
{
Collider2D[] collidedwith = Physics2D.OverlapCircleAll(this.gameObject.transform.position, radius);
//what should the hit vector be in order to destroy the tile.
tilemap.SetTile(tilemap.WorldToCell(hit), null);
}
}
A screenshot for better explanation (I would like to get rid of the blue tile):
If possible I would like to make it into an aoe projectile but for now it's not necessary
Assuming you have colliders in place, that is:
Collider in the rocket with is trigger selected (to allow OnTriggerEnter2D be triggered)
Collider on the tiles to actually trigger the OnTriggerEnter2D of the rocket during the collision
Now, to detect collisions between rocket and tiles, do the following:
Give the tile gameObject (prefab) the tag name tile
Replace your code in the rocket with:
Script
// It will be triggered the the rocket crashes against the tile
void OnTriggerEnter2D(Collider2D col)
{
if(collision.gameObject.tag == "tile")
{
// Destroy the tile the rockets collided with
Destroy(collision.collider.gameObject);
// Destroy the rocket itself
Destroy(gameObject);
}
}
ok i came up with a solution but this solution doesn't really have the feature i really wanted which is, i want the projectile to do aoe damage
Tilemap tilemap = GetComponent<Tilemap>();
Vector3 hitPosition = Vector3.zero;
foreach (ContactPoint2D hit in collision.contacts)
{
Debug.Log(hit.point);
hitPosition.x = hit.point.x - 0.1f;
hitPosition.y = hit.point.y - 0.1f ;
tilemap.SetTile(tilemap.WorldToCell(hitPosition), null);
}
Related
I am a starter in Unity and developing a soccer game. I have a problem ,my IF statements conflict each other. Let me explain it in detail.
In order for a ball to stick to player, I have used IF operator, so whenever the distance between the player and the ball is less than < 0.5 , the ball sticks to player and move together with it. Now when I try to set up shooting the ball (I try with "addforce") it doesnt let me, cause the ball is still attached to player and distance is <0.5.
This one is the balls script.
public bool sticktoplayer;
public transform player;
//gameobject Player is attached
float distancetoplayer;
Rigidbody rb;
//balls rigidbody
void Awake ()
{
rb = getComponent<Rigidbody>();
}
void Update()
{
If (!sticktoplayer)
{
float distancetoplayer = Vector3.Distance (player.position, transform.position);
if(distancetoplayer < 0.5f)
{
sticktoplayer = true;
}
}
else
{
transform.position = player.position;
}
if(Input.GetKeyDown(KeyCode.Space))
{
rb.addforce(20, 0, 0, ForceMode.Impulse);
sticktoplayer = false;
}
When the player is not controlling the ball the force is succesfully applied to the ball, but when the ball is attached (distancetoplayer<0.5) then the other IF statements blocks it from shooting.
Maybe there are some work arounds ? Thanks.
I tried to make another if statement.
why dont you try sticking the ball to the player by collision? instead of checking the distance, create a collider with the radius or scale you desire and whenever the ball is inside the collider (when it triggers with the collider) stick it to the player. Because you will not be able to let the ball go since the ball will always be less then 0.5f away from the player once it sticks
have you tried it this way?
if(Input.GetKeyDown(KeyCode.Space))
{
sticktoplayer = false;
rb.addforce(20, 0, 0, ForceMode.Impulse);
}
I am currently working on a game in Unity and I have a huge problem. I want to draw a level with a tilemap and then move the player on this tilemap. But I want to add an edge collider with the script at the start of the level, because I want to include a Level-Creator in the game. So, I cannot create every collider manual.
Here is an example picture of a "level":
I want to have an edge collider to prevent moving outside the tilemap, but I do not know how to implement that in code. I either cannot find anything helpful on web.
I would be glad about any ideas!
If you get the Collider component of your tilemap, you are able to access the "OverlapPoint" method. With this method you're able to make a basic edge detection system for your custom tile map.
https://docs.unity3d.com/ScriptReference/Collider2D.OverlapPoint.html
What I would do is:
Save Your player's current position in a "lastPosition" variable, check for every update if the corners are inside the collider with the "OverlapPoint" method. If not: do not save the current position but set the current position of the player to the lastPosition variable.
public Vector3 playerSize;
public Collider2d collider;
Vector2 lastPosition;
void Start()
{
lastPosition = transform.position;
}
void Update()
{
if(!collider.OverlapPoint(transform.position) ||
!collider.OverlapPoint(transform.position + playerSize) ||
!collider.OverlapPoint(transform.position + new Vector2(playerSize.x, 0)) ||
!collider.OverlapPoint(transform.position + new Vector2(0, playerSize.y)))
{
transform.position = lastPosition;
}
lastPosition = transform.position;
}
I have two different type colliders in a gameobject: a sphere collider for a trigger and a capsule collider for a hit raycast. I have this code for the OnTriggerEnter but nothing happens when the player enters in the sphere trigger. What am I doing wrong?
public GameObject canvasTesoroFoto;
public GameObject canvasTesoroDatos;
private GameObject Player;
public SphereCollider sCollider;
public CapsuleCollider cCollider;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
sCollider = GetComponent<SphereCollider> ();
cCollider = GetComponent<CapsuleCollider> ();
}
void OnTriggerEnter(Collider other)
{
if (other == sCollider) {
if (other.gameObject.tag == "Player") {
canvasTesoroFoto.SetActive (true);
canvasTesoroDatos.SetActive (true);
}
}
if (other == cCollider) {
Debug.Log ("HitCollider");
return;
}
}
To make it work you will need:
In the obstacle: The Sphere collider with the is trigger checked
In the player:
A collider
A rigidbody
Besides, if the scrip is in the obstacle, the collider other will refer to the player NOT to the OBSTACLE. So you should do directly like this:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player") {
canvasTesoroFoto.SetActive (true);
canvasTesoroDatos.SetActive (true);
}
}
Based on your comment. In that case you should consider add the trigger in the collider of the player, to detect the sphere of the obstacle, and leave the trigger for the capsule.
And in case you need that both colliders in the obstacle are triggered, what you can do is to create a sphere gameobject as child of the obstacle, make it transparent and add there the script and sphere collider. Then keep the collider in the obstacle itself. Then you can exchange information between script in the sphere and the obstacle if necessary.
But as far as I know, there is not way to distinguish which of the colliders in the gameobject triggered OnTriggerEnter() if both has got checked "is trigger"
Edit: based on your comments, I imagine a situation where the GameObejct of the colliders is some kind of enemy which may be hit by raycast and at the same time can crash with the Player (for example to take life from him).
The best approach is to make is trigger the collider of the Player, to detect the sphere collider of the enemy in a script attached to the Player. Then uncheck is trigger the sphere collider in the enemy. And just leave is trigger the capsule collider to detect raycast.
In this tutorial you have a nice example of this:
https://unity3d.com/learn/tutorials/s/survival-shooter-tutorial
Make sure that your game object for Player also has attached collider
I'm trying to make a BTD game. Since different balloons (enemies) have different speeds, they collide with each other when traveling on the path. I'm currently using this code:
void OnCollisionEnter (Collision coll)
{
if (coll.gameObject.tag == "Enemy")
{
Physics.IgnoreCollision(coll.collider, gameObject.GetComponent<SphereCollider>());
}
}
However, it doesn't appear to be working at all. The enemies still collide with each other. On the otherhand, the collision with the enemies and bullets from towers is working.
void OnTriggerEnter (Collider col)
{
if (col.tag == "Bullet")
{
CurrentHP -= col.GetComponent<TackShooterBullet>().Damage;
}
I've tried layer-collision (enemies to same layer & unchecking of the same layer collision in the layer collision matrix, but that doesn't work either. The enemy contains a sphere mesh filter, sphere collider, mesh renderer, rigidbody, material, and 2 scripts. Is there a better way to avoid collisions between the enemies. I'm asking this question since I've seen duplicates, but their solutions aren't working at all. I can provide more of my code if needed.
Edit for Clarity: Again, what I'm trying to accomplish is have the enemies be able to go through each other.
Edit (Fixed Problem): I found out to avoid Enemy Collisions, I could also remove rigidbody. However, removing the ridigbody would mess up the bullet --> enemy trigger in the enemy class. Therefore, I just wrote the collision between bullet & enemy in the bullet class instead.
using UnityEngine;
public class TackShooterBullet : MonoBehaviour {
private GameObject target;
public float Damage;
// Use this for initialization
void Start () {
target = transform.parent.GetComponent<TackShooterRange>().Target; // Target = Enemy[0] (First Enemy To Enter Range - Enemy is Removed from JList when exiting Range)
}
// Update is called once per frame
void Update()
{
Damage = gameObject.transform.parent.transform.parent.GetComponent<TackShooterLimitingRange1>().level * 20; // Upgrade Level * 20 = Damage Done
if (target == null) // If Enemy Exits Range
{
Destroy(gameObject); // Destroy Bullet
}
if (target != null) // Enemy Exists In Range
{
transform.position = Vector3.MoveTowards(transform.position, target.transform.position, 20 * Time.deltaTime); // Bullet Follows Enemy
Destroy(gameObject); // Destroy Bullet Upon Contact With Enemy
target.GetComponent<HealthOfEnemy>().CurrentHP -= Damage; // Enemy Loses Health
}
}
This allowed me to remove the OnTriggerEnter & OnCollisionEnter methods as well as the RigidBody from the Enemy Class as stated before, so these properties no longer affect the collisions between Enemies.
Unity has a built in function for easier collision detection called layer-based collision detection:
https://docs.unity3d.com/Manual/LayerBasedCollision.html
The documentation is really good. Just comment if you need further clarification.
I am having my player constantly drop downwards on the screen and when the player interact with other gameobjects, I want to destroy those gameobjects and want the player to carry on dropping.
But the moment the player hits the other gameobject, the gameobject does gets destroyed but the player stops dropping. Please help advice what I am doing wrong.
//Script attached to player:
//x-axis movement speed
public float playerMoveSpeed = 0.2f;
//how much force to act against the gravity
public float upForce = 9.0f;
//horizontal control
private float move;
// Update is called once per frame
void Update()
{
//player left right x-axis movement control
move = Input.GetAxis("Horizontal") * playerMoveSpeed;
transform.Translate(move, 0, 0);
}
void FixedUpdate()
{
//to fight against the gravity pull, slow it down
rigidbody.AddForce(Vector3.up * upForce);
}
//Script attached to gameObject to be destroyed on contact with player
void OnCollisionEnter(Collision col)
{
//as long as collide with player, kill object
if (col.gameObject.tag == "Player")
{
Destroy(gameObject);
}
}
First one should solve your problem, the second one might make your life easier :)
1.) Mark the objects as "Triggers" so that no real collision happens. That way your player should just fall through and keep its speed. You also need to use OnTriggerEnter instead of OnCollisionEnter
2.) If you dont really need "forces" but just want to move the player constantly you could just turn off gravity and set rigidbody.velocity manually like(i am assuming 2d here):
void FixedUpdate()
{
horizontalVelocity = Input.GetAxis("Horizontal") * playerMoveSpeed;
rigidbody.velocity = new Vector3(horizontalVelocity, verticalVelocity, 0.0f);
}
Just play around with values for verticalVelocity and horizontalVelocity untill it feels right.
Also note that if you move something in Update() you should probably multiply the translation with Time.deltaTime or your player will move faster on higher fps. FixedUpdate is called in fixed time intervalls so you dont need it there(thats why its called Fixed Update).