Attack timer stops after killing enemy (when attack script loose target) (Unity) - c#

Hey guys! I have a problem, I have attack script with cooldown and stuff in it, I've created basic combat system, everything works until I kill enemy, it destroys it as intended but then my attack timer stops counting until I select another enemy. Also I keep getting an error until I select first enemy because target field in attack script is empty at start.
Scripts:
Attack Script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class BasicAttack : MonoBehaviour {
public GameObject target; //target to attack
public int damage;
public float range = 4;
public float attackTimer;
public float cooldown = 2.0f;
public GameObject damageNumber;
public GameObject cooldownImage;
public Text cooldownText;
Targeting t;
UserInterface UI;
void Start () {
cooldownImage.SetActive(false);
attackTimer = 0;
t = FindObjectOfType<Targeting>();
UI = FindObjectOfType<UserInterface>();
}
void Update () {
float distance = Vector3.Distance(target.transform.position, transform.position); //calculating distance
cooldownText.text = attackTimer.ToString("F0");
if (attackTimer > 0) {
attackTimer -= Time.deltaTime;
}
if (attackTimer <= 0) {
attackTimer = 0;
}
if (Input.GetKeyUp("1")) { //attack key
if (attackTimer == 0 && distance < range) {
Attack();
attackTimer = cooldown;
//damage numbers
var clone = (GameObject)Instantiate(damageNumber, t.selectedTarget.GetComponent<EnemyAI>().hitPoint.position, t.myTransform.rotation);
clone.GetComponent<DamageNumbers>().damageNumber = damage;
}
else {
Debug.Log("Target is out of range!");
}
}
else {
cooldownImage.SetActive(true);
}
if (attackTimer == 0) {
cooldownImage.SetActive(false);
}
}
public void Attack() {
float distance = Vector3.Distance(target.transform.position, transform.position); //calculating distance
Vector3 dir = (target.transform.position - transform.position).normalized; //calculating direction
float direction = Vector3.Dot(dir, transform.forward); //calculating direction
if (distance < range) { //making player not be able to attack if too far
if (direction > 0) { //making player not be able to attack if target not in front of him
EnemyHealth eh = (EnemyHealth)target.GetComponent("EnemyHealth"); //getting enemy health
t.selectedTarget.GetComponent<EnemyHealth>().TakeDamage(-damage); //adjusting enemy health
UI.infoText.text = "";
}
else {
Debug.Log("Target needs to be in front of you!");
}
UI.infoText.text = "";
}
else {
Debug.Log("Target is out of range!");
}
} //attack
}
EnemyHealth Script:
using UnityEngine;
using System.Collections;
public class EnemyHealth : MonoBehaviour {
public float maxHealth = 100;
public float curHealth = 100;
CombatTargetUI ct;
void Start () {
ct = FindObjectOfType<CombatTargetUI>();
}
void Update () {
TakeDamage(0);
}
public void TakeDamage (int ad) {
curHealth += ad;
if (curHealth <= 0) {
curHealth = 0;
/*ct.HideUI();*/
Die();
}
if (curHealth >= maxHealth) {
curHealth = maxHealth;
}
if (maxHealth <= 1) {
maxHealth = 1;
}
}
void Die () {
StartCoroutine(TimeToDestroy());
}
IEnumerator TimeToDestroy () {
yield return new WaitForSeconds(0.5f);
ct.HideUI();
Destroy(gameObject);
}
}
Targeting Script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Targeting : MonoBehaviour {
public List<Transform> targets;
public Transform selectedTarget;
public Transform myTransform;
CombatTargetUI ct;
void Start () {
targets = new List<Transform>();
selectedTarget = null;
myTransform = transform;
ct = FindObjectOfType<CombatTargetUI>();
AddAllEnemies();
}
public void AddAllEnemies () {
GameObject[] go = GameObject.FindGameObjectsWithTag("Enemy");
foreach (GameObject enemy in go) {
AddTarget(enemy.transform);
}
}
public void AddTarget (Transform enemy) {
targets.Add(enemy);
}
void SortTargetsByDistance () {
targets.RemoveAll(target => target == null);
targets.Sort(delegate(Transform t1, Transform t2) {
return Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position));
});
}
void TargetEnemy () {
if (selectedTarget == null) {
SortTargetsByDistance();
selectedTarget = targets[0];
}
else {
int index = targets.IndexOf(selectedTarget);
if (index < targets.Count - 1) {
index++;
}
else {
index = 0;
}
DeselectTarget();
selectedTarget = targets[index];
}
SelectTarget();
}
void SelectTarget () {
ct.ShowUI();
selectedTarget.GetComponent<Renderer>().material.color = Color.red;
BasicAttack ba = (BasicAttack)GetComponent("BasicAttack");
ba.target = selectedTarget.gameObject;
}
public void DeselectTarget () {
if (selectedTarget != null) {
selectedTarget.GetComponent<Renderer>().material.color = Color.white;
}
selectedTarget = null;
}
void Update () {
if (Input.GetKeyDown(KeyCode.Tab)) {
TargetEnemy();
}
}
}
I think that those are all scripts that might cause problem, can anyone help me? I'm desperate. :(

In beginning of Update method of your Attack Script, add a null check for target object like this:
if(target == null)
{
return;
}

I think I know what your Timer problems are.
If I have understood correctly, in the Basic Attack class - Start Method, you iniate the timer.
Then, the timer goes down until its 0, and then you can attack.
I think the problem its that, once you have destroyed your enemy, nothing else happens.
I mean, you actually don´t reset the timer once the enemy is dead. That´s why it only works again, when you select another enemy.
When that happens, the BasicAttack class is called from the Targeting class, and thus, the Start method is called again.
I hope it helped.
Regards!

Related

Why does my grappling gun stay attached when I swap weapons?

When I shoot my grappling gun at a surface it works how it is supposed to but when I go to switch weapons I am still attached to the surface and I have to swap back to the grappling gun to detach myself from the surface. Does anyone know how I could make it so that I get detached when I swap weapons?
Here is the weapon switching code:
using UnityEngine;
public class WeaponSwitching : MonoBehaviour {
public int selectedWeapon = 0;
// Start is called before the first frame update
void Start()
{
SelectWeapon();
}
// Update is called once per frame
void Update() {
int previousSelectedWeapon = selectedWeapon;
if (Input.GetAxis("Mouse ScrollWheel") > 0f)
{
if (selectedWeapon >= transform.childCount - 1)
selectedWeapon = 0;
else
selectedWeapon++;
}
if (Input.GetAxis("Mouse ScrollWheel") < 0f)
{
if (selectedWeapon <= 0)
selectedWeapon = transform.childCount - 1;
else
selectedWeapon--;
}
if (Input.GetKeyDown(KeyCode.Alpha1))
{
selectedWeapon = 0;
}
if (Input.GetKeyDown(KeyCode.Alpha2))
{
selectedWeapon = 1;
}
if (Input.GetKeyDown(KeyCode.Alpha3) && transform.childCount >= 2)
{
selectedWeapon = 2;
}
if (previousSelectedWeapon != selectedWeapon)
{
SelectWeapon();
}
}
void SelectWeapon ()
{
int i = 0;
foreach (Transform weapon in transform)
{
if (i == selectedWeapon)
weapon.gameObject.SetActive(true);
else
weapon.gameObject.SetActive(false);
i++;
}
}
}
Here is the grappling gun code:
using UnityEngine;
public class GrapplingGun : MonoBehaviour {
private LineRenderer lr;
private Vector3 grapplePoint;
public LayerMask whatIsGrappleable;
public Transform gunTip, camera, 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(camera.position, camera.forward, out hit, maxDistance, whatIsGrappleable)) {
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;
currentGrapplePosition = gunTip.position;
}
}
void StopGrapple() {
lr.positionCount = 0;
Destroy(joint);
}
private Vector3 currentGrapplePosition;
void DrawRope() {
if (!joint) return;
currentGrapplePosition = Vector3.Lerp(currentGrapplePosition, grapplePoint, Time.deltaTime * 8f);
lr.SetPosition(0, gunTip.position);
lr.SetPosition(1, currentGrapplePosition);
}
public bool IsGrappling() {
return joint != null;
}
public Vector3 GetGrapplePoint() {
return grapplePoint;
}
}
Here is the grappling gun switching code:
using UnityEngine;
public class GrappleGunWeaponSwitching : MonoBehaviour
{
public int selectedWeapon = 0;
// Start is called before the first frame update
void Start()
{
SelectWeapon();
}
// Update is called once per frame
void Update() {
int previousSelectedWeapon = selectedWeapon;
if (Input.GetAxis("Mouse ScrollWheel") > 0f)
{
if (selectedWeapon >= transform.childCount - 1)
selectedWeapon = 0;
else
selectedWeapon++;
}
if (Input.GetAxis("Mouse ScrollWheel") < 0f)
{
if (selectedWeapon <= 0)
selectedWeapon = transform.childCount - 1;
else
selectedWeapon--;
}
if (Input.GetKeyDown(KeyCode.Alpha1))
{
selectedWeapon = 0;
}
if (Input.GetKeyDown(KeyCode.Alpha2) && transform.childCount >= 2)
{
selectedWeapon = 1;
}
if (previousSelectedWeapon != selectedWeapon)
{
SelectWeapon();
}
}
void SelectWeapon ()
{
int i = 0;
foreach (Transform weapon in transform)
{
if (i == selectedWeapon)
weapon.gameObject.SetActive(true);
else
weapon.gameObject.SetActive(false);
i++;
}
}
}
Here is my hierarchy:
hierarchy
Thanks
I think the GrappleGunWeaponSwitching Script is kind of redundant isnt it?
I would have 2 solutions for you I think. First of you could add the OnDisable() function (event) to the GrapplingGun Script and write something like this
void OnDisable() {
StopGrapple();
}
The Problem with this is that each time you disable the Script it will also be triggered. But I guess that wont be a problem.
Another solution may be to add a Gun Parent Script where each of your guns is a Child from. This would look like public class GrapplingGun : Gun {.
Now you will be able to change this function in WeaponSwitching
void SelectWeapon () {
int i = 0;
foreach (Transform weapon in transform) {
Gun gun = weapon.gameObject.GetComponent<Gun>();
if (i == selectedWeapon) {
gun.EnableEvent();
weapon.gameObject.SetActive(true);
} else {
gun.DisableEvent();
weapon.gameObject.SetActive(false);
}
i++;
}
}
Now you just need to add these two functions in the Gun Parent Class and overwrite it in each child so it will be called there. I hope you know some stuff about Polemorphy otherwise I may explain it to you.
Could you share a screenshot of your object hierarchy?
It looks like your SelectWeapon method iterates through child 'weapon' Transforms, so I'm guessing your weapon objects are children of the object with the WeaponSwitching script attached... is the Grappling Gun script attached to one of these child weapon gameobjects, or is it attached to the parent? If it's attached to the parent then the weapon switching isn't turning it off.
In either case, you could have your WeaponSwitching script(s) run the StopGrapple method in your GrapplingGun script when switching weapons, which I think should do the trick? Something like this:
public class WeaponSwitching : MonoBehaviour {
public int selectedWeapon = 0;
public GrapplingGun grapplingGun; // ADDED
void Start()
{
grapplingGun = gameObject.GetComponentInChildren<GrapplingGun>(); // ADDED
SelectWeapon();
}
...
void SelectWeapon ()
{
int i = 0;
foreach (Transform weapon in transform)
{
if (i == selectedWeapon)
weapon.gameObject.SetActive(true);
else
weapon.gameObject.SetActive(false);
i++;
}
if (grapplingGun != null) { grapplingGun.StopGrapple(); } // ADDED
}
}
You'd also need to set your StopGrapple method to public.
If you thought you were going to run into similar issues with other weapons you could make your weapon classes derive from a master weapon class and define different specific outcomes for generically named methods (i.e, 'Activate' and 'Deactivate'). Then you could just process the 'Deactivate' method on all weapon children whenever weapons are changed.

Unity 2d game Player and enemy not moving

I have been following a tutorial on a unity 2d game. The player and the enemy inherit from a base class known as MovingObject. Everything in the game works fine except that the player and the enemy can't move. Here are the scripts. The movement happens in a gridlike tile system.
This is the original tutorial series. Try going over the moving object, player, and enemy tutorials.
https://www.youtube.com/playlist?list=PLX2vGYjWbI0SKsNH5Rkpxvxr1dPE0Lw8F
Base MovingObject class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class MovingObject : MonoBehaviour {
public float moveTime = 0.1f;
public LayerMask blockinglayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
// Use this for initialization
protected virtual void Start () {
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
}
protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
{
Vector2 start = transform.position;
Vector2 end = start + new Vector2(xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast(start, end, blockinglayer);
boxCollider.enabled = true;
if (hit.transform == null)
{
StartCoroutine(SmoothMovement(end));
return true;
}
return false;
}
protected IEnumerator SmoothMovement(Vector3 end)
{
float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
while (sqrRemainingDistance > float.Epsilon)
{
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
rb2D.MovePosition(newPosition);
sqrRemainingDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
protected virtual void AttemptMove<T>(int xDir, int yDir)
where T : Component
{
RaycastHit2D hit;
bool canMove= Move(xDir, yDir, out hit);
if (hit.transform == null)
{
return;
}
T hitComponent = hit.transform.GetComponent<T>();
if(!canMove && hitComponent != null)
{
OnCantMove(hitComponent);
}
}
protected abstract void OnCantMove<T>(T component)
where T : Component;
// Update is called once per frame
}
Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MovingObject {
public int wallDamage = 1;
public int pointsPerFood = 10;
public int pointsPerSoda = 20;
public float restartLevelDelay = 1f;
private Animator animator;
private int food;
// Use this for initialization
protected override void Start () {
animator = GetComponent<Animator>();
food = GameManager.instance.playerFoodPoints;
base.Start();
}
private void OnDisable()
{
GameManager.instance.playerFoodPoints = food;
}
// Update is called once per frame
void Update () {
if (GameManager.instance.playersTurn)
{
return;
}
int horizontal = 0;
int vertical = 0;
horizontal = (int)Input.GetAxisRaw("Horizontal");
vertical = (int)Input.GetAxisRaw("Vertical");
if (horizontal != 0)
{
vertical = 0;
}
if(horizontal!=0 || vertical != 0)
{
AttemptMove<Wall>(horizontal, vertical);
}
}
protected override void OnCantMove<T>(T component)
{
Wall hitwall = component as Wall;
hitwall.damageWall(wallDamage);
animator.SetTrigger("playerChop");
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
food--;
base.AttemptMove<T>(xDir, yDir);
RaycastHit2D hit;
CheckIfGameOver();
GameManager.instance.playersTurn = false;
}
public void LoseFood(int loss)
{
animator.SetTrigger("playerHit");
food -= loss;
CheckIfGameOver();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Exit")
{
Invoke("Restart", restartLevelDelay);
enabled = false;
}
else if (other.tag == "Food")
{
food += pointsPerFood;
other.gameObject.SetActive(false);
}
else if (other.tag == "Soda")
{
food += pointsPerSoda;
other.gameObject.SetActive(false);
}
}
private void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
private void CheckIfGameOver()
{
if (food <= 0)
{
GameManager.instance.GameOver();
}
}
}
Enemy Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MovingObject {
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipmove;
// Use this for initialization
protected override void Start () {
GameManager.instance.AddEnemyToList(this);
animator = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
base.Start();
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
if (skipmove)
{
skipmove = false;
return;
}
base.AttemptMove<T>(xDir, yDir);
}
public void MoveEnemy()
{
int xDir = 0;
int yDir = 0;
if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
{
yDir = target.position.y > transform.position.y ? 1 : -1;
}
else
{
xDir = target.position.x > transform.position.x ? 1 : -1;
AttemptMove<Player>(xDir,yDir);
}
}
protected override void OnCantMove<T>(T component)
{
Player hitplayer = component as Player;
animator.SetTrigger("enemyAttack");
hitplayer.LoseFood(playerDamage);
}
}
I'm not sure which whether the player or enemy have an issue of the base script. Can anyone help.
A few Observations (Hopefully it helps):
MovingObject.cs - Inside of Update(), should it not be this?
if (!GameManager.instance.playersTurn)
Note I added a "!" before GameManager
Player.cs - in AttemptMove(), you need to call Move()... like this
Move (xDir, yDir, out hit);
Enemy.cs
1) At the end of AttemptMove(), there should be:
skipMove = true;
2) In MoveEnemy(), at the end, this code should NOT be in the else, but after the else:
AttemptMove<Player>(xDir,yDir);

IEnumerator not waiting for seconds

I have created an IEnumerator so that the enemy doesn't kill the player immediately on contact. the code worked fine yesterday, but now the IEnumerator seems to be completely ignored. The Unity 3d console is not showing any errors either.
I have tried to lower the damage amount to check if maybe it was too high but it wasn't the case.
the following is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class enemyAI : MonoBehaviour {
[SerializeField]
float chaseDistance = 5.0f;
public float damageAmount = 1.0f;
void Update () {
dist = Vector3.Distance(target.position, transform.position);
float distance = Vector3.Distance(transform.position, target.position);
if (distance < chaseDistance )
{
AttackPlayer();
}
}
void AttackPlayer()
{
agent.updateRotation = false;
Vector3 direction = target.position - transform.position;
direction.y = 0;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direction), turnSpeed * Time.deltaTime);
agent.updatePosition = false;
anim.SetBool("isWalking", false);
anim.SetBool("isAttacking", true);
StartCoroutine(AttackTime());
}
IEnumerator AttackTime()
{
canAttack = false;
yield return new WaitForSeconds(0.5f);
Player.singleton.Damage(damageAmount);
yield return new WaitForSeconds(2.0f);
canAttack = true;
}
}
//Player Script {
public class Player : MonoBehaviour {
public static Player singleton;
public float currentHealth;
public static float maxHealth = 100f;
public bool isDead = false;
private void Awake()
{
singleton = this;
}
// Use this for initialization
void Start () {
currentHealth = maxHealth;
}
// Update is called once per frame
void Update () {
if (currentHealth < 0)
{
currentHealth = 0;
}
}
public void Damage(float damage)
{
if(currentHealth > 0)
{
currentHealth -= damage;
}
else
{
currentHealth = 0;
}
}
void Dead()
{
currentHealth = 0;
isDead = true;
}
}
You are starting the "AttackPlayer" Coroutine in "Update()" - so when the enemy is in range, you will start ~60 Coroutines per second. While you want a single one.
You are already setting "canAttack" to "false" - maybe add "&& canAttack" to your range-condition in Update?
Like
if (distance < chaseDistance && canAttack)
{
AttackPlayer();
}
Try putting "canAttack = false;" beneath yield command

