I am trying to develop an AI that works with photon networking system, in unity engine. It should be fairly simple: it runs to a random player till it reaches 5 units distance between him and player, then it walk at a slightly slower speed till it reaches the front of the player. Then he attacks. So far so good, but sometimes, the AI get stuck right when it reaches 5 units distance between him and the player. I tried several fixes from the internet, but nothing worked.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(PhotonView))]
[RequireComponent(typeof(PhotonTransformView))]
public class EnemyAI : Photon.MonoBehaviour {
NavMeshAgent agent;
Animator anim;
PlayerController target;
[Header("Base settings")]
[SerializeField]
float health = 100f, damage, timeBetweenAttacks = 5f;
[Space]
[Header("Enemy Ragdoll")]
[SerializeField]
GameObject ragdoll;
AudioSource emotAud, stepAud;
[Space]
[SerializeField]
[Header("Audio")]
List<AudioClip> attackingAuds;
[Space]
[Header("Sunete pasi")]
[SerializeField]
List<AudioClip> stepAuds;
[Space]
[Header("Alte optiuni")]
[SerializeField]
float distantaLaCareIncepeSaMearga = 5f, walkSpeed = .5f, runSpeed = 3.5f;
bool dead, walking;
PhotonView killer;
float nextAttackTime;
// Use this for initialization
void Start () {
emotAud = gameObject.AddComponent<AudioSource>();
stepAud = gameObject.AddComponent<AudioSource>();
emotAud.spatialBlend = 1;
emotAud.maxDistance = 7;
stepAud.spatialBlend = 1;
stepAud.maxDistance = 7;
emotAud.playOnAwake = false;
stepAud.playOnAwake = false;
dead = false;
target = null;
agent = GetComponent<NavMeshAgent>();
anim = GetComponent<Animator>();
killer = null;
}
// Update is called once per frame
void Update () {
if (photonView.isMine)
{
if (walking)
{
agent.speed = walkSpeed;
}
else
{
agent.speed = runSpeed;
}
if (health <= 0)
{
if (!dead)
{
dead = true;
photonView.RPC("die", PhotonTargets.AllBuffered);
}
}
if (!target)
{
if (!PhotonNetwork.offlineMode)
{
nextAttackTime = (float)PhotonNetwork.room.CustomProperties["remainTime"];
}
else
{
nextAttackTime = 0f;
}
PlayerController[] controllers = FindObjectsOfType<PlayerController>();
int randCh = Random.Range(0, controllers.Length);
if (controllers.Length > 0)
{
target = controllers[randCh];
}
anim.SetFloat("move", 0);
}
else
{
if (Vector3.Distance(transform.position, target.gameObject.transform.position) > 1.8f)
{
if (Vector3.Distance(transform.position, target.gameObject.transform.position) > distantaLaCareIncepeSaMearga)
{
walking = false;
}
else
{
walking = true;
}
anim.SetBool("walking", walking);
anim.SetFloat("move", 1);
//print("Active: " + agent.isActiveAndEnabled + " Pend: " + agent.pathPending + " Has path: " + agent.hasPath);
if (agent.isActiveAndEnabled)
{
if (!agent.pathPending)
{
agent.SetDestination(target.gameObject.transform.position - transform.forward * 1.2f);
}
}
}
else
{
if (!PhotonNetwork.offlineMode)
{
if (nextAttackTime >= (float)PhotonNetwork.room.CustomProperties["remainTime"])
{
anim.SetTrigger("attack");
nextAttackTime -= timeBetweenAttacks;
}
else
{
anim.SetFloat("move", 0);
}
}
else
{
if (nextAttackTime <= 0f)
{
anim.SetTrigger("attack");
nextAttackTime += timeBetweenAttacks;
}
else
{
nextAttackTime -= Time.deltaTime;
anim.SetFloat("move", 0);
}
}
}
}
}
}
void OnDrawGizmosSelected()
{
if (target)
{
Gizmos.color = Color.blue;
Gizmos.DrawSphere(agent.destination, 1);
}
}
[PunRPC]
void die()
{
if (killer)
{
killer.gameObject.GetComponent<PlayerController>().kill();
}
if (attackingAuds.Count > 0)
{
emotAud.clip = attackingAuds[Random.Range(0, attackingAuds.Count - 1)];
emotAud.Play();
}
gameObject.GetComponent<CapsuleCollider>().enabled = false;
Instantiate(ragdoll, transform.position, transform.rotation);
Destroy(this.gameObject);
}
public void attack()
{
if (target && target.health >= 0)
{
if (Vector3.Distance(target.gameObject.transform.position, transform.position) <= 2f)
{
target.doDamage(damage);
if (target.health <= 0)
{
target.photonView.RPC("die", PhotonTargets.All, true);
}
}
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag.Contains("Bullet"))
{
killer = col.gameObject.GetComponent<Magic_Bullet>().owner;
target = killer.gameObject.GetComponent<PlayerController>();
photonView.RPC("takeDamage", PhotonTargets.AllBuffered, col.gameObject.GetComponent<Magic_Bullet>().damage);
PhotonNetwork.Destroy(col.gameObject);
}
}
[PunRPC]
void takeDamage(float dmg)
{
health -= dmg;
}
public void step()
{
stepAud.clip = stepAuds[Random.Range(0, stepAuds.Count - 1)];
stepAud.Play();
}
}
What am I doing wrong?
Well there's a hell of if else in your update function which just gives a headache to all of us,
Instead, try implementing a simple FSM using scriptableobject (as unity official tutorials ) or Coroutines which requires hard coding and is not recommended.
https://unity3d.com/learn/tutorials/topics/navigation/finite-state-ai-delegate-pattern
Related
I am trying to create an enemy that is 'smart', that changes a weapon if it has no ammo left and if all its weapons are depleted of ammo find the nearest weapon and change the weapon.
So far, I have an enemy that can patrol, find player in range, chase and attack the player.
Here is the code:
public class EnemyControler : MonoBehaviour
{
[Header("Attack")]
[SerializeField] float shootingDistance =10.0f;
[SerializeField] float shootDelay = 3.5f;
[Range(0,1.0f)][SerializeField] float shootingAccuracy =0.5f;
[SerializeField] int shootDamage =5;
[SerializeField] int ammo = 1;
[Header("User Interface")]
public Transform canvasTr;
public Slider Healthbar;
[Header("Health/Damage/Death")]
public float MaxHealth;
public float Damage;
public float AttackRange;
public int deathCounter;
public Transform ammoObject;
private NavMeshAgent navAgent;
private Collider enemycollider;
private Transform PlayerTr;
private Animator EnemyAnim;
float Health;
bool showingHealthBar, alive;
bool isPatrolling =false;
bool isInShootingRange =false;
bool canResumeIdleState =true;
bool isPreparingToShoot=false;
bool isDead =false;
bool isAlerted =false;
float shootTimer = Mathf.Infinity;
AIPatrolBehavior aIPatrolBehavior = null;
void Start()
{
Health = MaxHealth;
canvasTr.gameObject.SetActive(false);
navAgent = GetComponent<NavMeshAgent>();
EnemyAnim = GetComponent<Animator>();
enemycollider = GetComponent<Collider>();
PlayerTr = GameObject.FindGameObjectWithTag("Player").transform;
aIPatrolBehavior = GetComponent<AIPatrolBehavior>();
alive = true;
ammo = 100;
StartCoroutine(Idle());
// are you sure you want to randomly change MaxHealth after settting health = maxHealth?
//the slider gets weirdly bugged
// MaxHealth = Random.Range(50, 200);
Healthbar.maxValue = MaxHealth; // set the max value to MaxHelth
}
private void Update()
{
if(isDead)return;
if(Vector3.Distance(PlayerTr.transform.position, transform.position) > 20 && !isAlerted
|| PlayerTr.GetComponent<PlayerController>().HealthBar.value <= 0.0f){
StopAllCoroutines();
GetComponent<AIPatrolBehavior>().enabled =true;
return;
}
if(Vector3.Distance(PlayerTr.transform.position, transform.position) < 20 && isAlerted) isAlerted=false;
isInShootingRange = DistanceToPlayer() < shootingDistance &&
DistanceToPlayer() > AttackRange - 0.5f &&
PlayerTr.GetComponent<PlayerController>().HealthBar.value > 0;
if(isInShootingRange)
{
if(canResumeIdleState){
StopAllCoroutines();
canResumeIdleState=false;
}
ProcessShooting();
} else{
if(!canResumeIdleState){
isPreparingToShoot =false;
StartCoroutine(Idle());
canResumeIdleState =true;
navAgent.enabled =true;
}
}
}
private void ProcessShooting()
{
if(!isPreparingToShoot) shootTimer +=Time.deltaTime;
navAgent.enabled =false;
transform.LookAt(PlayerTr);
float randomProbability =Random.Range(0,1.0f);
if(shootTimer > shootDelay){
ShootAtPlayer();
}
EnemyAnim.SetFloat("MovmentSpeed", 0, 0.3f, Time.deltaTime);
}
private void ShootAtPlayer(){
if(isPreparingToShoot)return;
EnemyAnim.SetBool("PrepareAttack", false);
shootTimer =0.0f;
isPreparingToShoot = true;
EnemyAnim.SetTrigger("shoot");
}
public void ShootPlayerAnimationEvent(){
Debug.Log("Player got shot");
float randomAccuracy = Random.Range(0, 1.0f);
bool willHitTarget = randomAccuracy > 1.0f - shootingAccuracy;
if(willHitTarget && DistanceToPlayer() < shootingDistance){
PlayerTr.GetComponent<PlayerController>().DoDamage(shootDamage,true);
}
GetComponentInChildren<AIWeapon>().UseWeapon();
isPreparingToShoot =false;
}
IEnumerator Idle()
{
EnemyAnim.SetBool("PrepareAttack", false);
yield return new WaitUntil(() => Vector3.Distance(PlayerTr.transform.position, transform.position) < 20 || isAlerted);
StartCoroutine(RunToTarget());
}
IEnumerator RunToTarget()
{
aIPatrolBehavior.enabled =false;
if(navAgent.isOnNavMesh) { // save from error apperng
navAgent.isStopped = false;
}
EnemyAnim.SetTrigger("Attack");
while (Vector3.Distance(PlayerTr.transform.position, transform.position) > AttackRange - 0.5f)
{
if(navAgent.isOnNavMesh) { // save from error apperng
navAgent.SetDestination(PlayerTr.position);
}
// navAgent.SetDestination(PlayerTr.position);
EnemyAnim.SetFloat("MovmentSpeed", 1, 0.3f, Time.deltaTime);
yield return null;
}
StartCoroutine(Attack());
}
IEnumerator Attack()
{
EnemyAnim.SetBool("PrepareAttack", true);
navAgent.isStopped = true;
while (Vector3.Distance(PlayerTr.position, transform.position) < AttackRange)
{
EnemyAnim.SetTrigger("Attack");
float t = 0.5f;
while (t > 0)
{
Vector3 rotation = Vector3.RotateTowards(transform.forward, PlayerTr.position - transform.position, 5f * Time.deltaTime, 1f);
transform.forward = rotation;
t -= Time.deltaTime;
yield return null;
}
yield return null;
}
EnemyAnim.SetBool("PrepareAttack", false);
StartCoroutine(RunToTarget());
}
float DistanceToPlayer(){
return Vector3.Distance(transform.position,PlayerTr.position);
}
public void DoDamage(float damage)
{
Alert();
if (!showingHealthBar)
{
showingHealthBar = true;
StartCoroutine(ShowHealthBar());
}
Health -= damage;
Debug.Log("Health: " + Health + " of: " + MaxHealth);
Healthbar.value = Health;
if (Health <= 0)
{
StopAllCoroutines();
if(navAgent.isOnNavMesh) { // save from error apperng
navAgent.isStopped = true;
}
if (alive)
{
alive = true; // does this make sense?
StartCoroutine(Death());
}
}
}
I have tried searching through Google to find any tutorials, but without success. Does anyone have any ideas?
if the weapons placed on constant places all over the map, you can make the enemy stop patrolling or chasing the player when his ammo == 0 by a Boolean then use MoveTowrds() the weapon.
and u can include some way to calculate the distance between the enemy's position and all the weapons on the array, then it head for the closest.
you will use an array of vectors to store the locations of weapons.
now its your turn to try.
I am currently learning C# as I'm studying a Games Design Course at University. I am currently implementing a system where: when the time reaches 0, the game pauses and ends. This works :).
However, at first I tried implementing the code into another script - but doesn't work on that script. This has puzzled me. Here is the code (that works):
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Health : MonoBehaviour
{
private Text TimeText;
public float HealthTimer;
public bool TimeIsRunning;
public GameObject CanvasEnd;
void Start()
{
TimeText = GameObject.Find("Timer").GetComponent<Text>();
TimeIsRunning = true;
CanvasEnd.SetActive(false);
}
void Update()
{
TimeText.text = HealthTimer.ToString("0");
if (TimeIsRunning == true)
{
if (HealthTimer > 0)
{
HealthTimer -= 1 * Time.deltaTime;
}
else
{
Time.timeScale = 0;
CanvasEnd.SetActive(true);
}
if(HealthTimer == 0)
{
TimeIsRunning = false;
HealthTimer = 0;
}
}
This script is directly attached to the timer. But I don't understand why it doesn't work when I implement it into another script (that already controls other game aspects). There were no errors, and everything was declared properly.
The exact same code was put into this script (in void update) and didn't work:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public GameObject Player;
public GameObject PlayerTracker;
public GameObject BlueBottle;
public GameObject GreenBottle;
public GameObject RedBottle;
public GameObject ChestCanvas;
public float Score;
public float ChestScoreK = 0;
private Text HT;
private Text HC;
private Text Port;
private Text TimeText;
float speed = 4;
float rotSpeed = 80;
float rot = 0f;
float gravity = 8;
// Variables counting Blue, Red and Green bottles
public int BBCounter = 0;
public int RBCounter = 0;
public int GBCounter = 0;
public int CCounter = 0;
Vector3 moveDir = Vector3.zero;
CharacterController controller;
Animator anim;
void Start()
{
controller = GetComponent<CharacterController>();
anim = GetComponent<Animator>();
ChestCanvas.SetActive(false);
TimeText = GameObject.Find("Timer").GetComponent<Text>();
}
void Update()
{
//Script was implemented here
if (controller.isGrounded)
{
if (Input.GetKey(KeyCode.W))
{
anim.SetInteger("condition", 1);
moveDir = new Vector3(0, 0, 1);
moveDir *= speed;
moveDir = transform.TransformDirection (moveDir);
}
if (Input.GetKeyUp(KeyCode.W))
{
anim.SetInteger("condition", 0);
moveDir = new Vector3(0, 0, 0);
}
}
rot += Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;
transform.eulerAngles = new Vector3(0, rot, 0);
moveDir.y -= gravity * Time.deltaTime;
controller.Move(moveDir * Time.deltaTime);
}
private void FixedUpdate()
{
PlayerTracker.transform.position = Player.transform.position;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "BlueBottle")
{
Debug.Log("BLUE");
BBCounter = BBCounter + 1;
GameObject MasterScriptBlue = GameObject.Find("GameMaster");
MasterScriptBlue.GetComponent<GameMasterScript>();
MasterScriptBlue.GetComponent<GameMasterScript>().BlueBottleCounter = BBCounter;
}
if (other.gameObject.tag == "RedBottle")
{
Debug.Log("RED");
RBCounter = RBCounter + 1;
GameObject MasterScriptRed = GameObject.Find("GameMaster");
MasterScriptRed.GetComponent<GameMasterScript>();
MasterScriptRed.GetComponent<GameMasterScript>().RedBottleCounter = RBCounter;
}
if (other.gameObject.tag == "GreenBottle")
{
Debug.Log("GREEN");
GBCounter = GBCounter + 1;
GameObject MasterScriptGreen = GameObject.Find("GameMaster");
MasterScriptGreen.GetComponent<GameMasterScript>();
MasterScriptGreen.GetComponent<GameMasterScript>().GreenBottleCounter = GBCounter;
}
if(other.gameObject.tag == "CityCollider")
{
GameObject HuntingCity = GameObject.Find("HC");
Destroy(HuntingCity);
ScoringSystem.theScore += 100;
Destroy(other.gameObject);
Debug.Log("Destroyed");
}
if(other.gameObject.tag == "TownCollider")
{
GameObject HuntingTown = GameObject.Find("HT");
Destroy(HuntingTown);
ScoringSystem.theScore += 100;
Destroy(other.gameObject);
Debug.Log("Destroyed");
Debug.Log("Destroyed");
}
if(other.gameObject.tag == "PortCollider")
{
GameObject Port = GameObject.Find("Port");
Destroy(Port);
ScoringSystem.theScore += 100;
Destroy(other.gameObject);
Debug.Log("Destroyed");
}
if(other.gameObject.tag == "Chest")
{
Time.timeScale = 0;
ChestCanvas.SetActive(true);
ChestScoreK += 1;
GameObject MasterScriptChest = GameObject.Find("GameMaster");
MasterScriptChest.GetComponent<GameMasterScript>().ChestScore += ChestScoreK;
Destroy(other.gameObject);
GameObject HealthScript = GameObject.Find("Timer");
HealthScript.GetComponent<Health>().TimeIsRunning = false;
}
}
}
What can I try next?
It's hard to understand the problem from your question, but if you are looking for potential problems in your script then it looks like you are comparing a float to zero here:
if(HealthTimer == 0)
{
TimeIsRunning = false;
HealthTimer = 0;
}
So it is possible that HealthTimer is never exactly zero.
You probbaly want if (HealthTimer <= 0f) instead, or to move that block into the else block of your preceding if statement.
Other differences with the second script are:
the second script is not setting TimeIsRunning = true; in the Start() method,
other methods set Time.timeScale = 0; in the second script (not sure what impact this has, but may be relevant).
Do you have the same 'using' tags at the top of your scripts? The 'text' class only exists in UnityEngine.UI, and not UnityEngine.
There was a very interesting error with game characters, on the first level they walk quietly and everything is OK, and on the second they go only in the editor, and after compilation they are no longer there. Ai navigation exists. The character must find ... by the tag maybe he is on stage. What could be the problem? error only at the second level and only after assembly
mob script(They do not go, they do not attack if you approach. So either they don’t see or an error in the script on the phone occurs)
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class EmenScript: MonoBehaviour
{
public NavMeshAgent agent;
public Animator animator;
public GameObject zombieObject;
private Transform player;
private float curr_time;
private int xp = 100;
void Start()
{
player = GameObject.FindGameObjectsWithTag("Player")[0].transform;
StartCoroutine(findPath());
StartCoroutine(playerDetected());
curr_time = 0f;
}
public void damage()
{
if(xp == 0)
{
gameObject.transform.Find("Xp/Cube/").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
} else {
xp = xp > 15 ? xp - 15 : 0;
Transform xpp = gameObject.transform.Find("Xp/Cube/XpLine").transform;
xpp.localScale = new Vector3(xpp.localScale.x, xpp.localScale.y, xp / 100f);
xpp.localPosition = new Vector3(xpp.localPosition.x, xpp.localPosition.y, (0.97f - xpp.localScale.z) / 2);
}
}
public void damageFull()
{
gameObject.transform.Find("Xp/Cube").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
}
IEnumerator playerDetected()
{
while(true)
{
if(player == null)
{
break;
}
if(player.GetComponent<UserController>().xp <= 0)
{
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
if(Vector3.Distance(transform.position, player.position) < 1.2f)
{
animator.SetTrigger("attack");
curr_time -= Time.deltaTime;
if(curr_time <= 0)
{
if(player.GetComponent<UserController>().xp - 25 > 0)
{
player.GetComponent<UserController>().xp -= 25;
}
else
{
player.GetComponent<UserController>().xp = 0;
}
curr_time = 0.5f;
}
}
yield return new WaitForSeconds(.3f);
}
}
IEnumerator findPath()
{
while(true)
{
if(player.GetComponent<UserController>().xp > 0)
{
if(Vector3.Distance(transform.position, player.position) < 40f)
{
animator.SetBool("walk", true);
if(player && agent.isActiveAndEnabled)
{
agent.GetComponent<NavMeshAgent>().isStopped = false;
agent.SetDestination(player.position);
}
} else {
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
}
yield return new WaitForSeconds(0.2f);
}
}
}
I think error must be about scene change but I need to see script and lvl's.
https://gyazo.com/0a29918f513316fc4143a5ff76095bd3
This is how it looks visually.
That's my shooting weapon code:
public class Weapon : MonoBehaviour {
public float fireRate = 0;
public float maxDamage = 10;
public LayerMask whatToHit ;
public Transform BulletTrailPrefab;
public Transform MuzzleFlashPrefab;
public Transform HitPrefab;
float timeToSpawnEffect = 0;
public float effectSpawnRate = 10;
float timeToFire = 0;
Transform firePoint;
// Use this for initialization
void Awake () {
firePoint = transform.FindChild("FirePoint");
if(firePoint == null)
{
Debug.LogError("No FirePoint");
}
}
// Update is called once per frame
void Update () {
if(fireRate == 0)
{
if (Input.GetButtonDown("Fire1"))
{
Shoot();
}
}else
{
if(Input.GetButton("Fire1") && Time.time > timeToFire)
{
timeToFire = Time.time + 1 / fireRate;
Shoot();
}
}
}
void Shoot()
{
Vector2 mousePosition = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
Vector2 firePointPosition = new Vector2(firePoint.position.x, firePoint.position.y);
RaycastHit2D hit = Physics2D.Raycast(firePointPosition,mousePosition - firePointPosition,100,whatToHit);
Debug.DrawLine(firePointPosition, (mousePosition - firePointPosition) * 100,Color.cyan);
if(hit.collider != null)
{
Debug.DrawLine(firePointPosition, hit.point, Color.red);
Enemy enemy = hit.collider.GetComponent<Enemy>();
if(enemy != null)
{
enemy.DamageEnemy(Random.Range(maxDamage/2,maxDamage));
// Debug.Log("we hit" + hit.collider.name + " and did: " + maxDamage + " damage");
}
}
if (Time.time >= timeToSpawnEffect)
{
Vector3 hitPos;
Vector3 hitNormal;
if (hit.collider == null)
{
hitPos = (mousePosition - firePointPosition) * 30;
hitNormal = new Vector3(9999, 9999, 9999);
}
else
{
hitPos = hit.point;
hitNormal = hit.normal;
}
Effect(hitPos,hitNormal);
timeToSpawnEffect = Time.time + 1 / effectSpawnRate;
}
}
void Effect(Vector3 hitPos, Vector3 hitNormal)
{
Transform trail = Instantiate(BulletTrailPrefab,firePoint.position,firePoint.rotation) as Transform;
LineRenderer lr = trail.GetComponent<LineRenderer>();
if(lr != null)
{
// Set positions
lr.SetPosition(0, firePoint.position);
lr.SetPosition(1, hitPos);
}
Destroy(trail.gameObject, 0.035f);
if (hitNormal != new Vector3(9999, 9999, 9999))
{
Transform hitParticle = Instantiate(HitPrefab, hitPos, Quaternion.FromToRotation(Vector3.right,hitNormal)) as Transform;
hitParticle.parent = transform.parent;
Destroy(hitParticle.gameObject, 0.3f);
}
Transform clone = Instantiate(MuzzleFlashPrefab, firePoint.position, firePoint.rotation);
clone.parent = firePoint;
float size = Random.Range(0.3f, 0.5f);
clone.localScale = new Vector3(size, size, size);
Destroy(clone.gameObject, 0.02f);
}
}
I've been trying to figure it out what's wrong for hours now. Checked the code just too many times, don't know how to google this problem. Just can't understand why it's hitting everything except that spaceship..
Don't know what other information you might need so tell me if you need something more.
I want to make my player invulnerable from objects hitting him for a few seconds after he resets back to the center of the game, meaning I don't want anything to hurt him and I don't want the player to move for 5 seconds, but i'm not sure of how to do that! I searched it up but results that I found doesn't match up with my code. Anyway this is my playermovement script:
private Animator anim;
public float speed = 15f;
public static Vector3 target;
private bool touched;
private bool canmove;
Vector3 startPosition;
void Start () {
target = transform.position;
anim = GetComponent<Animator> ();
}
void Update () {
if (Input.GetMouseButtonDown (0)) {
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 10; // distance from the camera
target = Camera.main.ScreenToWorldPoint(mousePosition);
target.z = transform.position.z;
}
transform.position = Vector3.MoveTowards (transform.position, target, speed * Time.deltaTime);
var movementDirection = (target - transform.position).normalized;
if (movementDirection.x != 0 || movementDirection.y != 0) {
anim.SetBool ("walking", false);
anim.SetFloat("SpeedX", movementDirection.x);
anim.SetFloat("SpeedY", movementDirection.y);
anim.SetBool ("walking", true);
}
}
void FixedUpdate () {
float LastInputX = transform.position.x - target.x;
float LastInputY = transform.position.y - target.y;
if (touched) {
if (LastInputX != 0 || LastInputY != 0) {
anim.SetBool ("walking", true);
if (LastInputX < 0) {
anim.SetFloat ("LastMoveX", 1f);
} else if (LastInputX > 0) {
anim.SetFloat ("LastMoveX", -1f);
} else {
anim.SetFloat ("LastMoveX", 0f);
}
if (LastInputY > 0) {
anim.SetFloat ("LastMoveY", 1f);
} else if (LastInputY < 0) {
anim.SetFloat ("LastMoveY", -1f);
} else {
anim.SetFloat ("LastMoveY", 0f);
}
}
}else{
touched = false;
anim.SetBool ("walking", false);
}
}
}
And this is my player health script:
public int curHealth;
public int maxHealth = 3;
Vector3 startPosition;
bool invincible = false;
void Start ()
{
curHealth = maxHealth;
startPosition = transform.position;
}
void Update ()
{
if (curHealth > maxHealth) {
curHealth = maxHealth;
}
if (curHealth <= 0) {
Die ();
}
}
void Die ()
{
//Restart
Application.LoadLevel (Application.loadedLevel);
}
public void Damage(int dmg)
{
curHealth -= dmg;
Reset();
}
void Reset ()
{
transform.position = startPosition;
PlayerMovement.target = startPosition;
}
}
So to be more simple, I want to make my player invulnerable (once he reset back in the center of the screen) from getting hit from enemies for 5 seconds and people who are playing my player can not move for 5 seconds. Thank you! (My game is a topdown 2d click to move game)
I think this should do the trick. At least point you in the right direction.
Simple explanation, i changed invincible to be a time, a time in the future.
Then we simply add a time in the future to it at some event, and from that event onward to the point in the future we want him invincible.
So at every event where he would take damage we check, is now in the future of invincible or is invincible in the future of now. that is your bool.
DateTime invincible = DateTime.Now;
public void Damage(int dmg)
{
if(invincible <= DateTime.Now)
{
curHealth -= dmg;
Reset();
}
}
void Reset ()
{
transform.position = startPosition;
PlayerMovement.target = startPosition;
invincible = DateTime.Now.AddSeconds(5);
}
if you want a helper method like this
bool IsInvincible(){
return invincible <= DateTime.Now;
}
Then you can change out the if(invincible <= DateTime.Now) with if(IsInvincible()) in your public void Damage(int dmg)
In game development, you have to keep in mind that everything happens within a frame update. I like to use coroutines to implement invincibility frames in Unity. A coroutine is simply a method that runs in parallel to the main update loop and resumes where it left off in the next update.
float dmg = 100.0f;
bool isHitByEnemy = false
bool isInvulnerable = false
void Demage()
{
//some dmg logic
if (isHitByEnemy && isInvulnerable == false)
{
StartCoroutine("OnInvulnerable");
}
}
IEnumerator OnInvulnerable()
{
isInvulnerable = true;
dmg = 0.0f;
yield return new WaitForSeconds(0.5f); //how long player invulnerable
dmg = 100.0f;
isInvulnerable = false;
}