I use Cinemachine camera collider for my project. This basically means that my entire game is inside a polygon collider.
With the following script my line renderer collides instantly with this camera collider:
[SerializeField] private float defDistanceRay = 10f;
public Transform laserFirePoint;
public LineRenderer m_linerenderer;
Transform m_transform;
private void Awake()
{
m_transform = GetComponent<Transform>();
}
private void Update()
{
ShootLaser();
}
void ShootLaser()
{
if(Physics2D.Raycast(m_transform.position, transform.right))
{
RaycastHit2D _hit = Physics2D.Raycast(m_transform.position, transform.right);
Draw2DRay(laserFirePoint.position, _hit.point);
Debug.Log(_hit.collider.name);
}
else
{
Draw2DRay(laserFirePoint.position, laserFirePoint.transform.right * defDistanceRay);
}
}
void Draw2DRay(Vector2 startPos, Vector2 endPos)
{
m_linerenderer.SetPosition(0, startPos);
m_linerenderer.SetPosition(1, endPos);
}
Can I somehow bypass this collider by setting a "tag" on it and in my code ignore colliders with that specific tag?
Anyone have a good work around for this issue?
EDIT: Forgot to mention Im looking at: https://docs.unity3d.com/ScriptReference/Physics2D.IgnoreCollision.html
But that takes in 2 colliders I just want to ignore 1.
EDIT2: I tried to set the Cinemachine camera polygon collider as a Layermask and ignore it with the following code:
public LayerMask layerMask;
void ShootLaser()
{
if (Physics2D.Raycast(m_transform.position, transform.right))
{
RaycastHit2D _hit = Physics2D.Raycast(m_transform.position, transform.right, layerMask);
Draw2DRay(laserFirePoint.position, _hit.point);
Debug.Log(_hit.collider.name);
}
else
{
Draw2DRay(laserFirePoint.position, laserFirePoint.transform.right * defDistanceRay);
}
}
EDIT 3:
RaycastHit2D _hit = Physics2D.Raycast(m_transform.position, transform.right, defDistanceRay, layerMask);
I added defDistanceRay into the Raycast and now it dosent seem to collide with the camera collider atleast! Super buggy but atleast i bypass the Cinemachine camera collider!
Related
I have been working on a 2d top down rpg game and I have added walking animations etc, I want to stop the player from doing a walking animation when they hit a wall and currently I have a box collider with a ray cast, the ray cast originally hit the player box collider when walking down but after using a layermask this has stopped, however while walking left and right work perfectly two issues occur that I cannot seem to fix. First, when walking up or down into a tilemap that is on the collision layer (this tilemap has tilemap collider which will stop the player from walking through them) the animation still plays, and second the player will only collide once instead of repeatedly when hitting the tilemap when two tiles are placed back to back, here is my code for collision, the tiles that are for collision are on layer 6.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
public float moveSpeed;
private Animator ani;
private bool isMoving;
private Vector2 lastMove;
private Rigidbody2D body;
private Vector2 movement;
private LayerMask wallLayer = 1 << 6;
// Start is called before the first frame update
void Start()
{
body = GetComponent<Rigidbody2D>();
ani = GetComponent<Animator>();
movement = Vector2.zero;
isMoving = false;
}
// Update is called once per frame
void Update() {
isMoving = false;
movement = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
RaycastHit2D ray = Physics2D.Raycast(body.position, movement, 0.6f, wallLayer);
if((movement.x != 0f || movement.y != 0f) && !(ray && ray.collider.tag == "wall")) {
isMoving = true;
lastMove = movement;
}
ani.SetFloat("MoveX", movement.x);
ani.SetFloat("MoveY", movement.y);
ani.SetFloat("LastX", lastMove.x);
ani.SetFloat("LastY", lastMove.y);
ani.SetBool("IsMoving", isMoving);
}
void FixedUpdate() {
body.MovePosition(body.position + movement * moveSpeed * Time.deltaTime);
}
}
The code looks fine. Most likely, the issue is with your configuration of the AnimatorController.
Do you have transitions in place for (for example) coming from the walk animation back to idle?
I've been trying to set an enemy on a patrol path while not chasing my player character. I want to use RayCast so that the enemy can spot the player and begin to chase the player. It functions as I intended. However, even when there's an obstacle or wall between us, or when I approach from behind, the enemy 'sees' my player and starts to chase me. It seems to ignore the Raycast, and instead focuses on the proximity to the enemy.
Enemy spotting player through wall
public class EnemyController : MonoBehaviour
{
private NavMeshAgent enemy;// assaign navmesh agent
private Transform playerTarget;// reference to player's position
private float attackRadius = 10.0f; // radius where enemy will spot player
public Transform[] destinationPoints;// array of points for enemy to patrol
private int currentDestination;// reference to current position
public bool canSeePlayer = false;
private Ray enemyEyes;
public RaycastHit hitData;
private void Awake()
{
enemy = GetComponent<NavMeshAgent>();
playerTarget = GameObject.Find("Player").GetComponent<Transform>();
enemyEyes = new Ray(transform.position, transform.forward);
}
private void Start()
{
Physics.Raycast(enemyEyes, attackRadius);
}
private void Update()
{
Lurk();
Debug.DrawRay(transform.position, transform.forward * attackRadius);
}
void Lurk()
{
Debug.Log("Lurking");
float distanceToPlayer = Vector3.Distance(transform.position, playerTarget.position);
//check if raycast hits playerLayer and enemy is close enough to attack
if (Physics.Raycast(enemyEyes, out hitData, attackRadius * 2, layerMask: ~6) && distanceToPlayer < attackRadius)
{
Debug.Log("You hit " + hitData.collider.gameObject.name);
ChasePlayer();
}
else
{
canSeePlayer = false;
Patrol();
}
}
void Patrol()
{
if (!canSeePlayer && enemy.remainingDistance < 0.5f)
{
enemy.destination = destinationPoints[currentDestination].position;
UpdateCurrentPoint();
}
}
void UpdateCurrentPoint()
{
if (currentDestination == destinationPoints.Length - 1)
{
currentDestination = 0;
}
else
{
currentDestination++;
}
}
void ChasePlayer()
{
StartCoroutine(ChaseTime());
canSeePlayer = true;
transform.LookAt(playerTarget.position);
Vector3 moveTo = Vector3.MoveTowards(transform.position, playerTarget.position, attackRadius);
enemy.SetDestination(moveTo);
}
IEnumerator ChaseTime()
{
Debug.Log("Chasing");
yield return new WaitForSeconds(10.0f);
if (!Physics.Raycast(enemyEyes, out hitData, attackRadius * 2, layerMask: ~6))
{
canSeePlayer = false;
Debug.Log("Lurking");
Lurk();
}
}
}
I've removed the tilde "~" for the layermask, but then the enemy doesn't ever see the player.
I've initialised and set a layer mask reference to the 'playerLayer' and used it in place of "layermask: ~6", to no avail.
I've used the int reference to the Player layer, to no avail.
I've used bitwise operator to reference the player layer, to no avail.
I've removed the distanceToPlayer conditional, but the enemy doesn't see the player.
I've adjusted the length of the Ray but if it's ever shorter than the attack radius, it doesn't work.
I don't understand why you need a layer mask. If you want the Raycast to hit something in front of the player then you must include all layers in the Raycast.
What you need to do is remove the layermask from Raycast and in the if statement check if the out hit collider is on Player and if the player is in attack radius. Here is a simple outline
If(raycast)
{
if(hit.collider.gameobject==player && player in proximity)
{
Then can see is true
}
}
You can give this article on Unity Raycast a read to understand more on layermask.
regarding player detection through a wall,I would try adding an extra if statement in the Lurk method.This condition would check if the raycast is touching the wall, if so, do not proceed with the method, if not, continue. Sorry for giving the code in this form but I don't have access to a computer and the phone doesn't want to cooperate
enter image description here
I need some help with Unity.
I try to make an object to detect a collision, but for some reason, the OnColissionEnter function is not called.
Both my objects have rigidBody and Box Collider attached, isTrigger is unenabled as well.
I supposed it's because I have AddForce in my code, but I am not sure. Have anybody a clue what is going wrong there?
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Cuplat2 : MonoBehaviour
{
public Vector3 Target = new Vector3();
private Rigidbody rb;
public float thrust;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Vector3 NewPosition = transform.position + Target;
Vector3 Position = transform.position;
if (transform.position.x < Target.x)
{
rb.AddForce(transform.position * thrust);
}
else
{
//rb.isKinematic = true;
}
}
public void OnCollisionEnter(Collision collision)
{
Debug.Log("stop");
if (collision.gameObject.name == "Cupla T2")
{
Debug.Log("stop");
}
}
}
One of your rigidbodies has to have isKinematic = false;
If it's not possible in your case I see they have workaround for that:
https://forum.unity.com/threads/collision-detection-for-kinematic-rigidbodies.885778/
Other option would be that the collision is disabled in collision layer mask, but that would cause objects to pass trough each other (I believe that's not the case)
Third option: your rigidbody does not have collider (maybe collider is on parent, has enabled = false, or inactive game object?)
Fourth option: If your object moves very fast you should change Collision Detection Mode to Continous Dynamic
How about the collision layer matrix? Go into Edit > Project Settings, then select the Physics. Check if the layers set to the GameObjects are actually having any collision between them. Collision Layer matrix
Sorry for the bad formatting I don't know how to do this. I'm using 2020.3.21f1 and following a tutorial and when the enemy circle hits the player he doesn't take damage. when they collide they don't overlap at all, but the Debug.log isn't registering either so I think that the circle collider 2D is the problem. the enemy sprite still moves towards the player when it is in range. another problem (that will turn into a feature if I cant figure out how to change it) is that when the enemy collides with the player and the player pushes it goes the direction it was pushed until it runs into something Here's the tutorial I'm following
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy: MonoBehaviour
{
public float speed = 3f;
private Transform target;
[SerializeField] private float attackDamage = -10f;
private void Update(){
if (target != null){
float step = speed*Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, target.position, step);
}
}
private void OnCollision(Collision2D other){
if (other.gameObject.tag == "player"){
Debug.Log("hit");
other.gameObject.GetComponent<PlayerHealth>().UpdateHealth(attackDamage);
}
}
private void OnTriggerEnter2D(Collider2D other) {
if(other.gameObject.tag == "Player"){
target = other.transform;
Debug.Log(target);
}
}
private void OnTriggerExit2D(Collider2D other) {
if(other.gameObject.tag == "Player"){
target = null;
Debug.Log(target);
}
}
}
The sprite by itself wont detect collision, you need to add a box collider for that. If you add that component to the player then modify your code to include those collision detections then it should function ad intended.:)
-TheHackintoshProgrammer;
I am having an issue with my character which is not jumping at all. I am new to Unity, but I made sure to apply the script to the player and adjust the speed, I did not touch the Rigidbody 2D. If any one can help me figure our the issue, it will be much appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
public float moveSpeed;
public float jumpSpeed;
public bool grounded = false;
private Rigidbody2D rb;
void Start() {
rb = GetComponent<Rigidbody2D>();
}
void Update () {
transform.Translate (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0, 0);
if (grounded)
{
if (Input.GetButtonDown ("Jump"))
{
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
}
void OnCollisionEnter2D (Collision2D coll){
if (coll.transform.tag == "Ground")
{
grounded = true;
}
}
}
Inspector window of the Player GameObject
Inspector window of the Ground GameObject
Your problem is you haven't tag the Ground GameObject as so. So in the OnCollisionEnter2D the character detects the collision, but the if (coll.transform.tag == "Ground") will never be true. So it means the character can't be grounded
Since to be grounded is the first condition to check if the player pressed the Jump key. It is impossible it will ever jump
if (grounded)
{
if (Input.GetButtonDown ("Jump"))
{
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
To solve this issue: You need to tag the Ground GameObject as so. In case you are not sure how to do that, on the Tag menu, create (if it doesnt exist already) a new tag called Ground. Then assign in that same menu the Ground Tag to the Ground GameObject. Here you can learn how in case you need a visual reference:
https://docs.unity3d.com/Manual/Tags.html
Edit: You can try this script if everything fails. It should work. I used my self some time ago, I cleaned the code so to leave only what you need to move the character in the x and y axis. Hope to have included everything you need:
public class CharacterController2D : MonoBehaviour {
// LayerMask to determine what is considered ground for the player
public LayerMask whatIsGround;
// Transform just below feet for checking if player is grounded
public Transform groundCheck;
// store references to components on the gameObject
Transform transform;
Rigidbody2D rigidbody;
bool isGrounded = false;
float vy;
float vx;
public float jumpForce = 600f;
void Awake () {
transform = GetComponent<Transform> ();
rigidbody = GetComponent<Rigidbody2D> ();
}
void Update()
{
// determine horizontal velocity change based on the horizontal input
vx = Input.GetAxisRaw ("Horizontal");
vy = rigidbody.velocity.y;
// Check to see if character is grounded by raycasting from the middle of the player
// down to the groundCheck position and see if collected with gameobjects on the
// whatIsGround layer
isGrounded = Physics2D.Linecast(transform.position, groundCheck.position, whatIsGround);
if(isGrounded && Input.GetButtonDown("Jump")) // If grounded AND jump button pressed, then allow the player to jump
{
DoJump();
}
// Change the actual velocity on the rigidbody
rigidbody.velocity = new Vector2(_vx * MoveSpeed, _vy);
}
//Make the player jump
void DoJump()
{
// reset current vertical motion to 0 prior to jump
vy = 0f;
// add a force in the up direction
rigidbody.AddForce (new Vector2 (0, jumpForce));
}
}
So things to take into account:
Instead of tag the ground, you create a layer with everything you
consider ground. That will include possible platforms the character
may jump over. Pass as a parameter this layer to the script in the
inspector
You need to place an empty GameObject in the feet of the character.
You will drag and drop that GameObject in the editor onto the
groundCheck public variable.
Instead of OnTriggerEnter, you will use Physics2D.Linecast which
will trave a line from the position of the character to under its
feet (where you should have place the Transform mentioned in the
previous step) and if in the middle there is an element of the
groundLayer, it means the character will be grounded.
Let me know if anything is not clear or if you find some bug.
As mentioned your problem is deffinetly that your missing to tag your ground object :)
A tip: What i like to do when i have problems like this is to use the unitys Debug.Log() to locate where the problem is it. It will let you know easily in the console what code is run and which is not. Try do the following:
void Update () {
transform.Translate (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0, 0);
if (grounded)
{
Debug.Log("Is grounded");
if (Input.GetButtonDown ("Jump"))
{
Debug.Log("Jump clicked");
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
}