Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
3
Question by Persona · Mar 22, 2011 at 04:15 PM · arraycharacterselectiontargetting

Choosing from multiple Characters

I'm adding a V.S. mode to one of my games and there will be up to four characters on the field. The player will automatically lock onto an enemy when the character is spawned. All opponents will have

My problem is this:

1.) How do I allow the player to choose from the array of enemy characters? This allow the player to choose which enemy to Target with a key press.

2.) How to allow the enemy to choose who to target by random? Since they will all have the same tag, and I want them to fight against themselves and the player, how do I set it up so that they will target any active character other than themselves?

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Statement · Mar 25, 2011 at 01:01 PM 3
Share

All the opponents will have... ?

3 Replies

· Add your reply
  • Sort: 
avatar image
4
Best Answer

Answer by Statement · Mar 29, 2011 at 08:37 PM

Hi, I post another answer since I rewrote the whole system to make it easier to manage the answers and since this solution uses a bit different architecture.

Basically it works like this:

  • On every Player and Enemy, add the Targetter script.
    • It accepts two messages "TargetNext" and "TargetRandom"
    • It sends two messages "SetTarget" and "ClearTarget".
  • The Player script should sit on the same gameObject as the Targetter script for the player.
  • Any AI script (not included) should sit on the same gameObject as the Targetter script for the enemy.
  • Implement function SetTarget(target : GameObject) and function ClearTarget() on Player and AI.
  • Send message "TargetNext" or "TargetRandom" when you want to get a new target.
  • New targets are automatically sent when a target is removed.


I have tested this code myself and it works pretty nicely. The only time you will have a null target in your player script is if there is no other targets. If you spawn new targets they will automatically get included in every other targetters list of target - it's fully automatical. The only thing you need to do is make sure that every Enemy and every Player has a targetter. Study Player.js about how you maintain the target. See the two functions SetTarget and ClearTarget, and the call to TargetNext to cycle to the next target.

  • Due to a bug in SendMessage, I was unable to make it simpler such that SetTarget would had accepted null. It's a limitation in the current version of Unity3D.

I hope it works out as you wanted! It was a fun problem and I learnt a lot myself! Without further ado:
The Source.

Player.js

var target : GameObject;

function Update() { if (Input.GetKeyDown(KeyCode.Tab)) SendMessage("TargetNext"); }

function LateUpdate() { if (target) Debug.DrawLine(transform.position, target.transform.position); }

function SetTarget(newTarget : GameObject) { target = newTarget; }

function ClearTarget() { target = null; }

Targetter.js

import System.Collections.Generic;

private var targetIdx : int; private var targets : List.<GameObject> = new List.<GameObject>(4);

TargetRandom();

function OnEnable() {
AddTargets(GameObject.FindGameObjectsWithTag("Enemy")); AddTargets(GameObject.FindGameObjectsWithTag("Player")); SendToTargets("AddTarget"); }

function OnDisable() { SendToTargets("RemoveTarget");
targetIdx = 0;
targets.Clear(); }

function SendToTargets(message : String) { for (var target in targets) target.SendMessage(message, gameObject); }

function AddTargets(targets : GameObject[]) { for (var target in targets) AddTarget(target);
}

function AddTarget(target : GameObject) { if (target != gameObject && !targets.Contains(target)) {
targets.Add(target); if (targetIdx == -1) TargetNext(); } }

function RemoveTarget(target : GameObject) {
if (targetIdx < 0 || targetIdx >= targets.Count || targets[targetIdx] == target) targetIdx = -1;

 targets.Remove(target);

 if (targetIdx == -1)
     TargetRandom();

}

function TargetRandom() { if (targets.Count == 0) { targetIdx = -1; SendSetTarget(null); } else { targetIdx = Random.Range(0, targets.Count); SendSetTarget(targets[targetIdx]); } }

function TargetNext() { if (targets.Count == 0) { targetIdx = -1; SendSetTarget(null); } else { targetIdx = (targetIdx + 1) % targets.Count; SendSetTarget(targets[targetIdx]); } }

