Unity 2D RaycastHit2D not detecting collision continuously? - c#

I am quite new to unity and recently i began a little project with raycasters but now I have encontered a problem:
I am tring to shoot a Raycast from the centre of the screen to my mouse with a distance:
This is what it looks like
The problem is that I want the distance of the Raycast to change dependion on wheter there is collision occuring but the collision detection is not continuous and the Raycast flickers between the collsion point and its normal distance:
Here it take the normal distance value
Here the distance value is the point of collsion
This is the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateRay : MonoBehaviour
{
[SerializeField] float distance = 10f;
Ray2D ray;
Vector2 mouseposition;
RaycastHit2D raycastHit2D;
void Update()
{
mouseposition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
private void FixedUpdate()
{
CheckColliders();
}
void CheckColliders()
{
int layermask = 1 << 8;
layermask = ~layermask;
RaycastHit2D raycastHit2D = Physics2D.Raycast(Vector2.zero, mouseposition, distance, layermask);
if (raycastHit2D.collider != null)
{
distance = raycastHit2D.distance;
new WaitForEndOfFrame();
}
else if (raycastHit2D.collider == null)
{
distance = 15;
}
Debug.DrawRay(Vector2.zero, mouseposition.normalized * distance, Color.yellow);
}
}
The thing that changes the values is the else if statement but without it the distance of the Raycast would change one and not return to its original distance.

Related

Raycast from the player position to the mouse position within range

I want to make a raycast from the player position to the mouse position but it should only have a certain range.
I have tried the following:
using UnityEngine;
public class Raycasting : MonoBehaviour
{
public GameManager gm;
Vector3 worldPosition;
public Transform player;
void FixedUpdate()
{
//Debug.Log(Camera.main.ScreenToWorldPoint(Input.mousePosition));
Debug.DrawLine(player.transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition), Color.green);
RaycastHit2D hit = Physics2D.Raycast(player.transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition), 10f);
if(hit.collider.tag == "Enemy")
{
Debug.Log (hit.collider.gameObject);
gm.Attack();
if (GameManager.enemyhealth <= 0)
{
Debug.Log("Enemy Died!");
Destroy(hit.transform.gameObject);
}
}
}
}
in Debug.DrawLine() it works exactly as I want it to — without the range —, but the raycast dosen't detect the enemies around it.
There is a trick to getting the ray end point to solve your problem. Just make sure your camera is orthographic. Also, by determining the enemy layer, detection problems are eliminated.
public GameObject player;
public LayerMask enemyLayer;
void Update()
{
var point = Camera.main.ScreenPointToRay(Input.mousePosition).GetPoint(1);
point.z = player.transform.position.z;
Debug.DrawLine(player.transform.position, point);
var enemy = Physics2D.Linecast(player.transform.position, point, enemyLayer.value);
if (enemy)
{
// do something...
}
}
Also, if you want to control the distance, please leave a comment.
Limited Distance to pointer
This algorithm limits the distance. For example, if you enter 5 for distance, the maximum magnitude will be 5, and if the mouse approaches below 5, it will set the mouse point to the maximum.
public GameObject player;
public LayerMask enemyLayer;
public float distance = 4.5f;
void FixedUpdate()
{
var point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
point.z = player.transform.position.z;
var clamp = Vector3.ClampMagnitude(point - player.transform.position, distance);
Debug.DrawLine(player.transform.position, player.transform.position+clamp);
var enemy = Physics2D.Linecast(player.transform.position, player.transform.position+clamp, enemyLayer.value);
if (enemy)
{
Debug.Log("Detected..");
}
}
Fixed Distance along pointer direction
This algorithm takes the mouse to the player and then adds the size. Mouse location does not affect size and distance is fixed.
public GameObject player;
public LayerMask enemyLayer;
public float distance = 4.5f;
void FixedUpdate()
{
var point = Camera.main.ScreenPointToRay(Input.mousePosition).GetPoint(1);
point.z = player.transform.position.z;
var direction = (point - player.transform.position).normalized;
Debug.DrawRay(player.transform.position, direction*distance);
var enemy = Physics2D.Raycast(player.transform.position, direction, distance, enemyLayer.value);
if (enemy)
{
Debug.Log("Detected..");
}
}

FPS Projectile firing from the wrong place

I'm trying to make a basic FPS game in Unity and I'm having an issue where the projectiles I shoot won't instantiate in the right place. From what I can tell, the projectile instantiates in roughly the same position relative to the player regardless of where I look (that position being a little to the left of the starting angle of the player).
Here's a 20 second video demonstration of what I'm talking about.
https://youtu.be/WLVuqUtMqd0
Even when I'm facing the exact opposite direction of where the projectile usually instantiates it still spawns in the same place, which means the projectile ends up spawning behind the player and hitting the player.
I tried using Debug.DrawRay() to see if maybe the firepoint itself is wrong (which would be shown by the ray starting somewhere other than the gun barrel). However it seems like the starting point of the ray is correct every time.
I'm not sure if this is related to the issue above, but I have noticed that the ray direction is wrong if I'm looking a little below the horizon. It seems like the projectile's direction is correct regardless though.
Ray directions when looking slightly above the horizon vs. lower
Here's my code for intantiating/shooting the projectile. I think the most relevant parts are probably shootProjectile() and instantiateProjectile(). This script is attached to the player character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting : MonoBehaviour
{
public Camera cam;
public GameObject projectile;
public Transform firePoint;//firePoint is set to the end of the barrel.
public float projectileSpeed = 40;
//private var ray;
private Vector3 destination;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//var ray = cam.ViewportPointToRay(new Vector3(0.5f,0.5f,0));
//Debug.DrawRay(ray.origin, ray.direction);
if(Input.GetButtonDown("Fire1")) {
//player is shooting
ShootProjectile();
}
}
void ShootProjectile() {
Ray ray1 = cam.ScreenPointToRay(Input.mousePosition);
//Debug.Log(ray.direction);
RaycastHit hit;
if(Physics.Raycast(ray1, out hit))//checking whether the player is going to hit something
{
destination = hit.point;
}
else {
destination = ray1.GetPoint(1000);
}
Debug.DrawRay(firePoint.position, destination, Color.white, 10f);
InstantiateProjectile(firePoint);
}
void InstantiateProjectile(Transform firePoint) {
var projectileObj = Instantiate (projectile, firePoint.position, Quaternion.identity) as GameObject;//projectile is instantiated
projectileObj.GetComponent<Rigidbody>().velocity = (destination - firePoint.position).normalized * projectileSpeed;//projectile is set in motion
}
}
Here's the location of firePoint.
firePoint (i.e. where the projectile should instantiate)
I would appreciate any help on this, as I've been trying to fix it (on and off) for several days, and really have no idea what the problem is.
Edit: Here's my player movement script(s) as well. The first one is PlayerController.cs, and it converts the player's inputs into the appropriate movement vectors and camera rotation. It then calls methods from PlayerMotor.cs, which actually performs the movements.
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
[SerializeField]
public float speed = 10f;
[SerializeField]
private float lookSens = 3f;
private PlayerMotor motor;
void Start() {
motor = GetComponent<PlayerMotor>();
//Debug.Log("PlayerControllerStart");
Cursor.lockState = CursorLockMode.Locked;
}
void Update() {
//Debug.Log("PlayerControllerUpdate");
//calculate movement velocity as 3D vector.
float xMov = Input.GetAxisRaw("Horizontal");
float zMov = Input.GetAxisRaw("Vertical");
Vector3 movHorizontal = transform.right * xMov;
Vector3 movVertical = transform.forward * zMov;
Vector3 velocity = (movHorizontal + movVertical).normalized * speed;
motor.move(velocity);
//speed*=(float)1.15;
//rotation
float yRot = Input.GetAxisRaw("Mouse X");
Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSens;
motor.rotate(rotation);
float xRot = Input.GetAxisRaw("Mouse Y");
Vector3 cameraRotation = new Vector3 (xRot, 0f, 0f) * lookSens;
motor.rotateCamera(cameraRotation);
if (Input.GetKeyDown(KeyCode.Space) == true && motor.isGrounded()) {
motor.canJump=true;
}
if (Input.GetKey(KeyCode.W) == true) {
motor.accel=true;
}
else{
motor.accel=false;
}
}
}
PlayerMotor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{
[SerializeField]
private Camera cam;
private Vector3 velocity = Vector3.zero;
private Vector3 rotation = Vector3.zero;
private Vector3 cameraRotation = Vector3.zero;
private Vector3 jumpVector = new Vector3 (0f, 5f, 0f);
private PlayerController pc;
private Rigidbody rb;
public bool canJump;
public bool accel;
public float acceleration;
int jumpCount;
void Start() {
rb = GetComponent<Rigidbody>();
pc = GetComponent<PlayerController>();
canJump=false;
jumpCount=0;
accel=false;
//acceleration = 1.0;
//distToGround = collider.bounds.extents.y;
//Debug.Log("PlayerMotorStart");
}
//sets velocity to a given movement vector.
public void move(Vector3 _velocity) {
velocity = _velocity;
}
public void rotate(Vector3 _rotation) {
rotation = _rotation;
}
public void rotateCamera(Vector3 _cameraRotation) {
cameraRotation = _cameraRotation;
}
public bool isGrounded() {
return Physics.Raycast(transform.position, -Vector3.up, (float)2.5);
}
public void jump() {
rb.AddForce(transform.up * 250f);
//Debug.Log("Jump"+jumpCount);
jumpCount++;
canJump=false;
}
void FixedUpdate() {
performMovement();
performRotation();
if (canJump) {
jump();
}
//Debug.Log("PlayerMotorUpdate");
if(accel&&pc.speed<20f&&isGrounded())
{
//Debug.Log("W Pressed");
pc.speed*=(float)1.005;
}
else if(!accel) {
pc.speed=7f;
}
}
void performMovement() {
if(velocity != Vector3.zero) {
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
//Debug.Log("Movement");
}
}
void performRotation() {
rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
if(cam != null) {
cam.transform.Rotate(-cameraRotation);
}
}
}
Here are some pictures of my projectile prefab as well.
To solve one first confusion: The method Debug.DrawRay takes as paramters
a start position
a ray direction(!)
You are passing in another position which is not what you want.
This might only work "accidentally" as long as you stand on 0,0,0 so maybe it wasn't that notable but the debt ray definitely points into a wrong direction.
Rather do e.g.
Debug.DrawRay(firePoint.position, destination - firePoint.position, Color.white, 10f);
Or instead rather use Debug.DrawLine which rather actually takes
start position
end position
Then you don't need to calculate the direction first
Debug.DrawLine(firePoint.position, destination, Color.white, 10f);
Then I suspect the following is happening: The spawned projectileObj actually is placed correctly but it is the visuals inside that projectile prefab that have a local offset against the parent prefab root.
Since you always spawn the projectile in world rotation Quaternion.identity that offset stays the same no matter where you look.
I guess a simple fix would already be to also apply the same rotation like
var projectileObj = Instantiate (projectile, firePoint.position, firePoint.rotation);

LineRenderer not drawing where Mouse clicks

Following a tutorial, I'm trying to use a grappling gun mechanic that utilizes a spring joint and Line Renderer.
I've got the line drawing upon mouseclick, but the end of the line is not drawing where the user clicks.
It looks like this:
Can anyone kind of help me out as to why it's not working? Here's the (wonky) project in action-
https://i.imgur.com/IuMsEsQ.mp4
Grappling gun code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrapplingGun : MonoBehaviour
{
private LineRenderer lr;
private Vector3 grapplePoint; //where we grapple to
public LayerMask whatIsGrappable;
public Transform gunTip;
public Transform cam;
public Transform player;
private float maxDistance = 100f;
private SpringJoint joint;
void Awake()
{
lr = GetComponent<LineRenderer>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StartGrapple();
}
else if (Input.GetMouseButtonUp(0))
{
StopGrapple();
}
}
void LateUpdate()
{
DrawRope();
}
void StartGrapple()
{
RaycastHit hit;
if (Physics.Raycast(cam.position, cam.forward, out hit, maxDistance, whatIsGrappable))
//if (Physics.Raycast(transform.position, Vector3.forward, out hit, maxDistance, whatIsGrappable))
{
grapplePoint = hit.point;
joint = player.gameObject.AddComponent<SpringJoint>();
joint.autoConfigureConnectedAnchor = false;
joint.connectedAnchor = grapplePoint;
float distanceFromPoint = Vector3.Distance(player.position, grapplePoint);
joint.maxDistance = distanceFromPoint * 0.8f;
joint.minDistance = distanceFromPoint * 0.25f;
joint.spring = 4.5f;
joint.damper = 7f;
joint.massScale = 4.5f;
lr.positionCount = 2;
}
}
void DrawRope()
{
//If not grappling, don't draw anything
if (!joint) return;
lr.SetPosition(0, gunTip.position);
lr.SetPosition(1, grapplePoint);
}
void StopGrapple()
{
lr.positionCount = 0;
Destroy(joint);
}
}
Thank you.
The underlying issue is your raycast. the second parameter is the direction of the ray, which you have as the camera direction. Currently your ray is pointing forward from the camera at all times as a result.
What you can do is use Camera.ScreenPointToRay to give a ray to cast along to give you a 3d mouse position to cast to, then use your current raycast but replace the second parameter with the direction from the player to the point hit by the raycast from the function mentioned before
Ray ray = Camera.ScreenPointToRay(Input.mousePosition);
Physics.Raycast(ray, out RaycastHit hit);
if (Physics.Raycast(transform.position, (hit.point - transform.position).normalized, out hit, maxDistance, whatIsGrappable)) {
// Your code here...
}

How to launch an instantiated object in a certain direction from the center of the screen based on the mouse pointer position?

I am creating a simple game where you are locked in the center of the screen and must shoot things as they move toward you. The problem I am currently facing is that I can not launch a bullet in the direction of my mouse cursor. Currently, my code looks like this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour {
PlayerScript playerScript;
public float xVel;
public float yVel;
public float direction;
private void Awake()
{
playerScript = FindObjectOfType<PlayerScript>();
//playerScript.AngleDeg is the direction the player is facing (based on mouse cursor)
transform.rotation = Quaternion.Euler(0, 0, playerScript.AngleDeg);
direction = transform.rotation.z;
//from the unit circle (x = cos(theta), y = sin(theta)
xVel = Mathf.Cos(direction * Mathf.PI);
yVel = Mathf.Sin(direction * Mathf.PI);
}
void Update () {
transform.position += new Vector3(xVel,yVel,0);
}
}
currently, when I run the code, the bullet shoots at an angle which is at the direction that is correct when the player is orientated sideways, but when orientated vertically is a full 45 degrees off.
Attach this as a component to your instantiated bullet object and it should work.
Transform playerTransform;
float bulletSpeed;
Vector3 directionToShoot
void Start()
{
playerTransform = FindObjectOfType<PlayerScript>().gameObject.transform;
bulletSpeed = 3f;
//Direction for shooting
directionToShoot = playerTransform.forward - Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void Update()
{
//shoot
transform.Translate(directionToShoot * bulletSpeed * Time.deltaTime);
}

Raycast Mouse Controller ,difference between player and mouse point(Survival Shooter Tutorial)

I'm trying to understand the code of the PlayerController made by Unity(Survival Shooter Tutorial).I understand everything, except the reason, why they wrote the difference between FLOOR-POINT(where the mouse is directed) and the player (transform position).I tried to write only the floor point without the player position and its worked.Why they wrote that? Maybe someone passed this tutorial and can help me with that?
Unity tutorial : https://unity3d.com/learn/tutorials/projects/survival-shooter/player-character?playlist=17144
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float speed= 6f;
Vector3 movement;
Animator anim;
Rigidbody playerRigidbody;
int floorMask;
float camRayLength=100f;
void Awake()
{
floorMask = LayerMask.GetMask("Floor");
anim = GetComponent<Animator> ();
playerRigidbody = GetComponent<Rigidbody> ();
}
void FixedUpdate()
{
float v = Input.GetAxisRaw ("Vertical");
float h = Input.GetAxisRaw ("Horizontal");
Move (h, v);
Turning ();
Animating(h,v);
}
void Move(float h,float v)
{
movement.Set (h,0f,v);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition (transform.position+movement);
}
void Turning()
{
Ray camRay = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit floorHit;
if(Physics.Raycast(camRay,out floorHit,camRayLength,floorMask))
{
Vector3 playerToMouse = floorHit.point-transform.position ;********
playerToMouse.y = 0f;
Quaternion newRotation = Quaternion.LookRotation (playerToMouse);
playerRigidbody.MoveRotation (newRotation);
}
}
void Animating(float h,float v)
{
bool wakling = h != 0f || v != 0f;
anim.SetBool("IsWalking",wakling);
}
}
Raycasts need a direction, which is usually given as (someVector - someOtherVector). The result from this subtraction is a new vector that takes someVector as the origin point. In your case, the relative vector from the mouse to the player probably never changes, so the subtraction seems not needed. However, it is good practice to use the subtraction of two vectors as direction.

Categories

Resources