Need help with Zelda/Kingdom Hearts Styled Lock-On System

I finally finished writing the base code for my player’s combat system. However, I want to implement a Lock-on/Trigger system that will have the player facing the enemy and having him attack towards the enemy he is targeted to. I also want to display a ring or a targeting icon on the enemy that is targeted.

The player’s movement is based off the Lerpz ThirdPersonController.js and the player uses a CharacterController.

I speculate that something around the lines of using this

  var rushDirection = -theTarget.transform.forward; //Move toward the enemy
    GameObject.Find("Player").transform.eulerAngles.y = theTarget.transform.eulerAngles.y * 180; //Face the enemy in the direction the player is rushing

I figured out now to get the player to rush forward with his attacks by using this, I figured this area would be a good start to look at as far as making the enemy’s attacks move the player towards the enemy, rather that just forward:

//================================================================//
//Rushing Forward
//================================================================//

var smoothTime = 1.0;

function RushForward(rushDistance : Vector3)
{
    var rushTime = Time.time;

    while (rushTime+smoothTime > Time.time)
    {
        charController.Move(rushDistance*(rushTime+smoothTime-Time.time)/smoothTime*Time.deltaTime);
        yield;
    }
}

Here is a snippet of the attack system if you think it will help out any. I left only one attack in there to make the script a bit shorter

  //ThirdPersonCharacterAttack
        //Rewritten by SirVictory

        //This script is only for the player's attack

        var me : ThirdPersonStatus;

        //====Basic Settings===================================//
        var attackSpeed = 1;
        var attackHitTime = 0.2;
        var attackTime = 0.4;
        var strength;
        var liftForce = 1.0;
        //===================================================//


        //===================================================
        /*       -Making an attack-
        =====================================================
        In order to make an attack you will need the following variables:

        var attackStrength =  The knockback distance of the blow
        var attackPosition =  The origin of the attack sphere relative to the player's center
        var attackRadius = The size of the attack sphere
        var attackHitPoints = The anount of damage that the attack deals
        */


        //=======Individual Attack Settings===================//

        //Punching
        var viewPunchHitBox = true;
        var punchStrength = 1.0;
        var punchRadius = 1.3;
        var punchPosition =  new Vector3 (0, 0, 0.8);
        var punchHitPoints = 1;
        var punchLiftForce = 2;

        //=====Combo Timers================================//
        var fireRate: float = 2;
        var comboNum: float = 3;
        private var fired: boolean = false;
        private var timer: float = 0.0;
        private var comboCount: float = 0.0;
        private var lastPunchTime = 0.0;
        //=================================================//


        //======Flags======================================//
        var groundAttacking  = false;
        var airAttacking = false;
        var busy = false;
        //================================================//

        //=====Sounds====================================//
        var punchSound : AudioClip;
        //===============================================//

        function Start ()
        {
            var me : ThirdPersonStatus = GetComponent(ThirdPersonStatus);
            strength = me.attack;

            //You can increase the speed of the attack animations by increasing the attack speed
            animation["punch"].speed =attackSpeed;
            animation["kick"].speed = attackSpeed;
        }


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

            //This section controls the actual attack attacking logic
            //If attacking on the ground
            if (!busy  !playerController.IsControlledDescent()  !playerController.jumping  Input.GetButtonDown("Fire1")) {
                if (!fired) {
                    fired = true;
                    timer = 0.0;
                    comboCount = 0.0;
                    Debug.Log("Punch!");
                    SendMessage ("DidPunch");
                    busy = true;
                    } else
                    {   
                    comboCount++;
                        if (!busy  comboCount == comboNum)
                        {
                            Debug.Log("Kick!");
                            SendMessage ("DidKick");
                            busy = true;
                        }
                    }
                }

                //If attacking in the air
                if (!busy  !playerController.IsControlledDescent()  playerController.jumping  !playerController.IsGrounded()  Input.GetButtonDown("Fire1"))
                {
                    if (!fired)
                    {
                        fired = true;
                        timer = 0.0;
                        comboCount = 0.0;
                        Debug.Log("Aerial Kick!");
                        SendMessage ("DidAirKick");
                        busy = true;
                    }
                    else
                    {
                        comboCount++;
                        if (!busy  comboCount == comboNum)
                        {
                            Debug.Log("Aerial Kick!");
                            SendMessage ("DidAirKick");
                            busy = true;
                        }
                    }
                }

                if (fired) {
                    timer += Time.deltaTime;
                    if (timer > fireRate) {
                        fired = false;
                    }
                }
            }


    //=============================================================//
//**********************    LandAttacks  *************************
//=============================================================//


//================================================================//
//Rushing Forward
//================================================================//

function RushForward(rushDistance : Vector3)
{
    var rushTime = Time.time;

    while (rushTime+smoothTime > Time.time)
    {
        charController.Move(rushDistance*(rushTime+smoothTime-Time.time)/smoothTime*Time.deltaTime);
        yield;
    }
}


//=============================================================//
//Standard Kick
//=============================================================//
function DidKick ()
{
    var rushDirection = meTransform.transform.forward;
    animation.Play ("kick");
    //Lift up the player
    LiftUp(10);

    //Rush and Lift the player up
    RushForward(rushDirection * 3);

    yield WaitForSeconds(attackHitTime);

    var pos = transform.TransformPoint(kickPosition);
    var enemies : GameObject[] = GameObject.FindGameObjectsWithTag("Enemy");

    for (var go : GameObject in enemies)
    {
        var enemy = go.GetComponent(EnemyDamage);
        if (enemy == null)
        continue;

        if (Vector3.Distance(enemy.transform.position, pos) < kickRadius)
        {
            strength = kickStrength;
            liftForce = kickLiftForce;
            enemy.SendMessage("ApplyDamage", kickHitPoints);

            // Play sound.
            if (punchSound)
            audio.PlayOneShot(punchSound);
        }
    }
    yield WaitForSeconds(attackTime - attackHitTime);
    busy = false;
    //groundAttacking = false;
}


    @script RequireComponent(AudioSource)

i would use Vector3.Distance and go through all of your enemies. Find the closest one to you and do a LookAt to that enemy.

Where should I apply this logic, and how do i implement it? I’m not sure how to code the Vector3.Distance part to sort out what enemy is closet. And as far as an the LookAt, I tried doing something like that based on a UnityAnswers answer, but it didn’t work out for me.

i would put this in the controlling script where you handle all the inputs. i dont want to just give you the answer but i have done something similar this and it wasnt to hard. all i did was tag all of my enemies as Enemy. then in the third person controller script saw if you press whatever button you want to use the lockon go through all of the enemies. you need an array for this. then for each one calculate the Distance. Its really easy you just put the position of you and the position of the current enemy in the array. I had a variable which said if the current enemy is closer then the last enemy, then make that position the closer one. If you do this for all enemies, in the end you will have the position of the closest one

then yea the lookat i believe you just put in the target you look at

Sorry, I’m still having trouble. I set up an array and made a function that checks for all objects with the Tag “enemy” but couldn’t really get any further. Do you think you could provide a code example?

ok well here is the code i used. It was used for my enemies to find the closest point to hide at. Similar to what I think you should do

function FindClosestHidePoint () : GameObject
{
// Find all game objects with tag Enemy
var hidePointLocations : GameObject[ ];
hidePointLocations = GameObject.FindGameObjectsWithTag(“HidePoint”);
var closest : GameObject;
var distance = Mathf.Infinity;
var position = transform.position;
// Iterate through them and find the closest one
for (var go : GameObject in hidePointLocations)
{
var diff = (go.transform.position - position);
var curDistance = diff.sqrMagnitude;
if (curDistance < distance)
{
closest = go;
distance = curDistance;
}
}
return closest;
}

Okay, I added the code you provided (and changed “HidePoint” to Enemy) and changed “closest” to “theTarget” and then I added this to one of the attack functions.

transform.LookAt(theTarget.transform);
var rushDirection = meTransform.transform.forward;

However, I only want it to rotate on the y-axis.
Also, how can I do a check to see if there are any objects with the “Enemy” exist?

I want to do something like (pseudocode incoming):

if (GameObjectWithTagExists"Enemy")
 {
     transform.LookAt(theTarget.transform);
     var rushDirection = meTransform.transform.forward;
 }
 else
{
     var rushDirection = meTransform.transform.forward;
}

Thanks for your help so far!

so you want it more like a turret? to rotate towards it using transform.LookAt(), after you find the closest enemy

Yes, well sort of. I want it to where when I press the attack button, the character moves (well rush in to attack) in the direction of the enemy.

Then later will figure out the target toggle, (i’m taking baby steps here).

so yea use the lookat() right after u find the nearest enemy. that will turn your character towards that enemy. then u will have to have an attack function when you press the attack button.

Yeah, I have that part solved. It’s just that lookat() allows the player to also rotate on the X and Z axis when all I need him to do is to rotate on the y axis.

take a look in there

i think if you put something like transform.rotate(0, target, 0); it will only rotate on the y axis

Got it, http://forum.unity3d.com/threads/49471-LookAt-to-rotate-only-on-Y-axis

So, after defeating the enemy that I manually set as the target in the inspector, I get this error

because of the code that allows the player to face the enemy when attacking

How do I get the script to check if “theTarget” is null after destroying it or how do I disable the LookAt() line if enemies don’t exist on the map?

umm yea you could do just an

if(enemy)
{
Transform.Lookat()
}

that should work where i put enemy just put in what ever you call the closest enemy that you find

Solved it, thanks

BTW here is the script

//================================================
//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  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 < distance) 
            { 
                closest = go; 
                distance = curDistance; 
            } 
        } 
    return closest; 
}

Good stuff