I'm currently trying to have a raycast detect the player caracter to have an event happen when a specific key is pressed here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class action: MonoBehaviour
{
public float dist;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
RaycastHit2D down = Physics2D.Raycast(transform.position, -Vector2.up, dist);
Debug.Log(transform.position);
if (Input.GetKeyDown(KeyCode.Z) == true && down.collider != null)
{
Debug.Log("hi");
}
}
}
I'm basicly trying to make a small raycast,which is why I place a distance instead of letting it go infinitely, and have it so if the raycast is triggered and the player presses z the event happens(which for now is the debug console), but all it does now is triggers whenever I press z no matter where the player caracter is. I tried drawing the raycast but I can't seem to make it work.
I think the reason for that is that the raycast is hitting the object containning the script it self and so the collider is allways non null try adding a LayerMask that differs from the GameObject's Layer
so it's something like this :
RaycastHit2D down = Physics2D.Raycast(transform.position, -Vector2.up,
dist , 1 << /*The Target's Layer*/);
You can find the layer in the up left corner of your inspector when you click on a GameObject
You have not provided a LayerMask on the down. The Raycast must be colliding with the player's Collider. In case you don't know what LayerMask is.
LayerMask can be used to detect Raycast that collides with only the objects with that layer on it.
The ayer Dropdown, on each GameObject, refers to the layer of the object as shown:
Head to the Unity Documentation for LayerMask for more details.
If you want make raycast when press Z will be good to do it in time press:
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Z)){
RaycastDown()
}
}
private void RaycastDown()
{
Debug.Log("Player position: " + transform.position);
RaycastHit2D hit = Physics2D.Raycast(transform.position,
Vector2.down, dist);
if(hit.collider != null){
Debug.Log($"Hit object: {hit.transform.name}" );
}
}
And about issue, make sure that hit object has a collider or collider is active.
Possibly problem in raycast direction. To check it, use Debug.DrawRay, it`s help you to visualize a ray which you draw
Related
I want a character that simply walks forward until it hits a wall, then it does a 180 degree spin and repeats the action.
Making him walk forward is easy, how do I program him hitting the wall?
My current code:
public class Enemy : MonoBehaviour
{
public float speed = 5;
public Vector3 userDirection = Vector3.forward;
// Update is called once per frame
void Update()
{
transform.position += userDirection * speed * Time.deltaTime;
}
}
You can use raycast to detect walls and avoid them.
Raycast in Unity is a Physics function that projects a Ray into the scene, returning a boolean value if a target was successfully hit
The following code is a simple demenstration of raycast. Distance determine how far you ray is casted and layermask determine which layers ray should detect. Therefore, you must put your walls in a Layer and sit this variable equal to that:
public float distance;
public LayerMask wallLayerMask;
public Vector3 userDirection = Vector3.forward;
void Update()
{
if (Physics.Raycast(transform.position, userDirection, distance, wallLayerMask))
{
// rotate, possibly:
// userDirection *= -1
}
transform.position += userDirection * speed * Time.deltaTime;
}
UPDATE
As stated in comments, you can also use colliders. To use colliders, you need to add another empty gameObject to your enemy, add a SphereCollider to it. Sphere Collider's radius determines how far you want to detect walls. Then add the following code to the second object:
// a reference to your enemy controller class
public Enemy enemy;
private void OnCollisionEnter(Collider other)
{
enemy.Rotate();
}
The OnCollisionEnter is called whenever an object, which has a collider, collides with our object. You need to assign a layer to this new object (wallCheck) and another to your walls. Then from Edit -> Project Settings -> Physics uncheck the collision of wallCheck with any layer other than your walls layer.
playerLayer = 11;
if (Input.GetMouseButtonDown(1))
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, crooshair.transform.position - transform.position, 100, ~playerLayer);
if (hit != null)
{
Interactable interactable = hit.collider.GetComponent<Interactable>();
if (interactable != null)
{
SetFocus(interactable);
}
}
else
Debug.Log("Nothing was hit");
}
Every time my player shoot a raycast it ends up hitting my player. The reason this is is because the raycast is starting inside of the player (which is what I want it to do) but it keeps detecting the player no matter what I do. I've used layers, tried to disable Queries start in colliders, and even starting the raycast from a little bit outside of the player but nothing works. When I try and offset the raycast from the player it sometimes works but that is only as long as you shoot in the direction that the offset is going. Please help.
Does your Player have any childed objects with a Collider that are not layered as playerLayer? Just to assure your layermask is setup correctly, I would advise assigning it in the inspector then invert it using the tilde.
public LayerMask playerLayer;
void Update()
{
if (Input.GetMouseButtonDown(1))
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, crooshair.transform.position, 100, ~playerLayer);
if (hit != null)
{
Interactable interactable = hit.collider.GetComponent<Interactable>();
if (interactable != null)
{
Debug.Log("Hit" + hit.collider.name);
}
}
}
}
If you are still unable to debug this with assigning the LayerMask in the inspector, if you could post your hierarchy it might help solve the issue.
So I have the map in my game split into different areas. Each are made into a separate array in the Area array. I am currently stuck on being able to click on the object. When the player clicks on the object in the game the part of the map that he clicks on should pop up a certain amount and when he clicks on another part that part should pop up and the other one should do back to its original position. I am currently having that object be destroyed when I click on it, but it won't even be selected in game.
using UnityEngine;
using System.Collections;
public class AreaSelection : MonoBehaviour {
public GameObject[] Areas;
void Start()
{
Areas = new GameObject[20];
}
void Update()
{
}
void OnMouseDown()
{
Destroy(this.gameObject);
}
"OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider."
-- Documentation
This means that you need a Collider on the GameObject that this script is attached to. The OnMouseDown will only trigger on the GameObject it's attached to. So if you have this script on some kind of manager that doesn't have a Collider or size or anything, you won't be able to use OnMouseDown. If you'd like to go another route, which I sort of recommend, you'd relocate the logic to the Update() method sort of like this:
(from a 2d-project of mine)
```
RaycastHit2D hit;
public LayerMask mask;
Vector2 mousePos;
GameObject selectedObject;
void Update() {
// If mouse left click is pressed
if (Input.GetMouseButtonDown(0)) {
mousePos = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
hit = Physics2D.Raycast(mousePos, Vector2.zero, mask);
if (hit.collider != null)
{
selectedObject = hit.collider.gameObject;
}
}
}
Note that you have to set the public LayerMask in the inspector to only hit the Objects you want to hit.
With this script you should be able to send a Raycast from your screen towards your mouse and, if it hits any GameObject with the selected Layer in the LayerMask it will put that object in SelectedObject (and once you have the gameobject you can do whatever you want with it).
I want to check if my ship/s collided and not some other objects.
So this is the script that i attached to a GameObject and the GameObject have box collider and Rigidbody. The box collider: Is Trigger set to on. And he size is 500 600 500. The Rigidbody i didn't change anything and Use Gravity is on.
When running the game i have many cloned gameobjects each one Tagged as "Sphere" but in the script when i check the tag name the collider is "Untagged".
What i'm trying to do is to make sure the collided object is a cloned spaceship.
using UnityEngine;
using System.Collections;
public class InvisibleWalls : MonoBehaviour {
public float smooth = 1f;
private Vector3 targetAngles;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerExit(Collider other)
{
if (other.tag == "Sphere")
{
targetAngles = other.transform.eulerAngles + 180f * Vector3.up;
other.transform.eulerAngles = Vector3.Lerp (other.transform.eulerAngles, targetAngles, smooth * Time.deltaTime);
}
}
}
This is the part where i'm trying to check and make that a ship is collided:
if (other.tag == "Sphere")
But when using break point it does stop on this line when the pbject collided but the other.tag the tag is "Untagged".
Screenshot showing the object spaceship cloned that is tagged as "Sphere"
And this screenshot showing the gameobject with the box collider and the rigidbody
From what i can gather,
You CrashLandedShip objects do not have colliders, adding colliders should work.
Also note that for triggers to work, One of the objects (the terrain or the ship) has to be a non-trigger (2 triggers will not cause a collision or trigger event)
So try this : Add a sphere collider to your CrashLandedShip_UpsideDown prefab and make sure they are not set with IsTrigger
The rest of your code looks fine.
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.