I'm creating a patrolling AI that aggros to the player and follows them in Unity 3D

I'm having trouble keeping this method running. It runs for 1 frame them shuts itself off. I am having trouble working out the logic to keep it running. Yes, the enemy does detect if the player is within a field of view, and it does stop when it collides with walls, it also stops detecting the player when they leave the fov.
I've tried changing around if statements, but it's overall very important that the code runs based on the player existing in the FOV collider. The problem is pretty specific, so I don't know what research to do.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(AudioSource))]
public class EnemyAI : MonoBehaviour
{
public float patrolSpeed, chaseSpeed, chaseWaitTime, patrolWaitTime, castRadius;
public Transform[] wayPoints, wayPOI;
public Transform player;
public Animation flinch, die;
public AudioClip grunt, callOut, death;
public LayerMask mask;
public PlayerCheck check;
private float chaseTimer, patrolTimer, wanderTimer;
private int destIndex, destInit, destStart, health;
private bool playerIn;
protected string aggro, resting, warned, sawPlayer;
protected bool patroling;
public bool aggress;
private NavMeshAgent agent;
private Transform playerLP;
private Vector3 startPos;
private Animator anim;
private AudioSource aud;
MeshCollider fieldOfView;
void Awake()
{
//patroling = true;
startPos = transform.position;
destInit = destIndex;
agent = GetComponent<NavMeshAgent>();
agent.autoRepath = true;
agent.autoBraking = true;
fieldOfView = transform.GetChild(0).GetComponent<MeshCollider>();
if (fieldOfView == null)
{
Debug.LogError("The first object MUST be FOV, otherwise the script will not work correctly. 1");
}
check = GameObject.FindObjectOfType<PlayerCheck>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
if (check == null)
{
check = GameObject.FindObjectOfType<PlayerCheck>();
}
playerIn = check.playerIn;
RaycastHit hit;
if (Physics.Linecast(transform.position, player.position, out hit, ~mask))
{
if (!playerIn)
{
Debug.DrawLine(transform.position, hit.point, Color.red);
}
else if (hit.collider.gameObject != null)
{
if (!hit.collider.CompareTag("Player"))
{
Debug.DrawLine(transform.position, hit.point, Color.blue);
return;
}
else
{
Debug.DrawLine(transform.position, hit.point, Color.green);
aggress = true;
}
}
}
if (aggress)
{
Aggro(sawPlayer);
}
if (patroling)
{
GoToNext();
}
}
void GoToNext()
{
patroling = true;
aggress = false;
if (wayPoints.Length == 0)
return;
if (playerIn)
return;
if (agent.remainingDistance < .7f)
{
agent.SetDestination(wayPoints[destIndex].position);
destIndex = (destIndex + 1) % wayPoints.Length;
}
}
void Aggro(string condition)
{
if (condition == sawPlayer)
{
Chase(player);
}
}
void Chase(Transform transform)
{
patroling = false;
if (playerIn)
{
agent.SetDestination(transform.position);
print("Chasing");
}
else
{
**Wander(sawPlayer, 15);**
print("Wander, please");
}
}
**void Wander(string condition, float time)**
{
patroling = false;
print(time);
wanderTimer += Time.deltaTime;
print("Wandering");
//this is where I'm having the most trouble, it will print wandering for 1 //frame then stop and go back to patroling
//once the player leaves the fov. I'm trying to figure out where the method //stops and why.
if (condition == sawPlayer)
{
if (wanderTimer >= time)
{
wanderTimer = 0;
if (!agent.pathPending && agent.remainingDistance < .5f)
{
GoToNext();
}
}
else
{
Vector3 vec;
vec = new Vector3(Random.Range(agent.destination.x - 10, agent.destination.x), Random.Range(agent.destination.y - 10, agent.destination.y), Random.Range(agent.destination.z - 10, agent.destination.z));
agent.destination = transform.InverseTransformDirection(vec);
if (agent.remainingDistance < .3f || wanderTimer > time)
{
GoToNext();
}
}
}
}
}

