# Decellerating Ai based on Player proximity

Heres my submarineAi script, and 2 questions:
Im trying to get the sub to come within a set distance of the Player, and the shoot. I am trying to fiwrite a “HoldPosition” function, because I want to slow the sub’s motion down which is based on force… I guess thats quite dependent on how Im calling Both the Move Towards and HoldPosition functions also, because I dont want to be calling MoveTowards and Hold position at the same time I dont think…either one or the other…I guess even opinions there would be helpful right now…

I figure ForceMode.VelocityChange is best to slow the objects speed down, but I dont know to get it into code. So the Ai subs’ existence is to spawn, Find enemy and move towards, get to a set distance from the player, and start shooting…

Thanks for any help!

``````var Speed = 3.0;
var rotationSpeed = 5.0;
var shootRange = 15.0;
var attackRange = 30.0;
var difference = 4.0;
var shootAngle = 4.0;
var dontComeCloserRange = 5.0;
var delayShootTime = 0.35;
var target : Transform;

private var lastShot = -10.0;

function Update(){

if (target == null  GameObject.FindWithTag("Player")) {
target = GameObject.FindWithTag("Player").transform;
}

var targetDirection = target.transform.position - transform.position;
var forward = transform.TransformDirection(Vector3.forward);
var angle = Vector3.Angle(targetDirection, forward);
var distance = Vector3.Distance(transform.position, target.position);
var targetRotation = Quaternion.LookRotation(targetDirection.normalized);
var str = Mathf.Min(rotationSpeed * Time.deltaTime, 1);
transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, str);

if (distance < shootRange  angle < shootAngle)
StartCoroutine("Shoot");
if (distance > shootRange  angle < shootAngle)
MoveTowards();
}

function Shoot ()
{

// Fire gun

// Wait for the rest of the animation to finish
yield WaitForSeconds(delayShootTime);
}

function RotateTowards (position : Vector3)
{

var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.1)
return;

// Rotate towards the target
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
}

function MoveTowards ()
{

if (distance < shootRange  angle < shootAngle)
HoldPosition();

}
function HoldPosition(){
//In here I am not sure how to apply thr force to slow down the object...
//?ForceMode.VelocityChange?//
);
}
``````

Thanks
AC

At a quick glance…

function MoveTowards ()
{

if (distance < shootRange angle < shootAngle)
HoldPosition();

}

Doesn’t work, because you are adding the force even though you might be telling the sub to holdposition… something more like this simple logic.

function WhatShouldTheSubDo ()
{
if (distance < shootRange)
HoldPosition();
else
MoveSub();

if(angle < shootAngle)
{
if (distance < shootRange)
{
Shoot();
}
}
else
{
RotateSub();
}

}

The sub should be able to rotate independently of the move/hold, and should only shoot if position and rotation are right.

Okay, go that. So heres how it looks now-Hopefully its an improvement, But I still need to fix the “Hold Position” function so It an compile and I can test it

``````var Speed = 3.0;
var rotationSpeed = 5.0;
var shootRange = 15.0;
var attackRange = 30.0;
var difference = 4.0;
var shootAngle = 4.0;
var dontComeCloserRange = 5.0;
var delayShootTime = 0.35;
var target : Transform;

private var lastShot = -10.0;

function Update(){

if (target == null  GameObject.FindWithTag("Player")) {
target = GameObject.FindWithTag("Player").transform;
}

var targetDirection = target.transform.position - transform.position;
var forward = transform.TransformDirection(Vector3.forward);
var angle = Vector3.Angle(targetDirection, forward);
var distance = Vector3.Distance(transform.position, target.position);
var targetRotation = Quaternion.LookRotation(targetDirection.normalized);
var str = Mathf.Min(rotationSpeed * Time.deltaTime, 1);
transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, str);

if (distance < shootRange  angle < shootAngle)
StartCoroutine("Shoot");
if (distance > shootRange  angle < shootAngle)
WhatShouldTheSubDo();
}
function WhatShouldTheSubDo ()
{
if (distance < shootRange)
HoldPosition();
else
MoveSub();

if(angle < shootAngle)
{
if (distance < shootRange)
{
Shoot();
}
}
else
{
RotateSub();
}

}

function Shoot ()
{

// Fire gun

// Wait for the rest of the animation to finish
yield WaitForSeconds(delayShootTime);
}

function RotateSub (position : Vector3)
{

var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.1)
return;

// Rotate towards the target
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
}

function MoveTowards ()
{          var targetDirection = target.transform.position - transform.position;
var forward = transform.TransformDirection(Vector3.forward);
var angle = Vector3.Angle(targetDirection, forward);
var distance = Vector3.Distance(transform.position, target.position);
var targetRotation = Quaternion.LookRotation(targetDirection.normalized);
var str = Mathf.Min(rotationSpeed * Time.deltaTime, 1);
if (distance < shootRange  angle < shootAngle)
HoldPosition();

}
function HoldPosition(){
///Yeehaa now to fix this bit
ForceMode.VelocityChange(  Vector3 (0, 0.3, 0));
Shoot();
}
``````

Thanks Seon-What you said made it a bit clearer, for sure…
AC

A general observation of writing AI code:

Probably a good general approach is to think of your AI as a finite state machine. Give it a bunch of states (e.g. “unaware” “trying to close” “shadowing” “fleeing” “shooting” “hiding”), a decision-making process, and some kind of mechanism for determining how often the AI changes state.

(From the Finite State Machine point of view, what you’re coding isn’t “AI” but “actions”. Tracking a target and moving towards it are actions an enemy may or may not take depending on their internal “state”.)

The key point here is that “AI” in some respects is too easy to do. What you want is “AS” (artifical stupidity) and/or “IB” (interesting behavior). An AI that singlemindedly charges towards you and fires with deadly accuracy is more like a missile than an opponent, and generally the fun in computer games is recognising enemy behavior patterns and exploiting them.

Once you start coding this way, you’ll discover all kinds of benefits:

1. You can easily vary the deadliness of an opponent’s behavior.

2. You can make behaviors that are amusing or stupid.

3. You can give enemies “personalities”.

Hmm I agree Podperson. Its not intelligence, its decision making based on Parameters-which should be easy to do…

I have tried to make this easier to read, and I apologise if the previous posts had too much clutter, and are therefore confusing/annoying…

Perhaps snippets are easier to trouble shoot? The thing is I couldnt really say what to leave in and what to leave out…

the error is: error BCE0017: The best overload for the method ‘AI 2.Shoot(UnityEngine.Vector3)’ is not compatible with the argument list ‘()’

Wheres a good place to start finding the language errors here?-Sorry, Im looking at my third day of trying to get this to compile…
Thanks

``````var Speed = 3.0;
var rotationSpeed = 5.0;
var shootRange = 15.0;
var attackRange = 30.0;
var difference = 4.0;
var shootAngle = 4.0;
var dontComeCloserRange = 5.0;
var delayShootTime = 0.35;
var target : Transform;

private var lastShot = -10.0;

function Update(){

if (target == null  GameObject.FindWithTag("Player")) {
target = GameObject.FindWithTag("Player").transform;
}

var targetDirection = target.transform.position - transform.position;

var forward = transform.TransformDirection(Vector3.forward);

var angle = Vector3.Angle(targetDirection, forward);

var distance = Vector3.Distance(transform.position, target.position);

var targetRotation = Quaternion.LookRotation(targetDirection.normalized);

var str = Mathf.Min(rotationSpeed * Time.deltaTime, 1);

transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, str);

WhatShouldTheSubDo();

}

function WhatShouldTheSubDo () {

var targetDirection = target.transform.position - transform.position;

var forward = transform.TransformDirection(Vector3.forward);

var angle = Vector3.Angle(targetDirection, forward);

var distance = Vector3.Distance(transform.position, target.position);

var targetRotation = Quaternion.LookRotation(targetDirection.normalized);

var str = Mathf.Min(rotationSpeed * Time.deltaTime, 1);

transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, str);

if (distance > shootRange)

MoveTowards();
yield;

if(distance < shootRange  angle < shootAngle)

Shoot();
yield;

if(distance < shootRange  angle > shootAngle)

RotateSub();
yield;
}

function Shoot (position : Vector3)
{

// Fire gun

// Wait for the rest of the animation to finish
yield WaitForSeconds(delayShootTime);
}

function RotateSub (position : Vector3)
{
var direction = position - transform.position;

direction.y = 0;

if (direction.magnitude < 0.1)

return;

// Rotate towards the target
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);

}

function MoveTowards ()
{
var targetDirection = target.transform.position - transform.position;

var forward = transform.TransformDirection(Vector3.forward);

var angle = Vector3.Angle(targetDirection, forward);

var distance = Vector3.Distance(transform.position, target.position);

var targetRotation = Quaternion.LookRotation(targetDirection.normalized);

var str = Mathf.Min(rotationSpeed * Time.deltaTime, 1);

}

function HoldPosition(){

rigidbody.velocity= Vector3 (0,0,.05);

Shoot();
}
``````

PS, if you just want to advise me on how to make it more readable, thats cool too. Cheers
AC

You’ve defined Shoot as “Shoot (position : Vector3)”, but you’re just calling it with Shoot(), and not passing it a vector3. Although you’re not doing anything with “position” in Shoot anyway.

–Eric

Eric Said[quote]
You’ve defined Shoot as “Shoot (position : Vector3)”, but you’re just calling it with Shoot(), and not passing it a vector3. Although you’re not doing anything with “position” in Shoot anyway.
[/quote]
Yes-Thats where I understand the problem is. If I have the (position : Vector3) part in both, it doesnt compile. If I have it in neither, it also does not compile. Is this something to do with properties vs varibles or similar?

Thanks for seeing the problem-as I saw it too…(But I just dont get it)

EDIT Whoops that one fixes ok its the rotate sub function I mean
AC

When you define a function like “function Shoot (position : Vector3)”, that means you have to pass an actual vector3 when you call the function. Like “Shoot(vector3(4, 7, 82) )”. Or

``````var myVector = Vector3(30, 20, 10);
Shoot(myVector);
``````

However, your function should actually do something with the variable that you’re passing…otherwise there’s no need for it.

–Eric

Yeah i goofed that up for some reason…That function actually worked( Should’ve removed that before posting.)

The bit that never worked, was the rotate Sub function:

``````function RotateSub (position : Vector3)
{
var direction = position - transform.position;

direction.y = 0;

if (direction.magnitude < 0.1)

return;

// Rotate towards the target
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);

}
``````

Thats the one that doesnt let me call RotateSub(); or RotateSub(position:Vector3); I cant pull "position:Vector 3 out because that doesnt work either…
Damn this is hard to explain . All I need is a stupid mistake (directing you to the wrong function)and I make it even worse…

It’s the same problem though. When you define RotateSub as you have, it’s saying “Hey, give me a Vector3 when you call me.” But “RotateSub()” passes nothing, so it fails. “RotateSub(position:Vector3)” is defining “position” as a vector3 and not passing anything, so that fails. You need to call RotateSub with an actual vector3 from somewhere.

``````var someplace = Vector3(22, 35, 66);
RotateSub (someplace);
``````

That’s just an example; I haven’t read through all your code to see what it does. But that’s how you call functions using variables.

–Eric

Ok cool. Thanks Eric. Thats got to help