News Forums RAIN Sample Projects, How To, and Code How to get player's distance and how to move AI by code

This topic contains 10 replies, has 2 voices, and was last updated by  CodersExpo 2 years, 5 months ago.

Viewing 11 posts - 1 through 11 (of 11 total)
  • Author
    Posts
  • #12377

    RaycoSantana
    Participant

    Hi I would like to know how can I get the distance between the AI and the player when he is inside the sensor’s influence zone and how to move the AI using just code. I want to use only the pathfinder and sensor features of RAIN and use my own AI framework.

    I have been searching but cant find anything.

    Thanks

    • This topic was modified 2 years, 5 months ago by  RaycoSantana.
    • This topic was modified 2 years, 5 months ago by  RaycoSantana.
    #12428

    CodersExpo
    Participant

    var activeSensor = _ai.Senses.GetSensor(“SensorName”);
    activeSensor.MatchAspectName(“AspectOnTarget”);

    //This is a collection, there could be more than one. I’m getting the first.
    if(activeSensor.Matches[0] != null)
    {
    var distance = Vector3.Distance(_ai.Kinematic.Position, activeSensor.Matches[0].Position);
    }

    …as for moving the ai in code there are many examples. Check the wiki. If you really can’t find it let me know.

    #12431

    RaycoSantana
    Participant

    Thanks a lot.
    I have been trying to move the character on my own, so far I have been reading the API and found “MoveTo” and “Move”, since I didn’t had the target from the sensor I used “MoveTo”:
    (_airig is the AIRig)
    _airig.AI.Motor.MoveTo(target.position);

    but I get a null reference exeption, Im certain “target” is not null, so my AI doesn’t have a motor but I assigned a CharacterControllerMotor on the AIRig,¿?

    #12438

    RaycoSantana
    Participant

    Nevermind I forgot the AI rig was added as a children and not as a component, I had to use GetComponentInChildren instead of GetComponent.

    I dont get any error now, however the character doesn’t move, I adapted the code you gave me and used activeSensor.Matches[0].Position as target for “MoveTo” but the character doesn’t move. The sensor however seems to work fine, is detecting me and the proper running animation is playing but the character is running in place.

    _ai.Motor.MoveTo(Sensor.Matches[0].Position);

    • This reply was modified 2 years, 5 months ago by  RaycoSantana.
    #12444

    CodersExpo
    Participant

    You have a mesh graph generated correct?

    #12446

    RaycoSantana
    Participant

    By mesh graph you mean a Navigation mesh? yes I do, I had used the behaviour tree to move the character before attempting to do it by code and it worked fine.

    using UnityEngine;
    using System.Collections;
    using RAIN.Core;
    using RAIN.Perception.Sensors;
    using RAIN.Motion;
    public class EnemyAI : MonoBehaviour {
    	public float lookAtDistance = 15.0f;
        public float chaseRange = 10.0f;
    	public float attackRange = 0.0f;
        public float damping = 6.0f;
    	public float CoolDownTime;
    	private CharacterController Controller;
    	private animationManager animator;
    	private RAINSensor Sensor;
    	private float CoolDown;
    	private float Distance;
    	private int i;
    	private AI _ai;
    	string Enemy_state;
    	public AudioClip[]Growls = {};
    	void Start(){
    		Controller = gameObject.GetComponent<CharacterController>();
    		animator = gameObject.GetComponent<animationManager>();
    		_ai = GetComponentInChildren<AIRig>().AI;
    		Sensor = _ai.Senses.GetSensor("Eyes");
    		Sensor.MatchAspectName("aPlayer");
    	}
    void Update () {
    	if(Sensor.Matches[0] != null){
    	Distance  = Vector3.Distance(_ai.Kinematic.Position, Sensor.Matches[0].Position);
    	}
    	if (Distance > chaseRange){
    			Enemy_state = "Idle";
    		}
    	if (Distance < chaseRange){
    			Enemy_state = "Chase";
    		}
    	if (Distance < attackRange){
    			Enemy_state = "Attack";
    		}
    	switch (Enemy_state){
    		case "Idle":
    		animation.Play (animator.Idle.name);
    		break;
    		case "Chase":
    		animation.Play (animator.Run.name);
    		_ai.Motor.MoveTo(Sensor.Matches[0].Position);
    		break;
    		case "Attack":
    		_Attack();
    		break;
    		}
    	}
    void OnTriggerEnter (Collider other){
    		if (other.tag == "Sword"){
            Enemy_state = "Hited";
    		StartCoroutine (Hit());
    			}
    		}
    void PainGrowl(){
    	AudioManager.Instance.PlayAudioOneShot(Growls[Random.Range(0,Growls.Length)]);
    	}
    void FootSteps(){
    	AudioManager.Instance.PlayAudioOneShot(AudioManager.Instance.footsteps[Random.Range(0,AudioManager.Instance.footsteps.Length)]);	
    	}
    void CollitionToggle(){
        BroadcastMessage("ToggleCollition");
    	}
    void SwordSwing(){
    		AudioManager.Instance.PlayAudioOneShot(AudioManager.Instance.Swings[Random.Range(0,AudioManager.Instance.Swings.Length)]);	
    	}
    IEnumerator Hit(){
    		if (animation.IsPlaying(animator.Hit.name) == false){
    		animation.Stop(animator.Attack[i].name);
    		BroadcastMessage ("DisableCollitions");
    		animation[animator.Hit.name].layer = 0;
    		animation.CrossFadeQueued(animator.Hit.name, 0.4f);
    		Controller.Move (transform.forward * -30*Time.deltaTime);
    		yield return new WaitForSeconds (animation[animator.Hit.name].length);
    	}
    }
    IEnumerator _Attack(){
    		if (CoolDown <= 0){
    		i = Random.Range(0,animator.Attack.Length);
    		CoolDown = CoolDownTime;
    		}
    		animation.CrossFade(animator.Attack[i].name, 0.2f);
    		yield return new WaitForSeconds(CoolDownTime);
    			}
    public void DisableIA(bool disableBool){
    		Controller.enabled = disableBool;
    		this.enabled = disableBool;
    	}
    }
    • This reply was modified 2 years, 5 months ago by  RaycoSantana.
    • This reply was modified 2 years, 5 months ago by  RaycoSantana.
    #12450

    CodersExpo
    Participant

    hmmmmm… and activeSensor.Matches[0].Position is returning a vector3 position correct? You should be able to set that as your moveTo variable.

    _ai.Motor.MoveTo(Vector3Position);

    If there is any way I can see the project I might be able to identify the issue…at this point I’m not sure. There must be more going on that I can’t determine from this blog.

    #12451

    CodersExpo
    Participant

    I see you have _ai.Motor.MoveTo(Sensor.Matches[0].Position); are you checking the progress of AI reaching the goal? For example in the custom action we return running or success depending on whether the goal Is reached. Perhaps your logic is not allowing time to path find and move to the target.

    #12452

    RaycoSantana
    Participant

    I don’t know what do you mean by “checking the progress of AI reaching the goal”, so I guess…no? the script I posted is all that there is to it.
    I did a debug.log of “Sensor.Matches[0].position” and it returned a value correctly.
    I cant upload the project, sorry. I have a 3G conection and the project is like 2GB (at 2kb/s it would take me literately weeks to upload it!), but I can upload images, tell me what do you want to see and I will upload an image.

    Thanks for you time.

    #12478

    CodersExpo
    Participant

    I see what you’re doing. The problem is the move behavior requires RAINAction. You need to create a class that subclasses RAINAction and call the Execute method passing in your _ai. Then do all your Move logic in there.

    For example, when you create a custom action node in the behavior tree and open that script, you will see how your class needs to look.
    In your monobehavior do:
    _ai.Motor.moveTarget = new MoveLookTarget(){VectorTarget = Sensor.Matches[0].Position};

    and then call the CustomAction script and in the Execute method do this:

    public ActionResult Execute(AI ai)
    {
    if(!ai.Motor.IsAtMoveTarget)
    {
    _ai.Motor.Move();
    return ActionResult.RUNNING;
    }

    return ActionResult.SUCCESS;
    }

    Hope this helps.

    • This reply was modified 2 years, 5 months ago by  CodersExpo.
    #12488

    CodersExpo
    Participant

    If you use my example above… you may find it still does not work, because there is more you need to do. So I did some research myself and found an old blog from Prime.

    “The problem is that you are doing this in a separate monobehaviour, which means the timing isn’t working out in relation to the AI timing. What you are trying to do isn’t impossible, but it is certainly not the way RAIN is intended to be used, so you are going against the workflow.

    The AI Update loop does Pre, Sense, Think, and Act in sequence, all in the same Update. Because of that, the results of your MoveTo call are never applied (the Motor applies Motion transforms in Act.) The ways you can insert your code into the process are:
    1) Turn off the setting for “Use Unity Messages” and then call those methods yourself manually.
    2) Move your code so that it happens in AI Think or Act.
    3) Use a Behavior Tree and a custom action.

    You could also try calling airig.AI.Motor.UpdateMotionTransforms yourself after your MoveTo.

    Overall, I recommend trying to fit back into the normal workflow. Use your code to set the move target for the AI, but use an AI Behavior tree to actually move to the move target.” -Prime

    I would suggest creating a behavior tree with a Move node. Assign a memory variable to the node and update that working memory variable with your mono script. That would be the easiest way.

    I also created some wiki documentation on creating a custom element that will allow you to hook into the AI methods Prime mentioned in his blog above as another option.
    http://rivaltheory.com/wiki/doku.php?id=ai:extension:start

Viewing 11 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic.