How do I increase speed every time I kill an enemy? - c#

I'm trying to make it so that every time I kill an enemy, my player's speed increases by 1. I've been trying to do this but I don't really know what I'm doing. Can somebody help me?
Here is my player movement script
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float MovementSpeed = 5;
public float JumpForce = 5;
private Rigidbody2D _rigidbody;
private void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
}
private void Update()
{
//Movement
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
if (Input.GetButtonDown("Jump") && Mathf.Abs(_rigidbody.velocity.y) < 0.001f)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}
}
Here is my Enemy script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemyScript : MonoBehaviour
{
public int health = 100;
private static float speed;
private static float jump;
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
Die();
speed += 1.0f;
jump += 1.0f;
}
}
void Die()
{
Destroy(gameObject);
speed = GetComponent<PlayerMovement>().MovementSpeed;
jump = GetComponent<PlayerMovement>().JumpForce;
}
}
Sorry, my question didn't have all the details, the player is not gaining any speed. I tried using
GetComponent<PlayerMovement>().MovementSpeed += 1.0f;
GetComponent<PlayerMovement>().JumpForce += 1.0f;
and now I'm getting this error message
NullReferenceException: Object reference not set to an instance of an object
Sorry for the inconvenience

First of all it makes no sense to use GetComponent since the PlayerMovement is not attached to your enemy objects.
Then
speed = GetComponent<PlayerMovement>().MovementSpeed;
jump = GetComponent<PlayerMovement>().JumpForce
is also the wrong way round .. what use would it be to take the value from the player and store it in a field of the enemy?
If there is only one player anyway you could simply use FindObjectOfType and do
void Die()
{
Destroy(gameObject);
FindObjectOfType<PlayerMovement>().MovementSpeed += 1.0f;
FindObjectOfType<PlayerMovement>().JumpForce += 1.0f;
}
Or alternatively use a Singleton Pattern as actually even suggested by before mentioned docs like e.g.
public class PlayerMovement : MonoBehaviour
{
public static PlayerMovement Instance { get; private set;}
private void Awake ()
{
if(Instance && Instance!= this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
...
}
and then simply do
void Die()
{
Destroy(gameObject);
PlayerMovement.Instance.MovementSpeed += 1.0f;
PlayerMovement.Instance.JumpForce += 1.0f;
}

I am assuming you want to increase the jumpforce and speed of your player when the player kills an enemy. Also, Could you please elaborate the question if you are getting any error or just the speed is not increasing?
Please find the inline response for the Enemy Script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemyScript : MonoBehaviour
{
public int health = 100;
private static float speed;//This is enemy speed variable that you have declared
private static float jump;//This is enemy jump variable that you have declared
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
Die();
//speed += 1.0f; Here you are increasing enemy speed and not playerspeed.
//jump += 1.0f; Same goes for jump.
}
}
void Die()
{
Destroy(gameObject);
//speed = GetComponent<PlayerMovement>().MovementSpeed; here you are assigning Player movement speed to enemy speed.
//jump = GetComponent<PlayerMovement>().JumpForce; here you are assigning Player movement jump to enemy jump.
//Instead try
GetComponent<PlayerMovement>().MovementSpeed += 1.0f;
GetComponent<PlayerMovement>().JumpForce += 1.0f;
}
}
Also you can use
Debug.Log(your movementspeed variable);
to check if the player speed is being increased or not.

Related

Why does my enemy one hit me when I have 3 lives

I am in the process of making a game in Unity and I have run into a problem. I created a heart system UI + script and and enemy + script. In my game, I have 3 lives but when I made the enemy attack me, he one hits me. Is there a way that I can have a delay between each attack.
Here are the scripts.
Enemy Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public Transform attackPoint;
public float attackrange = 0.5f;
public LayerMask playerlayers;
public float speed = 3f;
private Transform target;
IEnumerator Cooldown()
{
yield return new WaitForSeconds(3);
}
private void Update()
{
if (target != null)
{
float step = speed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, target.position, step);
Collider2D[] hitplayers = Physics2D.OverlapCircleAll(attackPoint.position, attackrange, playerlayers);
foreach (Collider2D player in hitplayers)
{
player.GetComponent<HeartSystem>().TakeDamage(1);
StartCoroutine(Cooldown());
}
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
target = other.transform;
}
}
private void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
target = null;
}
}
void OnDrawGizmosSelected()
{
if (attackPoint == null)
return;
Gizmos.DrawWireSphere(attackPoint.position, attackrange);
}
}
And here is my health system script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class HeartSystem : MonoBehaviour
{
public GameObject[] hearts;
public int life;
void Update()
{
if (life < 1)
{
Destroy(hearts[0].gameObject);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
else if (life < 2)
{
Destroy(hearts[1].gameObject);
}
else if (life < 3)
{
Destroy(hearts[2].gameObject);
}
}
public void TakeDamage(int d)
{
life -= d;
}
}
I hope we can find a solution.
So from what i understood from your code: the enemy targets the player on collision and once the player is targeted it receives damage on update.
The problem may be caused by the fact that the update method runs more than once until the collision ends. That would mean that your cooldown is not working.
I don't understand the way your timer works but I can tell you how i usually do.
Let's say the cooldown is 1sec. After attacking the player the first time you get the current time, add 1 second to it and store it like "nextAttackTime". Next time the enemy tries to attack it will check if the current time is equal or higher to the "nextAttackTime".
Your way of doing the cooldown looks very elegant but if it really isn't working you can consider trying it the way i described. it may not be as elegant but it is reliable.
-----EDIT-----
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public Transform attackPoint;
public float attackrange = 0.5f;
public LayerMask playerlayers;
public float speed = 3f;
private Transform target;
//First we will need a variable to store the time when the next attack will be possible, it starts with 0. We'll also create a public variable to define the cooldown duration
private float nextAttackTime = 0f;
public float attackCoolDown = 3f;
IEnumerator Cooldown()
{
yield return new WaitForSeconds(3);
}
private void Update()
{
if (target != null)
{
float step = speed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, target.position, step);
Collider2D[] hitplayers = Physics2D.OverlapCircleAll(attackPoint.position, attackrange, playerlayers);
foreach (Collider2D player in hitplayers)
{
//then before dealing the damage we check if it is already time to attack again
if(Time.time >= nextAttackTime){
player.GetComponent<HeartSystem>().TakeDamage(1);
//After dealing damage we reset the time for the next attack. The Time.time should return the time in seconds that the game has been running and we'll add 3 seconds to that to define the time for the next attack.
nextAttackTime = (Time.time + attackCoolDown);
//StartCoroutine(Cooldown());
}
}
}
}
So this is the editted code with the changes I suggested. I edited it right here in StackOverflow with no help of a code editor so there could be some typos.

Unity 3D : NullReferenceException with Player health [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
In Unity (C#), why am I getting a NullReferenceException and how do I fix it? [duplicate]
(1 answer)
Closed 1 year ago.
I'm a beginner developper and I just started making my own game but in my advancement I got stuck with the creation of an enemy.
The goal of this script is to move the enemy, catch the player and most of all making damages to the player, but in this case, I cannot make link between my player health and my enemy controller script because of the NullReferenceException error that haunts me. It's the only error I have and I've searched everywhere to fix my error but don't find anything.
This is my EnemyController script which I know is not really optimized but whatever.
The real problem is right here at the line 49 in the Update function (if(playerHealth == null){})
All of my scripts are connected, here are all scripts I used for this.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyContoller : MonoBehaviour
{
public float lookRadius = 10f;
public float maxHealth = 100f;
public float currentHealth;
Transform target;
NavMeshAgent agent;
public HealthBarScript healthBar;
public Animator anim;
EnemyAttack attack;
PlayerHealth playerHealth;
// Update is called once per frame
void Start()
{
attack = GetComponent<EnemyAttack>();
anim = GetComponent<Animator>();
gameObject.layer = 6;
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
target = PlayerManager.instance.player.transform;
agent = GetComponent<NavMeshAgent>();
playerHealth = GetComponent<PlayerHealth>();
}
void Update()
{
float distance = Vector3.Distance(target.position, transform.position);
if(distance <= lookRadius)
{
anim.speed = agent.speed;
anim.SetBool("isRunning",true);
agent.SetDestination(target.position);
}else{
anim.speed = 0;
anim.SetBool("isRunning",false);
}
if(distance <= agent.stoppingDistance)
{
if(playerHealth != null)
{
attack.MakeDamage(attack.damages, playerHealth);
Debug.Log(playerHealth.currentHealth);
}
else if(playerHealth == null)
{
Debug.Log("Player Health = null");
}
FaceTarget();
}
}
public void TakeDamage(float amount){
currentHealth -= amount;
healthBar.SetHealth(currentHealth);
if(currentHealth <= 0)
{
Die();
}
}
void Die()
{
Destroy(gameObject);
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, lookRadius);
}
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 * 3f);
}
}
This is my Enemy Attack script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour
{
public float damages = 10f;
public float damageRate = 1f;
private float damageCooldown = 0f;
PlayerHealth pH;
void Update()
{
damageCooldown -= Time.deltaTime;
}
public void MakeDamage(float amount, PlayerHealth health)
{
if(damageCooldown <= 0f)
{
pH.TakeDamage(damages);
Debug.Log(health);
damageCooldown = 1f / damageRate;
}
}
}
This my PlayerHealth script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
public float currentHealth;
public float maxHealth = 50f;
public HealthBarScript healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
}
public void TakeDamage(float amount)
{
currentHealth -= amount;
healthBar.SetHealth(currentHealth);
Debug.Log(currentHealth);
if(currentHealth <= 0)
{
Debug.Log("You're Dead.");
Time.timeScale = 0;
}
}
}
If someone could help me that would be great I don't know what to do to fix this bug that lasts for 2 days.

Unity prefab movement

