- Home /
How can I make my player only target objects from a certain distance?
Right now I have some scripts that allow the Enemy to die, and when he dies you get XP, and I tried adding some more Enemies, and implemented a targeting system, but you can be any distance. You can be 500 meters away from it, and you can sitll target/damage it. I am guessing I have to use Vector math, but not sure how to do this. I want to make it so if the distance between the player and the enemy is less than 2 (From any direction (Up, down, left, right, etc.) then he can't target it, or damage it. If you need me to clarify more, let me know. Thanks in advance!
Here is the script with the targeting system and the DamageEnemy
using UnityEngine;
using System.Collections;
public class DamageEnemy : MonoBehaviour {
public GameObject Enemy;
public GameObject Enemy2;
public GameObject EnemyBoss;
public GameObject target;
public int number = 0;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
CheckKey();
}
void OnGUI(){
DisplayTarget();
}
//-------------------------------------------------------------------------------------
void CheckKey(){
//EnemyStats ES = (EnemyStats)Enemy.GetComponent("EnemyStats");
//EnemyStats ES2 = (EnemyStats)Enemy2.GetComponent("EnemyStats");
if(Input.GetKeyDown(KeyCode.X)){
number = number + 1;
if(number > 3){
number = 1;
}
switch (number){
case 1:
target = Enemy;
break;
case 2:
target = Enemy2;
break;
case 3:
target = EnemyBoss;
break;
default:
target = null;
break;
}
}
//if(Input.GetKeyDown(KeyCode.C)){
// target = Enemy2;
//}
if(target == Enemy){
if(Input.GetKeyDown(KeyCode.Z)){
EnemyStats ES = (EnemyStats)Enemy.GetComponent("EnemyStats");
ES.EnemyHealth = ES.EnemyHealth - 25;
}
}
if(target == Enemy2){
if(Input.GetKeyDown(KeyCode.Z)){
EnemyStats ES = (EnemyStats)Enemy2.GetComponent("EnemyStats");
ES.EnemyHealth = ES.EnemyHealth - 25;
}
}
if(target == EnemyBoss){
if(Input.GetKeyDown(KeyCode.Z)){
EnemyStats ES = (EnemyStats)EnemyBoss.GetComponent("EnemyStats");
ES.EnemyHealth = ES.EnemyHealth - 25;
}
}
}
//-------------------------------------------------------------------------------------------
void DisplayTarget(){
if(target == Enemy)
{
EnemyStats ES = (EnemyStats)Enemy.GetComponent("EnemyStats");
GUI.Box(new Rect((Screen.width / 2 + 250) + 2, 36, 160, 25), ("Targeting: Enemy LVL:1" ));
GUI.Box(new Rect((Screen.width / 2 + 250) + 2, 62, 160, 25), ("Enemy Health: " + ES.EnemyHealth + "/" + ES.EnemyMaxHealth));
}
if(target == Enemy2)
{
EnemyStats ES = (EnemyStats)Enemy2.GetComponent("EnemyStats");
GUI.Box(new Rect((Screen.width / 2 + 250) + 2, 36, 160, 25), ("Targeting: Enemy LVL:2" ));
GUI.Box(new Rect((Screen.width / 2 + 250) + 2, 62, 160, 25), ("Enemy Health: " + ES.EnemyHealth + "/" + ES.EnemyMaxHealth));
}
if(target == EnemyBoss)
{
EnemyStats ES = (EnemyStats)EnemyBoss.GetComponent("EnemyStats");
GUI.Box(new Rect((Screen.width / 2 + 250) + 2, 36, 180, 25), ("Targeting: Enemy LVL: Boss" ));
GUI.Box(new Rect((Screen.width / 2 + 250) + 2, 62, 180, 25), ("Enemy Health: " + ES.EnemyHealth + "/" + ES.EnemyMaxHealth));
}
}
}
Here is the script where the Enemy dies and such (if that's even needed?)
using UnityEngine;
using System.Collections;
public class EnemyStats : MonoBehaviour {
public int EnemyHealth = 100; //Change in inspector for each enemy this is put into.
public int EnemyMaxHealth = 100; //Change in inspector for each enemy this is put into.
public int DropXP = 11; //Change in inspector for each enemy this is put into.
public int DropGold = 8; //Change in inspector for each enemy this is put into.
public GameObject GiveStuff;
public GameObject GiveStuff2;
public bool IsAlive = true;
public bool IsTargeted = false;
// Use this for initialization
void Start () {
DropXP = DropXP / 2;
DropGold = DropGold / 2;
}
// Update is called once per frame
void Update () {
if(EnemyHealth < 0){
EnemyHealth = 0;
}
PlayerLevelDeclaration PT = (PlayerLevelDeclaration)GiveStuff.GetComponent("PlayerLevelDeclaration");
if(EnemyHealth <= 0 && IsAlive){
IsDead = true;
IsAlive = false;
EnemyHealth = 0;
if(IsDead = true && EnemyHealth == 0){
StartCoroutine(OnDeath());
IsDead = false;
}
}
}
bool IsDead = false;
IEnumerator OnDeath(){
AttributeDeclaration AT = (AttributeDeclaration)GiveStuff2.GetComponent("AttributeDeclaration");
PlayerLevelDeclaration PT = (PlayerLevelDeclaration)GiveStuff.GetComponent("PlayerLevelDeclaration");
if(EnemyHealth <= 0){
EnemyHealth = 0;
IsDead = true;
if(IsDead == true && EnemyHealth == 0){
AT.DroppedGold = DropGold;
PT.DroppedXP = DropXP;
yield return new WaitForSeconds(.00000000000000000000000000000000000000000000000000000000000000000000001f);
IsDead = false;
if(DropGold >= DropGold){
AT.DroppedGold = 0;
}
if(DropXP >= DropXP){
PT.DroppedXP = 0;
}
yield return new WaitForSeconds(2f);
collider.enabled = false;
renderer.enabled = false;
IsTargeted = false;
yield return new WaitForSeconds(10f);
IsDead = false;
IsAlive = true;
EnemyHealth = EnemyMaxHealth;
PT.DroppedXP = 0;
AT.DroppedGold = 0;
collider.enabled = true;
renderer.enabled = true;
}
}
yield return IsDead;
}
}
Answer by zak-reynolds · Nov 23, 2014 at 09:26 PM
The method you're looking for is Vector3.Magnitude; you can use it after assigning the targets in the switch statement:
switch (number){
case 1:
target = Enemy;
break;
case 2:
// etc...
default:
target = null;
break;
}
// Put your check here:
if (target) { // <-- same as "if (target != null) {"
// If the distance is too far (greater than 2 meters), unset the target
if (Vector3.Magnitude(this.transform.position - target.transform.position) > 2) {
target = null;
}
}
Thank you so much, this worked. If only one object is within that distance, say EnemyBoss, I have to hit X 3 times to target him, as if it is targeting nothing, 2 times. How can I change the number of times u can hit X to however many enemies are within the 2 meters? (I changed to 6 because 2 was VERY close..)
Awesome! What's happening when it's "targeting nothing" 2 times is that it's trying to target Enemy and Enemy2 first because of the way that "number" is looped around 1, 2, and 3 each time you press X. A way to do it with your current system (although it's a little hacky) is to wrap the targeting code in a while loop with a "safety valve":
if(Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.X)){
int targetTries = 3;
while (!target && targetTries > 0) {
targetTries--; // Same as "targetTries = targetTries - 1;
number++; // Same as "number = number + 1"
if (number > 3) {
number = 1;
}
switch (number) {
// Rest of the code from above goes here...
}
}
This will keep checking for an enemy until either 1) a valid target was found, or 2) all 3 enemies have been checked and none of them are close enough. You need the "targetTries" safety valve to avoid an infinite loop, and you should set it to the number of enemies that you're checking for.
However, this makes it more challenging to add more enemies later on, since you'll have to remember to increase the "int targetTries = 3;" line by one every time you add an enemy. It's a bit more advanced, but what I would do is look into adding a special "EnemyDetector" class to a child GameObject parented to the Player, and give that 'detector' object a trigger collider. Then have the EnemyDetector keep track of what enemies are nearby by using the "OnTriggerStay(Collider other)" method, and give your DamageEnemy class a reference to the EnemyDetector class so that it can see what enemies are nearby. It's a fairly big change so I won't go into more detail now, but if you're interested I can give you more details :)
Your answer
Follow this Question
Related Questions
Targeting script not finding a target 2D Mode 1 Answer
Edit this script so that the player stops at a distance and attack? 0 Answers
Look at closer to player 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers