Using the LookAt() function in Unity - c#

So I have an assignment that I have to do for school where an enemy shoots at the player in a gun type game. I have read about the LookAt() function in the Unity tutorials and used it to my knowledge of it. However it doesn't seem to be working. The following code is what I have so far:
public class EnemyControl : MonoBehaviour {
private Rigidbody rb;
public GameObject Bullet_Emitter2;
public GameObject EnemyBullet;
public float speedOfBullet;
private int score;
public Text countText;
public Text winText;
private GameObject Temporart_Bullet_Handler2;
public Transform player;
public Transform enemy;
void Start()
{
rb = GetComponent<Rigidbody>();
score = 0;
}
private void Update()
{
enemy.LookAt(player);
}
// Update is called once per frame
void FixedUpdate () {
int fire = Random.Range(0, 100);
if(fire == 0 || fire == 1 || fire == 5)
{
Temporart_Bullet_Handler2 = Instantiate(EnemyBullet, Bullet_Emitter2.transform.position, Bullet_Emitter2.transform.rotation) as GameObject;
Temporart_Bullet_Handler2.transform.Rotate(Vector3.right * 90);
Rigidbody Temporary_Rigid_Body;
Temporary_Rigid_Body = Temporart_Bullet_Handler2.GetComponent<Rigidbody>();
Temporary_Rigid_Body.AddForce(transform.up * speedOfBullet);
Destroy(Temporart_Bullet_Handler2, 20.0f);
}
}
}
The problem is my enemy now just looks at the ground instead of me and then just shoots downwards. Is there a way I can fix this? I have attached an image of what it looks like to a player playing the game?
Before putting in the LookAt() function my spaceman would just be stationary and fire bullets in a straight line but I need the AI to track the player instead of stationary. Is there another way to do this without using LookAt() or am I using this function wrong?
Thanks for the help in advance?

I would post this in comments but I can't yet because of low reputation
As Serlite pointed out, LookAt() only faces the GameObject's trasnform.forward (which is desired to be (0, 0, 1) when the object is not rotated) towards the target passed as argument.
To 'fix' this simply add an empty GameObject to your Hirarchy and set your AI object as its child
Empty GameObject
- AI GameObject (with your script)
Now you can set a global rotation for your object (Rotate the parent) in a way that the AI's forwards faces z+.

Related

Checking collision with Polygon Collider using Ray cast and instantiating objects issue (unity)

I'm trying to check collision with Polygon collider using Raycast on my field in my Unity game. And then create crop on position of ray cast if conditions met by clicking button. Even though it checks collision perfectly i have a few issues that i just cant figure out how to fix. Like:
my shooter game object teleport on scene randomly, but raycasting is always correct O_o.
Instantiated crop disappear in moment of next instantiation...
Can some one help me to fix it? Here is the code:
public class PlayerRay : MonoBehaviour
{
float borderLeft = -4.34f;
float borderRight = 3.85f;
float borderUp = 1.61f;
float borderDown = -2.32f;
public GameObject field;
public GameObject shooter;
public Transform shooterPos;
PolygonCollider2D fieldCollider;
public GameObject repka;
private void Start()
{
fieldCollider = field.GetComponent<PolygonCollider2D>();
}
void Update()
{
}
public void Sow()
{
Vector3 rayCastPos = new Vector3(Random.Range(borderLeft, borderRight), Random.Range(borderDown, borderUp), 0);
shooter.transform.Translate(rayCastPos);
Debug.DrawRay(transform.position, transform.forward * 10, Color.yellow);
RaycastHit2D hit = Physics2D.Raycast(rayCastPos, Vector3.forward);
if (hit == fieldCollider)
{
Debug.Log("We hit collider");
Instantiate(repka, shooterPos);
}
else
{
Debug.Log("There is no colider at: " + rayCastPos);
}
}
}
enter image description here
I found solution! It's just that i tried to use Transform overload for instantiate instead of using Vector3. Because I forgot to add "rotation" as third parameter. So I switched to Vector3 overload, added Quaternion.identity for rotation and it's all works just fine now :)
Here is the fix:
Instantiate(repka, rayCastPos, Quaternion.identity);

Respawn AI after destroy

I'm new, and I've got hard time to respawn my AI (right now he just a cube that follow my player) after he been destroy. I believe its because the script sits on the object that get destroyed. but what I need to do to respawn it?
(although I'm sure my respawn code is not good :\ (It's mobile-android project) )
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyTesting : MonoBehaviour
{
[SerializeField]
public GameObject player;
public GameObject enemy;
private Rigidbody body;
Vector3 accelerationDir;
// Use this for initialization
void Start()
{
body = GetComponent<Rigidbody>();
}
private void Update()
{
accelerationDir = Input.acceleration;
if (accelerationDir.sqrMagnitude>=5)
{
EnemyDead();
}
}
void EnemyDead()
{
Destroy(enemy);
Invoke("Respawn", 5);
}
void Respawn()
{
enemy = (GameObject)Instantiate(enemy);
enemy.transform.position = transform.position;
}
// Update is called once per frame
void FixedUpdate()
{
Vector3 toTarget = player.transform.position - transform.position;
float speed = 1.5f;
transform.Translate(toTarget * speed * Time.deltaTime);
}
}
Thanks very much!
I am supposing that your enemy GameObject is inside the scene holding your EnemyTesting MonoBehaviour instance (correct me if I'm wrong).
If this is the case, you cannot instantiate a gameObject that is destroyed.
As #derHugo pointed out, you should not use Destroy and Instantiate for your use case. It would be better to set inactive the enemy GameObject, move it to the position that you want, an (re)set it active. It will look like the enemy respawned.
If you want to dig the subject later, look at the object pooling game optimization pattern.
Otherwise, if you still want to use Instantiate for respawning, I would create a prefab of your enemy GameObject. The enemy GameObject referenced in the EnemyTesting field (in the Inspector view), would be your prefab from the project hierarchy instead of a GameObject inside the scene.
This way, you would be able to instantiate an enemy GameObject as many times as you want (and use it in other scenes!). Don't forget to hold a reference to the instantiated enemy GameObject so you can know which one you want to destroy. It would looke like this :
enemy = Instantiate(enemyPrefab, transform.position, transform.rotation);
You can replace transform with the transform of your choice, for example the transform of an empty enemyRespawnPoint GameObject in your Scene.
Do you see any error in the console ?

Enemy Projectile is not flying in the right direction?

I am having trouble getting the enemy's projectile to fly from the enemy to the player's position. When I play the game, the enemy bullet projectiles fly off in one direction on the screen and not toward the player. I think the issue might be in how I am assigning direction to the projectile prefab? Any suggestions would be much appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public float speed;
public Rigidbody enemyRb;
[SerializeField] float rateOfFire;
private GameObject player;
public GameObject projectilePrefab;
float nextFireAllowed;
public bool canFire;
Transform enemyMuzzle;
void Awake()
{
enemyRb = GetComponent<Rigidbody>();
player = GameObject.Find("Player");
enemyMuzzle = transform.Find("EnemyMuzzle");
}
void Update()
{
//move enemy rigidbody toward player
Vector3 lookDirection = (player.transform.position - transform.position).normalized;
enemyRb.AddForce(lookDirection * speed);
//overallSpeed
Vector3 horizontalVelocity = enemyRb.velocity;
horizontalVelocity = new Vector3(enemyRb.velocity.x, 0, enemyRb.velocity.z);
// turns enemy to look at player
transform.LookAt(player.transform);
//launches projectile toward player
projectilePrefab.transform.Translate(lookDirection * speed * Time.deltaTime);
Instantiate(projectilePrefab, transform.position, projectilePrefab.transform.rotation);
}
public virtual void Fire()
{
canFire = false;
if (Time.time < nextFireAllowed)
return;
nextFireAllowed = Time.time + rateOfFire;
//instantiate the projectile;
Instantiate(projectilePrefab, enemyMuzzle.position, enemyMuzzle.rotation);
canFire = true;
}
}
It looks like what is actually happening is that you create a bunch of bullets but don't store a reference to them. So each bullets sits in one place while the enemy moves closer to the player ( which might give the appearance that the bullets are moving relative to the enemy. ) I also assume the enemy is moving very fast since it is not scaled by delta time but is being updated every frame.
I think projectilePrefab is just the template object you're spawning, so you probably don't want to move it directly and you certainly don't want to instantiate a new bullet every frame.
If you want to move the object you spawned the least changes ( but still problematic ) from your example code might be:
public class EnemyController : MonoBehaviour
{
// add a reference
private GameObject projectileGameObject = null;
void Update()
{
//Update position of spawned projectile rather than the template
if(projectileGameObject != null ) {
projectileGameObject.transform.Translate(lookDirection * speed * Time.deltaTime);
}
// Be sure to remove this extra instantiate
//Instantiate(projectilePrefab, transform.position, projectilePrefab.transform.rotation);
}
public virtual void Fire()
{
//instantiate the projectile
projectileGameObject = Instantiate(projectilePrefab, enemyMuzzle.position, enemyMuzzle.rotation);
}
}
Or keep multiple bullets in a list. This implementation has the bug that it will always use the current enemy to player vector as the direction rather than the direction that existed when it was fired.
What you will probably want eventually is that each projectile is has it's own class script to handle projectile logic. All the enemyController class has to do is spawn the projectile and sets it's direction and position on a separate monobehavior that lives on the Projectile objects that handles it's own updates.

Move Object to the last position or position just outside the collision area

I am using a Player rigid body object and there are walls around the Player. These walls are restricting the Player to go through. The Player gets collided with these walls and then falls. The Player uses teleport function to jump from one area to next. Is there a way to make the Player jump to a position just outside the collision area after the Player is collided with these walls?
That is, Player A gets collided with the wall and does not jump to last position, but the position before the collision happened?
public GameObject Player;
public Vector3 PlayerPos;
public bool RecordPos = true;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(RecordPos == true)
{
PlayerPos = Player.transform.position;
}
}
public void OnTriggerEnter(Collider col)
{
if(col.gameObject.name == "Cube(3)" )
{
RecordPos = false;
Player.transform.position = PlayerPos;
}
}
In this script, the Player moves to last position it teleported from.
The "last" position before colliding is 1 frame before the collision. If you capture this position, the character will probably just fall on the obstacle again. Imagine you have a platform ___...___ and an obstacle. The easiest solution is to have 1 trigger at the left side of the obstacles and 1 trigger at the right side. If the player hasn't overcome the obstacle yet, he will be teleported to a chosen destination by you (before the obstacle) and if he's already overcome the obstacle, he will be teleported at the right side. __S_..._S__ (S stands for save/checkpoint trigger)
You need the following script on the gameobject with the Trigger collider. You also need to create a child object to the gameobject with the trigger:
private void OnTriggerEnter2D(Collider2D collision)
{
SaveManager.Instance.LastCheckpointOnHit = transform.GetChild(0).position;
}
And I suppose you have some sort of a singleton for data persistance. Now you can move the child gameobject whereever you want to teleport the player. And BTW I named the property LastCheckpointOnHit, because I was thinking of Holow Knight where if you get hit by spikes it instantly teleports you.
Then you just move the player: Player.transform.position = SaveManager.Instance.LastCheckpointOnHit;
In general when dealing with Rigidbody you shouldn't apply positions through the Transform component but rather through the Rigidbody.
I could imagine something like if you collide with a wall you get pushed away from the wall a bit in the direction where you came from like e.g.
[SerializeField] private float someDistanceThreshold = 0.01f;
[SerializeField] private Rigidbody _rigidbody;
private void Start()
{
if(!_rigidbody) _rigidbody = Player.GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
PlayerPos = _rigidbody.position;
}
public void OnTriggerEnter(Collider col)
{
// instead of the name I would rather use a tag later to cover all obstacles
if(col.gameObject.name == "Cube(3)")
{
_rigidbody.position -= (_rigidbody.position - PlayerPos).normalized * someDistanceThreshold;
// For stopping the player here
_rigidbody.velocity = Vector3.zero;
}
}

Unity3D CharacterController movement issue. Camera position not changed

I have a problem that main camera position doesn't change after CharacterController.SimpleMove() called. The task is to create scene where camera moves.
I have Main Camera game object with Character Controller and Script attached.
The issue is that nothing in vrCamera position changed after SimpleMove() called.
My question is what is wrong in this code. I suggest something wrong with binding between MainCamera object and CharacterController component, but I have spend a lot of time investigating and nothing working found.
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class VRLookWalk : MonoBehaviour {
public Transform vrCamera;
public float toggleAngle = 30.0f;
public float speed = 3.0f;
public bool moveForwad;
private CharacterController cc;
// Use this for initialization
void Start () {
cc = vrCamera.GetComponent<CharacterController>();
}
// Update is called once per frame
void Update () {
if (vrCamera.eulerAngles.x >= toggleAngle && vrCamera.eulerAngles.x < 90.0f)
{
Vector3 forward = vrCamera.TransformDirection(Vector3.forward);
cc.SimpleMove(forward * speed);
}
}
}
You can't move the VR Camera, it's the SDK that determine the mainCamera position.
In order to move your camera you can just make a new GameObject as a parent of your mainCamera then move the parent GameObject
Try this. Your TransformDirection probably returns wrong vector.
Vector3 forward = vrCamera.transform.forward;
cc.SimpleMove(forward * speed);

Categories