Hello i want to create a group of the same prefab following the player in my game. I already got the prefab intantiation to follow the player but when there is more than one they just follow the exact same path on top of each other. is there a way where they can follow the player but act like a bunch of bees moving?
Thanks!
This is the script on my prefab:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class KillerMovement : MonoBehaviour {
public GameObject player;
void FixedUpdate()
{
Vector2 toTarget = player.transform.position - transform.position;
float speed = 0.5f;
transform.Translate(toTarget * speed * Time.deltaTime);
}
}
The best solution depends on you game logic, but you may consider having a delay before starting following (you can tweak the delay depending on the position you want to the particular object to assume in the trail.
using System.Collections;
using UnityEngine;
public class Follower : MonoBehaviour
{
public GameObject player;
public float delay = 0f;
public float speed = .5f;
bool isReady = false;
void Start()
{
StartFollowing();
}
public void StartFollowing()
{
StartCoroutine(WaitThenFollow(delay));
}
IEnumerator WaitThenFollow(float delay)
{
yield return new WaitForSeconds(delay);
isReady = true;
Debug.Log(gameObject.name);
Debug.Log(Time.time);
}
void FixedUpdate()
{
if (isReady && player != null)
{
Vector2 toTarget = player.transform.position - transform.position;
transform.Translate(toTarget * speed * Time.deltaTime);
}
}
}
I've called StartFollowing in the Start method for you to test the code. You should call this method whenever approrpiate in your game logic.

How to make enemies turn and move towards player when near? Unity3D

I am trying to make my enemy object turn and start moving towards my player object when the player comes within a certain vicinity.
For the turning I have been testing the transform.LookAt() function although it isn't returning the desired results as when the player is too close to the enemy object the enemy starts to tilt backwards and I only want my enemy to be able to rotate along the y axis, thanks in advance.
using UnityEngine;
using System.Collections;
public class EnemyController : MonoBehaviour {
public Transform visionPoint;
private PlayerController player;
public Transform Player;
public float visionAngle = 30f;
public float visionDistance = 10f;
public float moveSpeed = 2f;
public float chaseDistance = 3f;
private Vector3? lastKnownPlayerPosition;
// Use this for initialization
void Start () {
player = GameObject.FindObjectOfType<PlayerController> ();
}
// Update is called once per frame
void Update () {
// Not giving the desired results
transform.LookAt(Player);
}
void FixedUpdate () {
}
void Look () {
Vector3 deltaToPlayer = player.transform.position - visionPoint.position;
Vector3 directionToPlayer = deltaToPlayer.normalized;
float dot = Vector3.Dot (transform.forward, directionToPlayer);
if (dot < 0) {
return;
}
float distanceToPlayer = directionToPlayer.magnitude;
if (distanceToPlayer > visionDistance)
{
return;
}
float angle = Vector3.Angle (transform.forward, directionToPlayer);
if(angle > visionAngle)
{
return;
}
RaycastHit hit;
if(Physics.Raycast(transform.position, directionToPlayer, out hit, visionDistance))
{
if (hit.collider.gameObject == player.gameObject)
{
lastKnownPlayerPosition = player.transform.position;
}
}
}
}
change the look at target:
void Update () {
Vector3 lookAt = Player.position;
lookAt.y = transform.position.y;
transform.LookAt(lookAt);
}
this way the look at target will be on the same height as your object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyMovement : MonoBehaviour
{
public Transform Player;
public float MoveSpeed = 4;
int MaxDist = 10;
int MinDist = 5;
void Update()
{
transform.LookAt(Player);
if (Vector3.Distance(transform.position, Player.position) >= MinDist)
{
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
if (Vector3.Distance(transform.position, Player.position) <= MaxDist)
{
// Put what do you want to happen here
}
}
}
}

How to get a projectile to shoot towards a gameobject

Im currently working on a TurretAi. I have it so that when the enemy is within a certain range the turret targets the enemy but I'm unable to get the turret to shoot the projectiles toward the enemy. this is currently what i have this is turret class.
using UnityEngine;
using System.Collections;
public class Defence : MonoBehaviour {
public float DistanceFromCastle,CoolDown;
public GameObject enemy;
public GameObject Bullet;
public int protectionRadius,bulletSpeed;
// Use this for initialization
void Start ()
{
protectionRadius = 35;
bulletSpeed = 50;
CoolDown = 5;
}
// Update is called once per frame
void Update () {
enemy = GameObject.FindGameObjectWithTag("Enemy");
if(enemy != null)
{
DistanceFromCastle = Vector3.Distance(GameObject.FindGameObjectWithTag("Enemy").transform.position,GameObject.FindGameObjectWithTag("Defence").transform.position);
//print (DistanceFromCastle);
if(DistanceFromCastle <= protectionRadius)
{
attackEnemy();
}
}
}
void attackEnemy()
{
transform.LookAt(enemy.transform);
CoolDown -= Time.deltaTime;
if (CoolDown <= 0)
{
Debug.DrawLine(transform.position,enemy.transform.position,Color.red);
Instantiate(Bullet,Vector3.forward,Quaternion.identity);
print("attack Enemy");
CoolDown = 5;
}
}
}
I also already have a cool down var so that it only shoot every 5 second any help would be awesome.
You were fairly close, you need to change this line:
Instantiate(Bullet, Vector3.forward, Quaternion.identity);
To this:
private const int SPAWN_DISTANCE = 5;
Instantiate(Bullet, transform.position + SPAWN_DISTANCE * transform.forward, transform.rotation);
Quaternion.identity refers to:
This quaternion corresponds to "no rotation".

Categories