// Due to a bug in SendMessage, we call ClearTarget if target is null.
function SendSetTarget(target : GameObject) { if (target) SendMessage("SetTarget", target, SendMessageOptions.DontRequireReceiver); else SendMessage("ClearTarget", SendMessageOptions.DontRequireReceiver); }

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Statement · Mar 29, 2011 at 09:34 PM 0
Share

Heck I even created yet another targetter but I can't be arsed to post three answers to one question so I'll paste it to pastebin: http://pastebin.com/QFCGrWfx

avatar image Statement · Mar 29, 2011 at 09:52 PM 0
Share

I realized it's quite useless to have ClearTarget since in Unity3D gameobjects are automatically nulled anyway! And that code reduce some complexity, just calling Find each time you try to set a new target. Code is so much cleaner and easier to use! On top of that, it selects next target based on distance, so it cycles through the nearest first and furthest last.

avatar image Persona · Mar 30, 2011 at 01:05 AM 1
Share

Sweet! That solved it! Now all that's left is the character selection menu and the constant skipping now, and my game will be one step closer!

avatar image
7

Answer by Statement · Mar 25, 2011 at 01:33 PM

Use a List with targets and add all game objects with tags Enemy and Player to that list. Remove yourself from list and you have all other targets but yourself. To select a random target, select one with Random.Range. To select next target, increment the index and make it wrap around bounds. See the attached code, which should work for both player and AI if the input code is put elsewhere (or every character would change target at the same time). If you will be removing game objects, you need to make sure you remove them from the list as well or you could be targeting null all of a sudden.

Good luck!

import System.Collections.Generic;

var target : GameObject; private var targetIdx : int; private var targets : List.<GameObject>;

function Start() { // 2.) How to allow the enemy to choose who to target by random? // Since they will all have the same tag, and I want them to // fight against themselves and the player, how do I set it up // so that they will target any active character other than // themselves?

 // A.) Create a list of all (other) characters and select one at 
 //     random. Maintain the index of the current character so
 //     you easily can cycle to the next (see below). Since we will 
 //     have up to 4 targets, we create the list with capacity for
 //     4 targets.

 targets = new List.&lt;GameObject&gt;(4);
 FindTargets();
 TargetRandom();

}

// --------------------------- // UPDATED SINCE ORIGINAL CODE // ---------------------------

// When an object is disabled (Destroyed), we want to notify all the // other targets about this so they can remove that target from their // list. function OnDisable() {
for (var target in targets) target.SendMessage("OnTargetExpired", gameObject); }

// --------------------------- // UPDATED SINCE ORIGINAL CODE // ---------------------------

// This is called when one of our targets have expired. At this point // we should remove that target from our list and select a random // target in case our current target was the one we removed. function OnTargetExpired(tgt : GameObject) {
targets.Remove(tgt); if (target == tgt) TargetRandom(); }

function Update() { // 1.) How do I allow the player to choose from the array of enemy // characters? This allow the player to choose which enemy to // Target with a key press.

 // A.) Cycle through targets with tab key, just like you do in many
 //     popular games such as WoW. Note that you should probably do
 //     this check in your player controller code or you would end up
 //     with each targetter changing target. (You can then place this
 //     component on all combatants).

 if (Input.GetKeyDown(KeyCode.Tab))
     TargetNext();

}

// --------------------------- // UPDATED SINCE ORIGINAL CODE // ---------------------------

// Sets target randomly. function TargetRandom() { if (targets.Count == 0) { targetIdx = -1; target = null; return; } targetIdx = Random.Range(0, targets.Count); target = targets[targetIdx]; }

// --------------------------- // UPDATED SINCE ORIGINAL CODE // ---------------------------

// Sets next target, in a looping manner. function TargetNext() { if (targets.Count == 0) { targetIdx = -1; target = null; return; } targetIdx = (targetIdx + 1) % targets.Count; target = targets[targetIdx]; }

// Populates targets array. function FindTargets() {
// Find all targets, which are objects tagged Enemy or Player, but // is not self. targets.Clear(); targets.AddRange(GameObject.FindGameObjectsWithTag("Enemy")); targets.AddRange(GameObject.FindGameObjectsWithTag("Player")); targets.Remove(gameObject); }

Comment
Add comment · Show 12 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Persona · Mar 26, 2011 at 12:44 AM 0
Share

It works, but once an enemy is destroyed they are unable to select a new enemy. The AI will just stand there, while the player, who's movement and lock on function are centered around the AI's location, is unable to function as well.

avatar image Statement · Mar 26, 2011 at 11:54 AM 1
Share

Then you could call FindTargets again if you're spawning more enemies. If you will be removing game objects, you need to make sure you remove them from the list as well or you could be targeting null all of a sudden. The code isn't foolproof, you need to plug in the code in the skeleton I provided so it matches your games expectations. For example you could prune all nulls (destroyed) out in update and reselect a target if you happened to have a null target.

avatar image Persona · Mar 26, 2011 at 03:30 PM 0
Share

So: function Update(){ if(Target == null){ //Prune Null // Find Targets(); }

}

How do I remove a Null from an array or list?

avatar image Statement · Mar 27, 2011 at 09:36 AM 0
Share

list.Remove(null);

avatar image Statement · Mar 27, 2011 at 09:41 AM 0
Share

I guess you could iterate through every enemy in OnDisable (upon dying) and send message to signal to remove that opponent. This should avoid nulls to begin with.

Show more comments
avatar image
2

Answer by SrBilyon · Mar 25, 2011 at 05:47 AM

As far as selecting an enemy target, here is a script I had a little help making, It returns the closet enemy and sets it as target, you can even have a little indicator on the selected enemy.

//================================================ //Lock On Script //================================================ private var current : int = 0; private var locked : boolean = false; var playerController : ThirdPersonController ; var enemyLocations : GameObject[]; var closest : GameObject; var activeIcon : Transform; //Current targeted enemy indicator

function Update() {
var playerController : ThirdPersonController = GetComponent(ThirdPersonController);

 if (closest != null &amp;&amp; locked)

{ activeIcon.active = true; activeIcon.transform.position.y = (closest.transform.position.y+1); activeIcon.transform.position.x = (closest.transform.position.x); activeIcon.transform.position.z = (closest.transform.position.z); } else {
activeIcon.active = false; }

 if(Input.GetButtonDown("Lock")) 
 {       
 //Looks for the closest enemy
 FindClosestEnemy();
 locked = !locked;
 }

 if(locked) 
 {
     //If there aren't any enemies (or the player killed the last one targeted) make sure that the lock is false
     if (!closest)
     {       
         activeIcon.active = false;
         locked = false;
         closest = null;
     }

     if (playerController.isAttacking)
     transform.LookAt(Vector3(closest.transform.position.x, transform.position.y, closest.transform.position.z));
 }

}

function FindClosestEnemy () : GameObject { // Find all game objects with tag Enemy enemyLocations = GameObject.FindGameObjectsWithTag("Enemy"); //var closest : GameObject; var distance = Mathf.Infinity; var position = transform.position; // Iterate through them and find the closest one for (var go : GameObject in enemyLocations) { var diff = (go.transform.position - position); var curDistance = diff.sqrMagnitude;

         if (curDistance &lt; distance) 
         { 
             closest = go; 
             distance = curDistance; 
         } 
     } 
 return closest; 

}

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Persona · Mar 25, 2011 at 10:30 PM 0
Share

That conflicts with the scripts I have and rather than searching for closest, I'm going for the order listed in an array.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

No one has followed this question yet.

Related Questions

Character development with abilities 1 Answer

Array Selection(?) 1 Answer

A simple character selection screen,Help with characters selection screen 1 Answer

Using a selected character 1 Answer

Play with the selected character 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges