I made an AI Enemy system that has the enemy walk towards a target that I want to attack.The target (who is the player collects points). What I want is when the enemy reaches its target it takes away -1 point from the player. What I want to know is how do I deduct the point from my game manager. I already created a public game object that carries the script for my points. When I try this out the enemy does not take a point away once it reaches the player. Should I create a function within my Enemy AI script called TargetIsReached()?
public class aiEnemy : MonoBehaviour, IPooledObject {
public float lookRadius = 40f;
Transform target;
UnityEngine.AI.NavMeshAgent agent;
Rigidbody theRigidBody;
public Casting castingScript;
void Start(){
target = PlayerManager.instance.player.transform;
agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
}
void Update(){
float distance = Vector3.Distance (target.position, transform.position);
if (distance <= lookRadius)
{
agent.SetDestination (target.position);
if (distance <= agent.stoppingDistance)
{
FaceTarget ();
castingScript.RemovePoint ();
}
}
}
void FaceTarget()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation (new Vector3 (direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp (transform.rotation, lookRotation, Time.deltaTime * 5f);
}
// Use this for initialization
public void OnObjectSpawn () {
//myRender = GetComponent<Renderer> ();
theRigidBody = GetComponent<Rigidbody>();
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere (transform.position, lookRadius);
}
}
//Casting Script//
public GameObject Float;
public Transform target;
public GameObject disableFish;
public float waitTime= 3f;
public int scoreValue = 1;
int waterMask;
public float maxCastDist = 1000f;
public float fishDist = 1f;
public bool hitObject;
void Awake ()
{
waterMask = LayerMask.GetMask ("Water"); // will only cast in water
}
void Update ()
{
if (EventSystem.current.IsPointerOverGameObject ()) {
return;
} else {
if (Input.GetMouseButtonDown (0)) {
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, maxCastDist, waterMask))
if (hit.collider != null) {
float dist = Vector3.Distance (hit.point, target.position);
Debug.Log (dist);
Destroy (GameObject.FindWithTag ("Float"));
Instantiate (Float, hit.point, Quaternion.identity);
if (dist < fishDist) {
disableFish.SetActive(false);
StartCoroutine (fishWaiter ());
StartCoroutine (DestroyOb(waitTime));
}
}
}
}
}
IEnumerator fishWaiter ()
{
FishLoader.SetActive (true);
FishSlider.value = waitTime;
Debug.Log ("Timer Started");
yield return new WaitForSeconds (waitTime);
print ("I waited" + waitTime + "Sec");
FishSlider.value = 0f;
print ("You Caught The Fish!");
ScoreManager.score += scoreValue;
}
IEnumerator DestroyOb (float waitTime){
yield return new WaitForSeconds (waitTime);
Destroy (GameObject.FindWithTag ("Float"));
}
}
Related
I have a problem with an enemy on Unity2D.
The enemy should run to the player and if it's in the attackRange then it has to attack the enemy with a bullet, but the enemy follows my Player.
But there is a problem:
The enemy doesn't shoot with the bullet.
I changed the code, so when I press a button the enemy attacks too.
It worked only with the button.
Here's my code for the enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class Enemy2 : MonoBehaviour
{
public Transform target;
public Transform firePoint;
public float speed = 200f;
public float nextWaypointDistance = 3f;
public float range = 10f; // the range at which the enemy will start moving towards the player
public float attackRange = 8f; // the range at which the enemy will attack the player
float distance;
public Transform enemyGFX;
private Transform player; // reference to the player's transform
public GameObject EnemyWeapon;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
Seeker seeker;
Rigidbody2D rb;
public Animator animator;
bool Stop = false;
public static float Enemy2Direction;
// Start is called before the first frame update
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
animator = GetComponentInChildren<Animator>();
player = GameObject.FindGameObjectWithTag("Player").transform;
InvokeRepeating("UpdatePath", 0f, .5f);
}
void UpdatePath()
{
if (seeker.IsDone())
{
seeker.StartPath(rb.position, target.position, OnPathComplete);
}
}
void OnPathComplete (Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Update is called once per frame
void FixedUpdate()
{
if (Pause.IsPause == false)
{
if (path == null)
{
return;
}
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] -rb.position).normalized;
Vector2 force = direction * speed * Time.deltaTime;
rb.AddForce(force);
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
//You can make look it differently, if you delete 'rb.velocity' and add 'force' instead.
if (rb.velocity.x >= 0.01f)
{
enemyGFX.transform.localScale = new Vector3(-1f, 1f, 1f);
Enemy2Direction = 1f;
}
else if (rb.velocity.x <= -0.01f)
{
enemyGFX.transform.localScale = new Vector3(1f, 1f, 1f);
Enemy2Direction = 0f;
}
if (distance < attackRange)
{
if (Stop = false)
{
StartCoroutine(Attack());
}
}
}
distance = Vector2.Distance(transform.position, player.position);
if (distance > range)
{
Destroy(gameObject);
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
animator.SetBool("Damage", true);
}
if (collision.gameObject.tag == "Bullet")
{
animator.SetBool("Damage", true);
}
}
void Update()
{
if (animator.GetBool("Damage"))
{
StartCoroutine(DamageAnimation());
}
if (Input.GetKeyDown(KeyCode.L))
{
StartCoroutine(Attack());
}
}
IEnumerator Attack()
{
Debug.Log("Attacked");
Stop = true;
yield return new WaitForSeconds(2.0f);
animator.SetBool("Attack", true);
Instantiate(EnemyWeapon, firePoint.position, firePoint.rotation);
yield return new WaitForSeconds(2.0f);
animator.SetBool("Attack", false);
StartCoroutine(Wait());
}
IEnumerator DamageAnimation()
{
yield return new WaitForSeconds(2.0f);
animator.SetBool("Damage", false);
}
IEnumerator Wait()
{
yield return new WaitForSeconds(2.0f);
Stop = false;
}
}
I don't know what's wrong with my code.
Can somebody please help me?
if(Stop == false)
Replace the = in when you check the Stop bool with ==, in C# you use == in order to check for equality
See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators for more detail.
I am working on a 2d zombie killing game but there was an error rotating the gun in my code, when I rotate the gun it turns wrong. Can you help me?
Video:https://youtu.be/8kUgXkEZc2M
Here is the code:
[SerializeField] Transform _arm;
float _offset = -90;
Vector3 _startingSize;
Vector3 _armStartingSize;
public GameObject Bullet;
public float BulletSpeed;
public Transform ShootPoint;
#region Start
// Start is called before the first frame update
void Start()
{
_startingSize = transform.localScale;
_armStartingSize = _arm.localScale;
}
#endregion
// Update is called once per frame
void Update()
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 perendicular = _arm.position - mousePos;
Quaternion val = Quaternion.LookRotation(Vector3.forward, perendicular);
val *= Quaternion.Euler(0, 0, _offset);
_arm.rotation = val;
if(transform.position.x - mousePos.x < -0.1)
{
transform.localScale = _startingSize;
_arm.localScale = _armStartingSize;
}
else if(transform.position.x - mousePos.x > 0.1)
{
transform.localScale = new Vector3(-_startingSize.x, _startingSize.y, _startingSize.z);
_arm.localScale = new Vector3(-_armStartingSize.x, -_armStartingSize.y, _armStartingSize.z);
}
if (Input.GetMouseButtonDown(0))
{
shoot();
}
}
void shoot()
{
cineShake.Instance.ShakeCamera(5f, .1f);
GameObject BulletIns = Instantiate(Bullet, ShootPoint.position, ShootPoint.rotation);
BulletIns.GetComponent<Rigidbody2D>().AddForce(BulletIns.transform.right * BulletSpeed);
}
In survival Shooter, I have the enemy object and added my own 3d game object
Everything is working fine, the gameobject is following and hurting the player but when the player shoots the gameobject the bullet goes through the gameobject and score also does not increase. I have attached the rigidbody component to my custom 3d gameobject but the bullet still doesn't cause any damage.
This is the code for PlayerShooting
using UnityEngine;
public class PlayerShooting : MonoBehaviour
{
public int damagePerShot = 20;
public float timeBetweenBullets = 0.15f;
public float range = 100f;
float timer;
Ray shootRay;
RaycastHit shootHit;
int shootableMask;
ParticleSystem gunParticles;
LineRenderer gunLine;
AudioSource gunAudio;
Light gunLight;
float effectsDisplayTime = 0.2f;
void Awake ()
{
shootableMask = LayerMask.GetMask ("Default");
shootableMask = LayerMask.GetMask ("Default");
shootableMask = LayerMask.GetMask("Default");
shootableMask = LayerMask.GetMask("Default");
gunParticles = GetComponent<ParticleSystem> ();
gunLine = GetComponent <LineRenderer> ();
gunAudio = GetComponent<AudioSource> ();
gunLight = GetComponent<Light> ();
}
void Update ()
{
timer += Time.deltaTime;
if(Input.GetButton ("Fire1") && timer >= timeBetweenBullets)
{
Shoot ();
}
if(timer >= timeBetweenBullets * effectsDisplayTime)
{
DisableEffects ();
}
}
public void DisableEffects ()
{
gunLine.enabled = false;
gunLight.enabled = false;
}
void Shoot ()
{
timer = 0f;
gunAudio.Play ();
gunLight.enabled = true;
gunParticles.Stop ();
gunParticles.Play ();
gunLine.enabled = true;
gunLine.SetPosition (0, transform.position);
shootRay.origin = transform.position;
shootRay.direction = transform.forward;
if(Physics.Raycast (shootRay, out shootHit, range, shootableMask))
{
EnemyHealth enemyHealth = shootHit.collider.GetComponent <EnemyHealth> ();
if(enemyHealth != null)
{
enemyHealth.TakeDamage (damagePerShot, shootHit.point);
}
gunLine.SetPosition (1, shootHit.point);
}
else
{
gunLine.SetPosition (1, shootRay.origin + shootRay.direction * range);
}
}
}
and below is the enemy health script:
using UnityEngine;
public class EnemyHealth : MonoBehaviour
{
public int startingHealth = 100;
public int currentHealth;
public float sinkSpeed = 2.5f;
public int scoreValue = 10;
public AudioClip deathClip;
Animator anim;
AudioSource enemyAudio;
ParticleSystem hitParticles;
CapsuleCollider capsuleCollider;
bool isDead;
bool isSinking;
void Awake ()
{
anim = GetComponent <Animator> ();
enemyAudio = GetComponent <AudioSource> ();
hitParticles = GetComponentInChildren <ParticleSystem> ();
capsuleCollider = GetComponent <CapsuleCollider> ();
currentHealth = startingHealth;
}
void Update ()
{
if(isSinking)
{
transform.Translate (-Vector3.up * sinkSpeed * Time.deltaTime);
}
}
public void TakeDamage (int amount, Vector3 hitPoint)
{
if(isDead)
return;
enemyAudio.Play ();
currentHealth -= amount;
hitParticles.transform.position = hitPoint;
hitParticles.Play();
if(currentHealth <= 0)
{
Death ();
}
}
void Death ()
{
isDead = true;
capsuleCollider.isTrigger = true;
anim.SetTrigger ("Dead");
ScoreManager.score += scoreValue;
enemyAudio.clip = deathClip;
enemyAudio.Play ();
}
public void StartSinking ()
{
GetComponent <UnityEngine.AI.NavMeshAgent> ().enabled = false;
GetComponent <Rigidbody> ().isKinematic = true;
isSinking = true;
ScoreManager.score += scoreValue;
Destroy (gameObject, 2f);
}
}
If the line that shows the bullet is going through the enemy gameobject, then your Physics.Raycast is not hitting this gameobject's collider.
You can test this quickly by adding some Debug output to your raycast block as below:
if(Physics.Raycast (shootRay, out shootHit, range, shootableMask))
{
Debug.Log("I HIT SOMETHING CALLED: " + shootHit.collider.gameObject.name);
EnemyHealth enemyHealth = shootHit.collider.GetComponent <EnemyHealth> ();
if(enemyHealth != null)
{
enemyHealth.TakeDamage (damagePerShot, shootHit.point);
}
gunLine.SetPosition (1, shootHit.point);
}
else
{
Debug.Log("I DIDN'T HIT ANYTHING!");
gunLine.SetPosition (1, shootRay.origin + shootRay.direction * range);
}
I suspect your problem is that your enemy gameobject is on the Default layer.
In your Awake method, you are setting your shootableMask as follows shootableMask = LayerMask.GetMask ("Default"); and then when you call Physics.Raycast you are passing it the shootableMask. What this is effectively doing is telling the raycast to ignore any objects that are on the Default layer.
Try putting your enemy gameobject on a different layer.
On a side note, you only need to have shootableMask = LayerMask.GetMask ("Default"); once in your Awake method, not four times.
How can I have my enemy disable a script once it reaches target player? I want to reference this script called casting under my GameManager in my code and disable it but I'm unsure how to write the function for when target location is reached.
public float lookRadius = 40f;
Transform target;
UnityEngine.AI.NavMeshAgent agent;
Rigidbody theRigidBody;
void Start()
{
target = PlayerManager.instance.player.transform;
agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
}
void Update()
{
float distance = Vector3.Distance (target.position, transform.position);
if (distance <= lookRadius)
{
agent.SetDestination (target.position);
if (distance <= agent.stoppingDistance)
{
FaceTarget ();
}
}
}
void FaceTarget()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation (new Vector3 (direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp (transform.rotation, lookRotation, Time.deltaTime * 5f);
}
// Use this for initialization
public void OnObjectSpawn ()
{
//myRender = GetComponent<Renderer> ();
theRigidBody = GetComponent<Rigidbody>();
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere (transform.position, lookRadius);
}
You need to obtain the gameobject that has the script, get the script on that gameobject, and disable.
if (distance < 1f) // or some distance
{
Gameobject mygo = GameObject.Find("GameManager"); // or some other method to get gameobject.
mygo.GetComponent<casting>().enabled = false;
}
I am working on a Character Controller Script and everything is working fine but the problem is that once my player starts to fall it is so sudden and jerks down. I would like the player to gradually fall down, this is my character controller script -
using UnityEngine;
using System.Collections;
public class CharacterController : MonoBehaviour {
public float inputDelay = 0.1f;
public float forwardVel = 12;
public float rotateCel = 12;
public float JumpHeight = 20;
public Vector3 Gravity = new Vector3 (0, -180, 0);
public bool CanPress;
private float jumpTime;
public float _initialJumpTime = 0.4f;
//[HideInInspector]
public bool isGrounded;
Quaternion targetRotation;
Rigidbody rBody;
Vector3 forwardInput, turnInput;
public bool HasJumped;
public Quaternion TargetRotation
{
get {return targetRotation;}
}
// Use this for initialization
void Start () {
Physics.gravity = Gravity;
targetRotation = transform.rotation;
if (GetComponent<Rigidbody> ())
rBody = GetComponent<Rigidbody> ();
else {
Debug.LogError("Character Needs Rigidbody");
}
// forwardInput = turnInput = 0;
forwardInput = turnInput = Vector3.zero;
}
// Update is called once per frame
void Update () {
GetInput ();
//Turn ();
if (CanPress == true) {
if (Input.GetKeyDown (KeyCode.Space)) {
HasJumped = true;
jumpTime = _initialJumpTime;
}
}
if (HasJumped == true) {
rBody.useGravity = false;
jumpTime -= 1 * Time.deltaTime;
if (jumpTime > 0) {
Jump();
}
else {
HasJumped = false;
rBody.useGravity = true;
}
}
}
void GetInput() {
//forwardInput = Input.GetAxis ("Vertical");
//turnInput = Input.GetAxis ("Horizontal");
forwardInput = new Vector3 (Input.GetAxis ("Horizontal") * rotateCel, 0, Input.GetAxis ("Vertical") * forwardVel);
forwardInput = transform.TransformDirection (forwardInput);
if (Input.GetKeyUp (KeyCode.Space)) {
//HasJumped = false;
}
}
void Jump() {
Vector3 up = transform.TransformDirection (Vector3.up);
GetComponent<Rigidbody> ().AddForce (up * 5, ForceMode.Impulse);
}
void FixedUpdate() {
Run ();
}
void Run() {
if (Mathf.Abs (10) > inputDelay) {
//Move
//rBody.velocity = transform.forward * forwardInput * forwardVel;
rBody.velocity = forwardInput;
} else {
//zero velocity
rBody.velocity = Vector3.zero;
}
}
void Turn() {
// targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
// transform.rotation = targetRotation;
}
void OnTriggerEnter(Collider col) {
isGrounded = true;
CanPress = true;
}
void OnTriggerExit(Collider col) {
isGrounded = false;
CanPress = false;
}
}
My character has a Rigidbody attactches which uses gravity and has X,Y,Z constraints for Rotation.
The player goes up smoothly and falls down smoothly but the transition between the two is very abrupt and sudden.
Thanks for the help. :)
Okay, so I took your code and had a play.
I think the issue was that in your Run() function, you were altering the velocity of the rigidbody which was affecting your jumping.
I've taken that stuff out and improved your script slightly and tested it. Attach this to a capsule with a rigidbody on it, with a floor underneath with a box collider on and hit space, and you should get a smooth jump.
Your new(ish) script:
using UnityEngine;
using System.Collections;
public class CharacterController : MonoBehaviour
{
public float inputDelay = 0.1f;
public float forwardVel = 12;
public float rotateCel = 12;
public float jumpHeight = 10;
private float jumpTime;
public float _initialJumpTime = 0.4f;
//[HideInInspector]
public bool isGrounded;
Quaternion targetRotation;
Rigidbody rBody;
Vector3 forwardInput, turnInput;
public bool canJump;
public Quaternion TargetRotation
{
get { return targetRotation; }
}
void Start()
{
targetRotation = transform.rotation;
if (GetComponent<Rigidbody>())
rBody = GetComponent<Rigidbody>();
else
{
Debug.LogError("Character Needs Rigidbody");
}
// forwardInput = turnInput = 0;
forwardInput = turnInput = Vector3.zero;
}
void Update()
{
GetInput();
//Turn ();
if (Input.GetKeyDown(KeyCode.Space) && canJump)
{
rBody.AddForce(Vector3.up * jumpHeight, ForceMode.Impulse);
}
}
void GetInput()
{
//forwardInput = Input.GetAxis ("Vertical");
//turnInput = Input.GetAxis ("Horizontal");
forwardInput = new Vector3(Input.GetAxis("Horizontal") * rotateCel, 0, Input.GetAxis("Vertical") * forwardVel);
forwardInput = transform.TransformDirection(forwardInput);
}
void FixedUpdate()
{
//Run();
}
void Run()
{
//HERE YOU SET THE RIGIDBODYS VELOCITY, WHICH IS CAUSING YOUR JUMP TO NOT WORK PROPERLY. DO NOT MODIFY THE VELOCITY
//OF A RIGIDBODY
if (Mathf.Abs(10) > inputDelay)
{
//Move
//rBody.velocity = transform.forward * forwardInput * forwardVel;
rBody.velocity = forwardInput;
}
else
{
//zero velocity
rBody.velocity = Vector3.zero;
}
}
void Turn()
{
// targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
// transform.rotation = targetRotation;
}
void OnCollisionEnter(Collision col)
{
isGrounded = true;
canJump = true;
}
void OnCollisionExit(Collision col)
{
isGrounded = false;
canJump = false;
}
}
Couple of points:
name your variables inThisKindOfFashion (jumpHeight, isOnGround, camelCaseExample), having variables beginning with a capital letter like Gravity and JumpHeight can get confusing.
as someone once answered on one of my questions, don't modify the velocity of a rigidbody unless you know what you are doing! Seems odd, but after following that advice I've never had a problem since!
In your script I have used OnCollision rather than OnTrigger. If you put a floor with a box collider underneath your capsule with a collider, rigidbody and this script on, your character will stop on the ground. If you use a trigger, he will fall through (at least in my experience!)
Happy coding! :-)
Edit
To respond to your comments:
"How do you suggest I move the player"
Movement can be done in a variety of different ways, but I usually use this one all the time unless I need to do something a bit differently:
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
transform.position += Vector3.left * speed * Time.deltaTime; //speed could be 5f, for example (f means float);
}
// then do the same for other directions, RightArrow -.right, UpArrow - .forward, DownArrow - .back
}
"How do I adjust how fast the player jumps"
You can alter the jumpHeight variable for a higher or smaller jump. If by faster you mean falls down faster, go to Edit>Project Settings>Physics> and change Y gravity to something smaller, such as -20.
Tutorials can be found here
They have a wide variety of tutorials, and even have ones that come with example projects so you can just put it together following the video.