Unity2D: How to make spawn object gradually go faster after the player collects 10 points?

so I was wondering if there was a way to make a spawned object gradually moves/go faster after the player (you the user) collects 10 points. And faster when the player collects another 10 points and so on and so on?
This is my movement script attach to my objects that get spawned in:
public class Movement : MonoBehaviour
{
public static int movespeed = 20;
public Vector3 userDirection = Vector3.right;
public void Update()
{
transform.Translate(userDirection * movespeed * Time.deltaTime);
}
}
This is my score script attach to my player
public int Score;
public Text ScoreText;
void Start ()
{
Score = 0;
SetScoreText ();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
Score = Score + 1;
SetScoreText ();
}
}
void SetScoreText ()
{
ScoreText.text = "Score: " + Score.ToString ();
}
And this is my generateEnemy script:
public GameOverManager gameOverManager = null;
[HideInInspector]
public float minBlobSpawnTime = 2;
[HideInInspector]
public float maxBlobSpawnTime = 5;
[HideInInspector]
public bool generateBlobs = true;
[HideInInspector]
public GameObject blobPrefab = null;
[HideInInspector]
public GameObject blobRoot = null;
[HideInInspector]
public float minimumYPosition = -0.425f;
[HideInInspector]
public float maximumYPosition = 0.35f;
[HideInInspector]
public float minDaggerSpawnTime = 2;
[HideInInspector]
public float maxDaggerSpawnTime = 5;
[HideInInspector]
public bool generateDaggers = true;
[HideInInspector]
public GameObject daggerPrefab = null;
[HideInInspector]
public GameObject daggerRoot;
[HideInInspector]
public float minimumXPosition = -11.5f;
[HideInInspector]
public float maximumXPosition = 11.5f;
public Camera camera = null;
// Use this for initialization
void Start ()
{
generateBlobs = ((generateBlobs) && (blobPrefab != null) && (blobRoot != null));
generateDaggers = ((generateDaggers) && (daggerPrefab != null) && (daggerRoot != null));
if (camera == null)
{
Debug.LogError("GenerateEnemy: camera is not set in the inspector. Please set and try again.");
camera = Camera.main;
}
if (gameOverManager == null)
{
Debug.LogError("GenerateEnemy: gameOverManager not set in the inspector. Please set and try again.");
}
if (generateBlobs)
{
StartCoroutine(GenerateRandomEnemy(true, blobPrefab, blobRoot, minBlobSpawnTime, maxBlobSpawnTime));
}
if (generateDaggers)
{
StartCoroutine(GenerateRandomEnemy(false, daggerPrefab, daggerRoot, minDaggerSpawnTime, maxDaggerSpawnTime));
}
}
// Update is called once per frame
void Update ()
{
DestroyOffScreenEnemies();
}
// Spawn an enemy
IEnumerator GenerateRandomEnemy(bool generateOnYAxis, GameObject prefab, GameObject root, float minSpawnTime, float maxSpawnTime)
{
if ((prefab != null) && (gameOverManager != null))
{
if (!gameOverManager.GameIsPaused())
{
GameObject newEnemy = (GameObject) Instantiate(prefab);
newEnemy.transform.SetParent(root.transform, true);
// set this in the prefab instead
// newEnemy.transform.position = new Vector3(newEnemy.transform.parent.position.x, 0.5f, newEnemy.transform.parent.position.z);
// or if you want the y position to be random you need to do something like this
if (generateOnYAxis)
{
newEnemy.transform.position = new Vector3(newEnemy.transform.parent.position.x, Random.Range(minimumYPosition, maximumYPosition), newEnemy.transform.parent.position.z);
}
else
{
newEnemy.transform.position = new Vector3(Random.Range(minimumXPosition, maximumXPosition), newEnemy.transform.parent.position.y, newEnemy.transform.parent.position.z);
}
}
}
yield return new WaitForSeconds(Random.Range(minSpawnTime, maxSpawnTime));
StartCoroutine(GenerateRandomEnemy(generateOnYAxis, prefab, root, minSpawnTime, maxSpawnTime));
}
public void DestroyOffScreenEnemies()
{
GameObject[] enemies = GameObject.FindGameObjectsWithTag("enemy");
if ((enemies.Length > 0) && (camera != null))
{
for (int i = (enemies.Length - 1); i >= 0; i--)
{
// just a precaution
if ((enemies[i] != null) && ((camera.WorldToViewportPoint(enemies[i].transform.position).x > 1.03f) ||
(enemies[i].transform.position.y < -6f)))
{
Destroy(enemies[i]);
}
}
}
}
}
(This script has an generateEnemyCustomEditor script that references it, to show in the inspector)
Thank you :)
First of all, remove the static keyword from public static int movespeed = 20; and use GameObject.Find("ObjectMovementIsAttachedTo").GetComponent<Movement>(); to get the script instance if you want to modify movespeed variable from another script.
And faster when the player collects another 10 points and so on and so
on?
The solution is straight on. Use
if (Score % 10 == 0){
//Increement by number (4) movespeed from Movement script
movement.movespeed += 4;
}
to check if the Score is increased by 10 then increment movespeed by any value you want if that condition is true. It makes sense to put that in the OnTriggerEnter2D function after Score is incremented by 1.
Your new score script:
public class score : MonoBehaviour
{
public int Score;
public Text ScoreText;
private int moveSpeed;
void Start()
{
Score = 0;
SetScoreText();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Pick Up"))
{
other.gameObject.SetActive(false);
Score = Score + 1;
if (Score % 10 == 0)
{
//Increement by number (4) movespeed from Movement script
moveSpeed += 4;
}
SetScoreText();
}
}
public int getMoveSpeed()
{
return moveSpeed;
}
void SetScoreText()
{
ScoreText.text = "Score: " + Score.ToString();
}
}
Since your Movement script will be instantiated, when you instantiate it, you send its reference to the Player script.
public class Movement : MonoBehaviour
{
public int movespeed = 20;
public Vector3 userDirection = Vector3.right;
score mySpeed;
void Start()
{
//Send Movement instance to the score script
GameObject scoreGameObject = GameObject.Find("GameObjectScoreIsAttachedTo");
mySpeed = scoreGameObject.GetComponent<score>();
}
public void Update()
{
transform.Translate(userDirection * mySpeed.getMoveSpeed() * Time.deltaTime);
}
}

Categories