Reference problems to other Gameobjects
Hey guys
I am pretty new to Unity. I try to do a simple 2D-Platforfmer currently but I am stuck on a problem. I wrote a script, which controls actually all of my Ki-Enemy. It has some line casts, health etc.
Once the Player hits the enemy, it should lose some health. This works as well.
But just with 1 enemy in the scene. Once there are more, it damages all the time the origin enemy. I've already created a prefab out of it, but it did not help.
I am pretty sure that the problem is the reference to it. I just reference the base gameobject.
What are the ways to reference to all instances of that object? How would you separate your scripts, because at the moment my ki script is a big mess, maybe I need to structure it differently to solve the problem with the reference thing?
Anyway, I appreciate every help I can get. Sorry for my English. And unfortunately, I have a deadline (I am doing it for school), so I hope you can give me fast some answers :D
The following script is my script concerning my enemy. I comment it a bit, hope it is enough:
using UnityEngine; using System.Collections;
public class kiEnemyMoving : MonoBehaviour {
public LayerMask mskEnemyBlock;
public LayerMask mskEnemyGround;
public LayerMask playerSpot;
public float speed = 1;
bool booEnemyIsGrounded;
bool booEnemyIsBlocked;
bool booPlayerSpotted;
bool booEnemyAttack;
public Rigidbody2D ri2EnemyBody;
public SpriteRenderer mySprite;
public SpriteRenderer BodySprite;
private ControllerScriptAlt scrControllerScriptAlt;
Transform traEnemy;
float myWidth;
Vector2 vec = new Vector2(-1f,-1.0f);
Vector2 vec1 = new Vector2(1f, -1.0f);
public Animator anim;
Vector2 ve2EnemyLastPosition;
Vector2 ve2EnemyPace;
Vector2 ve2PlayerPosition = Vector2.zero;
Vector2 ve2EnemyPosition = Vector2.zero;
Vector2 ve2CurrRot;
Vector2 lineCastPosBlockCheck;
Vector2 watchPlayer;
bool booPlayerLeftFromEnemy;
bool booEnemyMovesLeft;
bool spotReminder = false;
bool booAttackBegin = false;
float fltAttackBegin;
float fltLastSpottedPlayer;
float fltTimeSinceLastSpotted;
int intCurrentEnemyHealth;
public int intMaxEnemyHealth;
//public Transform Player;
void Start ()
{
traEnemy = this.transform;
ri2EnemyBody = GetComponent<Rigidbody2D>();
mySprite = this.GetComponent<SpriteRenderer>();
// scrPlayerHealth = GameObject.Find("_Playeralt2").GetComponent();
myWidth = mySprite.bounds.extents.x / 3;
anim = GetComponent<Animator>();
ve2PlayerPosition = GameObject.FindGameObjectWithTag("Player").transform.position;
scrControllerScriptAlt = GameObject.FindGameObjectWithTag("Player").GetComponent<ControllerScriptAlt>();
ve2EnemyPosition = this.transform.position;
ve2EnemyLastPosition = new Vector2(ve2EnemyPosition.x - 1, ve2EnemyPosition.y);
intCurrentEnemyHealth = intMaxEnemyHealth;
if (ve2PlayerPosition.x > ve2EnemyPosition.x)
booPlayerLeftFromEnemy = true;
else
booPlayerLeftFromEnemy = false;
}
void FixedUpdate ()
{
if (scrControllerScriptAlt.booPlayerDied)
Destroy(this);
//setting up the linecasts
Vector2 lineCastPosGroundCheck = traEnemy.position.toVector2() + traEnemy.right.toVector2() * myWidth + Vector2.down;
if (booEnemyMovesLeft)
lineCastPosBlockCheck = traEnemy.position.toVector2() + vec;
else
lineCastPosBlockCheck = traEnemy.position.toVector2() + vec1;
Vector2 lineCastPosPlayerSpot = traEnemy.position.toVector2() + traEnemy.right.toVector2() * myWidth;
Vector2 lineCastPosPlayerAttack = traEnemy.position.toVector2() + traEnemy.right.toVector2() * myWidth;
Debug.DrawLine(lineCastPosGroundCheck, lineCastPosGroundCheck + new Vector2(0,-4.5f), Color.blue);
booEnemyIsGrounded = Physics2D.Linecast(lineCastPosGroundCheck, lineCastPosGroundCheck + new Vector2(0,-4.5f), mskEnemyGround);
Debug.DrawLine(lineCastPosBlockCheck, lineCastPosBlockCheck + traEnemy.right.toVector2() * 0.3f, Color.blue);
booEnemyIsBlocked = Physics2D.Linecast(lineCastPosBlockCheck, lineCastPosBlockCheck + traEnemy.right.toVector2() * 0.3f, mskEnemyBlock);
Debug.DrawLine(lineCastPosPlayerSpot, lineCastPosPlayerSpot + traEnemy.right.toVector2() * 10.0f, Color.yellow);
booPlayerSpotted = Physics2D.Linecast(lineCastPosPlayerSpot, lineCastPosPlayerSpot + traEnemy.right.toVector2() * 10.0f, playerSpot);
Debug.DrawLine(lineCastPosPlayerAttack, lineCastPosPlayerAttack + traEnemy.right.toVector2() * 1.0f, Color.red);
booEnemyAttack = Physics2D.Linecast(lineCastPosPlayerAttack, lineCastPosPlayerAttack + traEnemy.right.toVector2() * 1.0f, playerSpot);
//empty, will fill it later, when I have an idea what do to, when the enemy dies
if (intCurrentEnemyHealth <= 0)
{
}
//method to determin the setting, like in which direction the enemy moves and where the player is (left, right of the enemy)
funSetting();
//that is the idle mode, the enemy moves slow and turns when it is not grounded anymore or blocked
if (!booPlayerSpotted && !spotReminder)
{
speed = 1;
ve2EnemyPace = ri2EnemyBody.velocity;
ve2EnemyPace.x = traEnemy.right.x * speed;
ri2EnemyBody.velocity = ve2EnemyPace;
anim.SetBool("EnemyHeavy_Run", true);
if (!booEnemyIsGrounded || booEnemyIsBlocked)
{
ve2CurrRot = traEnemy.eulerAngles;
ve2CurrRot.y += 180;
traEnemy.eulerAngles = ve2CurrRot;
}
}
//once the player gets spotted a timer starts
else if (booPlayerSpotted)
{
spotReminder = true;
fltLastSpottedPlayer = Time.time;
}
//that is the so called "chasing" mode, the enemy moves faster and, depending where the player is, moves to him
if (spotReminder && !booEnemyAttack)
{
speed = 6;
booAttackBegin = false;
if (booPlayerLeftFromEnemy && booEnemyMovesLeft)
{
funPlayerInReachTest();
funEnemyWatchesLeft();
}
else if (!booPlayerLeftFromEnemy && !booEnemyMovesLeft)
{
funPlayerInReachTest();
funEnemyWatchesRight();
}
else if (booPlayerLeftFromEnemy && !booEnemyMovesLeft)
{
funPlayerInReachTest();
funEnemyWatchesLeft();
}
else if (!booPlayerLeftFromEnemy && booEnemyMovesLeft)
{
funPlayerInReachTest();
funEnemyWatchesRight();
}
fltTimeSinceLastSpotted = Time.time;
//check, whether the enemy did not spot the player for longer than 6 seconds, if so, enemy looses interest and goes into idle again
if (fltTimeSinceLastSpotted - fltLastSpottedPlayer > 6.0f)
spotReminder = false;
}
// if the player is in reach, the enemy starts to attack the player. Again a timer starts that let him only attack every 2 seconds
else if (booEnemyAttack && !booAttackBegin)
{
funEnemyAttacksPlayer();
fltAttackBegin = Time.time;
booAttackBegin = true;
}
else if (booAttackBegin)
{
float check = Time.time;
if (check - fltAttackBegin > 2.0f)
{
funEnemyAttacksPlayer();
anim.SetTrigger("Hit");
scrControllerScriptAlt.funPlayerDamage(1);
//this thing manages the knockback, because it depends unfortunatly from where the enemy is attacking the player
if (booPlayerLeftFromEnemy)
{
StartCoroutine(scrControllerScriptAlt.IEnKnockback(0.02f, 100f, scrControllerScriptAlt.transform.position, 100f));
}
else if (!booPlayerLeftFromEnemy)
{
StartCoroutine(scrControllerScriptAlt.IEnKnockback(0.02f, 100f, scrControllerScriptAlt.transform.position, -100f));
}
booAttackBegin = false;
}
}
}
//method checks wether the player is in reach of the enemy. If it is not, it just stops
void funPlayerInReachTest()
{
if (booEnemyIsBlocked || !booEnemyIsGrounded)
{
ve2EnemyPace = ri2EnemyBody.velocity;
ve2EnemyPace.x = 0;
ri2EnemyBody.velocity = ve2EnemyPace;
anim.SetBool("EnemyHeavy_Chasing", false);
anim.SetBool("EnemyHeavy_Run", false);
}
else
{
ve2EnemyPace = ri2EnemyBody.velocity;
ve2EnemyPace.x = traEnemy.right.x * speed;
ri2EnemyBody.velocity = ve2EnemyPace;
anim.SetBool("EnemyHeavy_Chasing", true);
anim.SetBool("EnemyHeavy_Run", false);
}
}
//determines the initial situation of the scene
void funSetting()
{
ve2PlayerPosition = GameObject.FindGameObjectWithTag("Player").transform.position;
ve2EnemyPosition = this.transform.position;
if (ve2PlayerPosition.x > ve2EnemyPosition.x)
booPlayerLeftFromEnemy = false;
else
booPlayerLeftFromEnemy = true;
if (ve2EnemyPosition.x > ve2EnemyLastPosition.x)
{
booEnemyMovesLeft = false;
anim.SetBool("EnemyHeavy_Run", true);
}
else if (ve2EnemyPosition.x < ve2EnemyLastPosition.x)
{
booEnemyMovesLeft = true;
anim.SetBool("EnemyHeavy_Run", true);
}
ve2EnemyLastPosition = ve2EnemyPosition;
}
//determines where the enemy shall look
void funEnemyWatchesLeft()
{
ve2CurrRot = traEnemy.eulerAngles;
ve2CurrRot.y = 180;
traEnemy.eulerAngles = ve2CurrRot;
}
void funEnemyWatchesRight()
{
ve2CurrRot = traEnemy.eulerAngles;
ve2CurrRot.y = 0;
traEnemy.eulerAngles = ve2CurrRot;
}
//set the enemy in attacking mode
void funEnemyAttacksPlayer()
{
ve2EnemyPace = ri2EnemyBody.velocity;
ve2EnemyPace.x = 0;
ri2EnemyBody.velocity = ve2EnemyPace;
anim.SetBool("EnemyHeavy_Chasing", false);
anim.SetBool("EnemyHeavy_Run", false);
}
//method to damage the enemy through the player
public void funEnemyDamage(int dmg)
{
intCurrentEnemyHealth = intCurrentEnemyHealth - dmg;
anim.SetTrigger("Damaged");
}
}
The next script is from my player:
using UnityEngine; using System.Collections;
public class ControllerScriptAlt : MonoBehaviour {
public Animator anim;
public Rigidbody2D rb;
private SceneManagment scrSceneManagment;
public LayerMask lmsAttackable;
SpriteRenderer mySprite;
bool facingRight = true;
float maxSpeed = 10.0f;
bool grounded = false;
public Transform groundCheck;
float groundRadius = 1f;
public LayerMask whatIsGround;
bool booPlayerDamaged;
public Transform traPlayer;
float myWidth;
bool booEnemyInRange;
private kiEnemyMoving scrKiEnemyMoving;
Vector2 lineCastPosPlayerAttack;
bool pressedSpace = false;
bool hit = false;
public int intCurrentPlayerHealth;
public int intMaxPlayerHealth = 3;
public bool booPlayerDied;
void Start ()
{
anim = this.GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
scrSceneManagment = GetComponent<SceneManagment>();
intCurrentPlayerHealth = intMaxPlayerHealth;
booPlayerDamaged = false;
mySprite = this.GetComponent<SpriteRenderer>();
myWidth = mySprite.bounds.extents.x / 3;
scrKiEnemyMoving = GameObject.FindGameObjectWithTag("Enemy").GetComponent<kiEnemyMoving>();
booPlayerDied = false;
}
void FixedUpdate ()
{
//setting up the linecasts depending on in which direction the player is looking
if (facingRight)
{
lineCastPosPlayerAttack = traPlayer.position.toVector2() + traPlayer.right.toVector2() * myWidth * 1.5f;
Debug.DrawLine(lineCastPosPlayerAttack, lineCastPosPlayerAttack + traPlayer.right.toVector2() * 1.5f, Color.red);
booEnemyInRange = Physics2D.Linecast(lineCastPosPlayerAttack, lineCastPosPlayerAttack + traPlayer.right.toVector2() * 1.5f, lmsAttackable);
}
else if (!facingRight)
{
lineCastPosPlayerAttack = traPlayer.position.toVector2() + traPlayer.right.toVector2() * myWidth * -1.5f;
Debug.DrawLine(lineCastPosPlayerAttack, lineCastPosPlayerAttack + traPlayer.right.toVector2() * -1.5f, Color.red);
booEnemyInRange = Physics2D.Linecast(lineCastPosPlayerAttack, lineCastPosPlayerAttack + traPlayer.right.toVector2() * -1.5f, lmsAttackable);
}
booPlayerDamaged = false;
//groundchecks checks wether the player is grounded
GroundCheck();
anim.SetFloat("vSpeed", rb.velocity.y);
//input of the player, excluded into a method
float move = Controlling();
//checks in which direction the player watches
if (move > 0 && !facingRight)
Flip();
else if (move < 0 && facingRight)
Flip();
//manages the initializing of the attack
PressedSpace();
//if the enemy is in range and the player pressed space, the enemy gets damaged, but only the one, which is referenced. There is the problem. Somewehere there...
if (pressedSpace && booEnemyInRange)
{
scrKiEnemyMoving.funEnemyDamage(1);
}
hit = false;
anim.SetBool("Hit", hit);
//manages the health of the player
if (intCurrentPlayerHealth > intMaxPlayerHealth)
{
intCurrentPlayerHealth = intMaxPlayerHealth;
}
if (intCurrentPlayerHealth <= 0)
{
funPLayerDie();
}
}
void Update()
{
//manages the jumpcapability of the player
if (grounded /*|| !doubleJump*/ && Input.GetButtonDown("Jump") && !booPlayerDamaged)
{
anim.SetBool("Ground", grounded);
rb.AddForce(new Vector2(0, 700));
//if(!doubleJump && !grounded)
// doubleJump = true;
}
}
//method the flip the world, once the player moves in the other direciton
void Flip()
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
//groundcheck, I did not do this with a linecasts, just got that code from another script somewhere
void GroundCheck()
{
grounded = Physics2D.OverlapCircle (groundCheck.position, groundRadius, whatIsGround);
anim.SetBool("Ground",grounded);
}
//controlls the input of the player
float Controlling()
{
float move = Input.GetAxis ("Horizontal");
if (move != 0f) {
anim.SetBool ("PlayerAlt2_Run", true);
}
else
{
anim.SetBool ("PlayerAlt2_Run", false);
}
rb.velocity = new Vector2(move * maxSpeed, rb.velocity.y);
return move;
}
//checks, wether the player pressed space and communicates with the animator
void PressedSpace()
{
pressedSpace = false;
anim.SetBool("pressedSpace",pressedSpace);
if (Input.GetKeyDown (KeyCode.Space) && !pressedSpace)
{
pressedSpace = true;
anim.SetBool("pressedSpace",pressedSpace);
}
}
//method, what shall happen, once the player died
public void funPLayerDie()
{
scrSceneManagment.funRestartCurrentScene();
booPlayerDied = true;
}
//method, which controlls the damage the player can take by the enemy but also by traps etc...
public void funPlayerDamage(int dmg)
{
intCurrentPlayerHealth = intCurrentPlayerHealth - dmg;
anim.SetTrigger("Damaged");
booPlayerDamaged = true;
}
//knockback Enumkerator, manages everything around knockbacks of the player
public IEnumerator IEnKnockback(float fltKnockDur, float fltKnockbackPwr, Vector3 ve3KnockbackDir, float fltKnockbackDir)
{
float timer = 0;
while (fltKnockDur > timer)
{
timer += Time.deltaTime;
rb.AddForce(new Vector3(ve3KnockbackDir.x * fltKnockbackDir, ve3KnockbackDir.y * fltKnockbackPwr * 2, transform.position.z));
}
yield return 0;
}
}
oh oh, that just looks horrible. I feel sorry to everyone, who is going to read that :/
Answer by iAmAwsum · Jan 08, 2017 at 04:17 PM
First of all it would be appreciated if you would post your code with the damaging enemies, etc.
If you create a public GameObject and assigned the enemy prefab to it and then calling the damage script on the GameObject assigned above, it will always damage only the one assigned. If you have your damage detections set up with raycasts then use the RayCastHit that you stored and and call
hit.transform.GetComponent<ScriptAttachedToEnemy>().DamageFunction(5);
Thanks for your fast answer.
Uhhm, I could have posted my code but I feel a bit ashamed of it because as I said, it is a big mess, like Spaghetticode (you know that word? ).
Anyway, I will poste it.
If you create a public GameObject and assigned the enemy prefab to it and then calling the damage script on the GameObject assigned above, it will always damage only the one assigned.
Is this a solution? Sorry for asking but I don't really understand what you meant by it.
I watched a tutorial where they choose line casts, so i don't know anything about raycasts. What would you prefer?
Answer by MagJ99 · Jan 26, 2017 at 02:30 PM
Guys, please. I need help. I have a certain feeling that I miss something