Line Casting: GameObject Face End Point of Ray - c#

I'm trying to make the enemy object face the end of the line cast. The code I have locks the ray onto the player when detected properly. My problem here is that my enemy sprite is a grandchild of the Rigidbody2D and I'm using eulerAngles to change the sprites direction. Here is the code I have:
using UnityEngine;
public class PlayerDetection : MonoBehaviour
{
public Transform origin, end, player;
public float radarSpd;
public bool playerDetected;
public static bool playerIsDetected;
private int playerLayer = 1 << 8;
private Rigidbody2D enemyRb;
private Vector3 facePlayer;
private void Start()
{
enemyRb = GetComponentInParent<Rigidbody2D>();
playerIsDetected = false;
}
private void Update()
{
PlayerDetector();
if (playerDetected == false)
{
Radar();
}
else { PlayerIsDetected(); }
}
void PlayerDetector()
{
Debug.DrawLine(origin.position, end.position, Color.red);
playerDetected = Physics2D.Linecast(origin.position, end.position, playerLayer);
}
void Radar()
{
end.RotateAround(origin.position, Vector3.forward, radarSpd * Time.deltaTime);
}
void PlayersPosition()
{
facePlayer = player.position - enemyRb.transform.GetChild(0).GetChild(0).position;
float enemyRot = Mathf.Atan2(facePlayer.y, facePlayer.x) * Mathf.Rad2Deg;
enemyRb.transform.GetChild(0).GetChild(0).eulerAngles = new Vector3(0, 0, enemyRot);
}
void PlayerIsDetected()
{
if(playerDetected == true)
{
playerIsDetected = true;
end.position = player.position;
PlayersPosition();
}
}
}
The main focus for this code that I need help is here:
void PlayersPosition()
{
facePlayer = player.position - enemyRb.transform.GetChild(0).GetChild(0).position;
float enemyRot = Mathf.Atan2(facePlayer.y, facePlayer.x) * Mathf.Rad2Deg;
enemyRb.transform.GetChild(0).GetChild(0).eulerAngles = new Vector3(0, 0, enemyRot);
}
The enemy does not face the player at all and doesn't seem to rotate much at all as the player moves around the screen.
I've tried applying a rotationSpeed variable and multiplied it by enemyRot multiplied by Time.deltaTime but didn't work either.
enemyRb.transform.GetChild(0).GetChild(0).eulerAngles = new Vector3(0, 0, enemyRot * rotSpd * Time.deltaTime);
I've been stuck on this for a week now and really need some help resolving this issue! So how can I achieve my desired rotation by use of eulerAngles?

Turned out that I was doing too much math. Here is the solution:
Edit: My enemy is facing in an upward position. This code works on that scale.
void PlayersPosition()
{
facePlayer = player.position - enemyRb.transform.GetChild(0).GetChild(0).position;
enemyRb.transform.GetChild(0).GetChild(0).up = -facePlayer;
}

Related

Unity - how to make an object face the direction of its movement?

I'm trying to make a character prefab face the direction in which its moving. I've tired all sorts of things, with and without rigidbodies but nothing seems to work. The thing is, it does actually face in the correct direction. But once its there, it starts to rotate the whole prefab and it goes down into the ground.
The character holds a 3D shield, and goes towards a tower. So once it reaches the tower it raises the shield which in turn rotates the whole character down into the ground. I would like it to just rotate in the X and Z axis and never change the Y axis.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BlockRadar : MonoBehaviour
{
// Start is called before the first frame update
public Transform Tower;
private GameObject[] multipleBlocks;
public Transform closestBlock;
public bool blockContact;
public float currentDistance;
public float stopDistance;
public Animator animator;
public int damage;
public float attackspeed;
private float canAttack;
public float moveSpeed = 5f;
public Vector3 distance;
private Vector3 movement;
void Start()
{
closestBlock = null;
blockContact = false;
}
// Update is called once per frame
void Update()
{
Vector3 pos = transform.position;
pos.y = 0;
pos.x = 0;
transform.position = pos;
closestBlock = getClosestBlock();
closestBlock.gameObject.GetComponent<Renderer>().material.color = new Color(1, 0.7f, 0, 1);
Vector3 direction = closestBlock.position - transform.position;
direction.Normalize();
movement = direction;
float dist = Vector3.Distance(closestBlock.position, transform.position);
if (dist <= 1.5f)
{
{
blockContact = true;
animator.SetBool("Moving", false);
Debug.Log("Now touching block");
if (attackspeed <= canAttack)
{
Attack();
canAttack = 0f;
}
else
{
canAttack += Time.deltaTime;
}
}
}
if (dist > 1.5f)
{
transform.forward = movement;
blockContact = false;
Debug.Log("Lost contact with block");
animator.SetBool("Moving", true);
moveCharacter(movement);
}
}
public void Attack()
{
Debug.Log("ATTACKING!");
Damage(closestBlock.transform);
animator.SetTrigger("Attacking");
}
private void FixedUpdate()
{
}
void moveCharacter(Vector3 direction)
{
transform.Translate(direction * moveSpeed * Time.deltaTime, Space.World);
}
void DistanceToTower()
{
if (Tower)
{
float dist = Vector3.Distance(Tower.position, transform.position);
if (dist <= 1)
{
{
blockContact = true;
Debug.Log("Now touching block");
if (attackspeed <= canAttack)
{
Attack();
canAttack = 0f;
}
else
{
canAttack += Time.deltaTime;
}
}
}
}
}
//when the object carrying this script is destroyed
private void OnDestroy()
{
if (closestBlock !=null)
{
closestBlock.gameObject.GetComponent<Renderer>().material.color = new Color(0, 0, 0, 0);
}
}
public Transform getClosestBlock()
{
multipleBlocks = GameObject.FindGameObjectsWithTag("Block");
float closestDistance = Mathf.Infinity;
Transform trans = null;
//finds all blocks in the scene
foreach (GameObject go in multipleBlocks)
{
currentDistance = Vector3.Distance(transform.position, go.transform.position);
if (currentDistance < closestDistance)
{
closestDistance = currentDistance;
trans = go.transform;
}
}
return trans;
}
void Damage(Transform block)
{
Tower_Stats e = block.GetComponent<Tower_Stats>();
if (e != null)
{
e.TakeDamage(damage);
}
}
}
I would be really, really grateful for any help. As I said before I used to have rigidbodies on the character, but I removed them since I thought maybe they were the fault. But doesnt seem like it. One other thing I've noticed is that when the prefab is instantiated, its children doesnt have the correct position values. Not sure why. But if that could be a clue I just thought I'd let you know.

Unity 3D Aerial movement and jumping problem

Aerial Movement Problem
I've followed a few tutorials and I've set up a decent base for a game, - basic player movement, entity animation, health, HUD UI, etc. - but I wanted to make the movement a bit smoother, less snappy, more physics-based, you get the gist. I made it a bit better and it definitely meets all the requirements for terrain-based movement (i.e: movement across physical surfaces - while the player is on the ground), but I want jumping to be a bit more dynamic, and I know what I want to do but I'm having trouble doing it.
Here's the issue:
If the player moves (regardless of whether sprintActive is toggled or not) and they jump after moving, the player gains speed in the air way too fast, and they can't move in any direction other than forward (relative to their rotation).
Here's the objective:
I set it up so the velocity is simply redirected to whatever direction is forward from the playerRB, but I think I would prefer if the velocity didn't immediately change direction, but rather gradually curve as the player tries to move a certain direction? I know I may be asking for a lot, but some advice on how to do this, or if I should try a different approach, would be very much appreciated.
Code used:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RFPSPlayerMovement : MonoBehaviour
{
public float speedForce;
public float jumpForce;
public float diveForce;
public Transform groundCheck;
public float groundDistance = 0.25f;
public LayerMask groundMask;
private Transform playerBody;
private Rigidbody playerRB;
private bool isGrounded;
private bool sprintActive = false;
private bool delay = false;
private float lateralSpeed;
private Vector3 velocity;
float xMov, zMov;
float xSpeed, zSpeed;
IEnumerator DelayTimer(float duration)
{
delay = true;
yield return new WaitForSeconds(duration);
delay = false;
}
void Start()
{
playerBody = GetComponent<Transform>();
playerRB = GetComponent<Rigidbody>();
}
void Update()
{
xMov = Input.GetAxisRaw("Horizontal") * Time.deltaTime;
zMov = Input.GetAxisRaw("Vertical") * Time.deltaTime;
if(Input.GetKey(KeyCode.LeftShift))
{
sprintActive = true;
}
else
{
sprintActive = false;
}
if(Input.GetKey(KeyCode.W))
{
Movement(0, speedForce);
}
if(Input.GetKey(KeyCode.S))
{
Movement(0, -speedForce);
}
if(Input.GetKey(KeyCode.A))
{
Movement(-speedForce, 0);
}
if(Input.GetKey(KeyCode.D))
{
Movement(speedForce, 0);
}
if(Input.GetKey(KeyCode.Space))
{
if(delay == false)
{
if(isGrounded)
{
StartCoroutine(DelayTimer(0.05f));
Jump(jumpForce);
}
}
}
}
void FixedUpdate()
{
velocity = playerRB.velocity;
lateralSpeed = new Vector2(playerRB.velocity.x, playerRB.velocity.z).magnitude;
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if(isGrounded)
{
velocity = new Vector3(
xMov + (float) (playerRB.velocity.x * 0.90),
playerRB.velocity.y,
zMov + (float) (playerRB.velocity.z * 0.90)
);
}
else
{
velocity.x = (float) (playerBody.forward.x * lateralSpeed);
velocity.y = playerRB.velocity.y;
velocity.z = (float) (playerBody.forward.z * lateralSpeed);
}
playerBody.eulerAngles = new Vector3(0, playerBody.eulerAngles.y, 0);
playerRB.velocity = velocity;
}
void Movement(float xAmount, float zAmount)
{
if(sprintActive)
{
xSpeed = (float) (xAmount * 2);
zSpeed = (float) (zAmount * 2);
}
else
{
xSpeed = xAmount;
zSpeed = zAmount;
}
playerRB.AddRelativeForce(new Vector3(xSpeed, 0, zSpeed), ForceMode.Impulse);
}
void Jump(float yAmount)
{
playerRB.AddRelativeForce(new Vector3(0, yAmount, 0), ForceMode.Impulse);
}
}

How to respawn a paddle and ball in breakout - Unity 3D C#

I'm making a breakout game in 3D and it's my first time making a game and using Unity so I'm a bit clueless. I've got to the point where my game works fine up until the ball goes off the screen and into the "dead zone".
Can someone advise how to respawn the paddle and ball together and carry on with the game?
I've included my ball and paddle scripts below, I have a script for the bricks as well but not sure that was relevant. I also made a prefab of the ball and paddle together but no idea what to do with it.
Thanks to anyone who can help :)
Code for my ball
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallScript : MonoBehaviour
{
public Rigidbody rbody;
public float MinVertMovement = 0.1f;
public float MinSpeed = 10f;
public float MaxSpeed = 10f;
private bool hasBeenLaunched = false;
void Start()
{
}
private float minVelocity = 10f;
private Vector3 lastFrameVelocity;
void FixedUpdate()
{
if (hasBeenLaunched == false)
{
if (Input.GetKey(KeyCode.Space))
{
Launch();
}
}
if (hasBeenLaunched)
{
Vector3 direction = rbody.velocity;
direction = direction.normalized;
float speed = direction.magnitude;
if (direction.y>-MinVertMovement && direction.y <MinVertMovement)
{
direction.y = direction.y < 0 ? -MinVertMovement : MinVertMovement;
direction.x = direction.x < 0 ? -1 + MinVertMovement : 1 - MinVertMovement;
rbody.velocity = direction * MinSpeed;
}
if (speed<MinSpeed || speed>MaxSpeed)
{
speed = Mathf.Clamp(speed, MinSpeed, MaxSpeed);
rbody.velocity = direction*speed;
}
}
lastFrameVelocity = rbody.velocity;
}
void OnCollisionEnter(Collision collision)
{
Bounce(collision.contacts[0].normal);
}
private void Bounce(Vector3 collisionNormal)
{
var speed = lastFrameVelocity.magnitude;
var direction = Vector3.Reflect(lastFrameVelocity.normalized, collisionNormal);
Debug.Log("Out Direction: " + direction);
rbody.velocity = direction * Mathf.Max(speed, minVelocity);
}
public void Launch()
{
rbody = GetComponent<Rigidbody>();
Vector3 randomDirection = new Vector3(-5f, 10f, 0);
randomDirection = randomDirection.normalized * MinSpeed;
rbody.velocity = randomDirection;
transform.parent = null;
hasBeenLaunched = true;
}
}
Code for my paddle
public class PaddleScript : MonoBehaviour
{
private float moveSpeed = 15f;
void Start()
{
}
void Update()
{
if (Input.GetKey(KeyCode.RightArrow) && transform.position.x<9.5)
transform.Translate(moveSpeed *Input.GetAxis("Horizontal")*Time.deltaTime, 0f, 0f);
if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x>-7.5)
transform.Translate(moveSpeed *Input.GetAxis("Horizontal")*Time.deltaTime, 0f, 0f);
}
}
The simplest thing you can do to check wether the ball goes off screen is to place a trigger immediately off the perimeter of the camera, and add an OnTriggerEnter2D method to your ball.
/* Inside the ball script */
private void OnTriggerEnter() { // Use the 2D version if you're using 2D colliders
/* Respawning stuff */
}
Since you may want a bunch of different things to happen when that method triggers, you may want to use a Unity Event, which is not the king of performance but it probabily doesn't matter for a game like breakout.
using UnityEngine.Events;
public class BallScript : MonoBehaviour
{
public UnityEvent onBallOut;
/* ... */
private void OnTriggerEnter() {
onBallOut.Invoke();
}
}
You then probabily want a Respawn() method (not Reset() because that's a default MonoBehaviour call) which places the ball back to its original position, which you can store in a field as soon as the scene loads:
private Vector3 defaultPosition;
private void Start() {
defaultPosition = transform.position;
}
PS: If you aren't using the Start() method in your paddle script then remove it, cause it will be called by Unity even if empty.

LineRender | collision himself with raycast2D

i build game with line that you can control his movement.
every few seconeds the line create hole for the player can move through them.
look picture:
enter image description here
now in my code you can see the playerMovement, createLine and drawLine.
i draw the line By player location and every few seconeds i stop draw to millie seconed to create hole and than draw new line.
my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawLineNisayon : MonoBehaviour
{
[SerializeField] private GameObject linePrefab;
LineRenderer lineRenderer;
public GameObject currentLine;
private bool createHole = false;
private bool drawLine = false;
float rotZ = 0f;
public float speedMovement = 3f;
public float speedRotation = 6f;
public float timingCreateHoles = 2f;
public float widthHoles = 0.2f;
public EdgeCollider2D edgeCollider2D;
public List<Vector2> posLine;
void Start()
{
CreateLine();
}
void Update()
{
PlayerMovement(speedMovement);
DrawLine();
}
private void CreateLine()
{
currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity);
lineRenderer = currentLine.GetComponent<LineRenderer>();
edgeCollider2D = currentLine.GetComponent<EdgeCollider2D>();
posLine.Clear();
posLine.Add(transform.position);
posLine.Add(transform.position);
lineRenderer.SetPosition(0, posLine[0]);
lineRenderer.SetPosition(1, posLine[1]);
edgeCollider2D.points = posLine.ToArray();
}
private void DrawLine()
{
if(!drawLine)
{
posLine.Add(transform.position);
lineRenderer.positionCount++;
lineRenderer.SetPosition(lineRenderer.positionCount - 1, transform.position);
edgeCollider2D.points = posLine.ToArray();
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.right, 1f);
Debug.DrawRay(posLine[lineRenderer.positionCount - 1], transform.right);
if(createHole == false){
StartCoroutine(DrawHole(timingCreateHoles));
createHole = true;
}
}
}
private IEnumerator DrawHole(float timingCreateHoles)
{
yield return new WaitForSeconds(timingCreateHoles);
drawLine = true;
StartCoroutine(DrawLine(widthHoles));
}
private IEnumerator DrawLine(float widthHoles)
{
yield return new WaitForSeconds(widthHoles);
CreateLine();
drawLine = false;
createHole = false;
}
private void PlayerMovement(float speed)
{
transform.Translate(Vector3.right * speed * Time.deltaTime);
if(Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.A))
{
transform.Rotate(0f, 0f, rotZ);
rotZ = speedRotation;
}
if (!Input.GetKey(KeyCode.D) && Input.GetKey(KeyCode.A))
{
transform.Rotate(0f, 0f, rotZ);
rotZ = -speedRotation;
}
}
}
so what is my problem? i try to create raycast to check collision with the line himself like the game "snake". i tryed to create raycast in function "DrawLine" and i havnt idea how to do that.
my line built by list of vector2 like you can see in my code, its say that i need to compare vector to vector and i dont know how...
*i try collision with the last index in line, not with the circle in the picture.

with AddForceAtPosition objects only moves but doesn't torque

assume that there is a hole that's able to grab all the objects around of itself by its own gravity the script works fine but objects doesn't torque.
i want to make objects move to position of the hole and give them torque while they moving
you can use of two cube one of them could be hole and another one would be block that has rigidbody and box layer
thanks in advance.
public class EatTheBoxes : MonoBehaviour
{
public bool Starttoeat;
public float distance,speed,Gizmo_hight,FollowSpeed;
public LayerMask layerint;
public ForceMode forcemode;
private int _numberoftile;
void FixedUpdate()
{
if (Starttoeat)
{
CatchTheBoxes(transform.position,distance,layerint);
}
}
void CatchTheBoxes(Vector3 center, float radius , LayerMask layerint)
{
Collider[] hitColliders = Physics.OverlapSphere(center, radius,layerint);
int i = 0;
while (i < hitColliders.Length)
{
Vector3 forceDirection = transform.position - hitColliders[i].transform.position;
if (hitColliders[i].CompareTag("bomb"))
{
hitColliders[i].GetComponent<Rigidbody>().AddForceAtPosition(Time.fixedTime * 20 * forceDirection.normalized,transform.position,forcemode);
hitColliders[i].GetComponent<Rigidbody>().isKinematic = false;
}
else
{
hitColliders[i].GetComponent<Rigidbody>().AddForceAtPosition(Time.fixedTime * speed * forceDirection.normalized,transform.position,forcemode);
hitColliders[i].GetComponent<Rigidbody>().isKinematic = false;
}
i++;
}
}
void OnDrawGizmos()
{
Vector3 newTransform = transform.position;
newTransform.y = newTransform.y + Gizmo_hight;
Gizmos.DrawWireSphere(newTransform,distance);
}
}
You can add torque to rigidbody.
Just use
hitColliders[i].GetComponent<Rigidbody>().AddTorque(torqueVector);
Also consider cashing rigidbody:
Rigidbody hitRigidbody = hitColliders[i].GetComponent<Rigidbody>();
hitRigidbody.isKinematic = false;
hitRigidbody.AddForceAtPosition(Time.fixedTime * speed * forceDirection.normalized,transform.position,forcemode);
hitRigidbody.AddTorque(torqueVector);

Categories