How to set the object to detect the waypoint by range instead of line sight?
p/s: im using the FPS tutorial autowaypoint script and AI script.
How to set the object to detect the waypoint by range instead of line sight?
p/s: im using the FPS tutorial autowaypoint script and AI script.
What do you want the monster (or whatever is moving between waypoints) to do? Should it go to the closest waypoint in the direction of the target? Or follow a series of waypoints along a path? Or… well you get the idea… the impl may change depending on what you want to do.
One way to get the closest point is to have the monster (on spawn only, unless you generate new wpts on the fly) find all waypoints, stuff those into an array, and then when you want to pick a new point run through the list until you find the closest to the monster’s location.
Jeff
i would prefer the monster to follow a series of waypoints along a path. Which means it goes like A B C D E F…to Z waypoint accordingly.
Or maybe the closest waypoint in the direction will do too, just need to set more waypoints near to each other.
Well if you have a specific path on the waypoints for the monster to follow, then the waypoint can have a script that defines a “next waypoint” variable which you can then set in the editor. Your monster script will select the “next waypoint” as its new waypoint after it reaches some distance condition to the current waypoint. So for example Monster is going to waypoint A. Waypoint A has it’s “next” set to B, after the monster gets within 1 meter of A it will then start heading to B.
Jeff
static var waypoints = Array();
var connected = Array();
static var kLineOfSightCapsuleRadius = 0.25;
static function FindClosest (pos : Vector3) : AutoWayPoint
{
// The closer two vectors, the larger the dot product will be.
var closest : AutoWayPoint;
var closestDistance = 100000.0;
for (var cur : AutoWayPoint in waypoints)
{
var distance = Vector3.Distance(cur.transform.position, pos);
if (distance < closestDistance)
{
closestDistance = distance;
closest = cur;
}
}
return closest;
}
@ContextMenu ("Update Waypoints")
function UpdateWaypoints ()
{
RebuildWaypointList();
}
function Awake ()
{
RebuildWaypointList();
}
// Draw the waypoint pickable gizmo
function OnDrawGizmos () {
Gizmos.DrawIcon (transform.position, "Waypoint.tif");
}
// Draw the waypoint lines only when you select one of the waypoints
function OnDrawGizmosSelected () {
if (waypoints.length == 0)
RebuildWaypointList();
for (var p : AutoWayPoint in connected)
{
if (Physics.Linecast(transform.position, p.transform.position))
{
Gizmos.color = Color.red;
Gizmos.DrawLine (transform.position, p.transform.position);
}
else
{
Gizmos.color = Color.green;
Gizmos.DrawLine (transform.position, p.transform.position);
}
}
}
function RebuildWaypointList () {
var objects : Object[] = FindObjectsOfType(AutoWayPoint);
waypoints = Array(objects);
for (var point : AutoWayPoint in waypoints) {
point.RecalculateConnectedWaypoints();
}
}
function RecalculateConnectedWaypoints ()
{
connected = Array();
for (var other : AutoWayPoint in waypoints) {
// Don't connect to ourselves
if (other == this)
continue;
// Do we have a clear line of sight?
if (!Physics.CheckCapsule(transform.position, other.transform.position, kLineOfSightCapsuleRadius)) {
connected.Add(other);
}
}
}
which part of it that i can set the variable for the next waypoint? under the array?
So I was thinking something in FindClosest like:
var nextWayPoint : AutoWayPoint;
.
.
.
static function FindClosest (pos : Vector3) : AutoWayPoint
{
// The closer two vectors, the larger the dot product will be.
var closest : AutoWayPoint;
var closestDistance = 100000.0;
for (var cur : AutoWayPoint in waypoints)
{
var distance = Vector3.Distance(cur.transform.position, pos);
if (distance < closestDistance)
{
closestDistance = distance;
closest = cur;
}
}
nextWayPoint=closest;
}
static var nextWayPoint : AutoWayPoint;
static var waypoints = Array();
var connected = Array();
static var kLineOfSightCapsuleRadius = 0.25;
static function FindClosest (pos : Vector3) : AutoWayPoint
{
// The closer two vectors, the larger the dot product will be.
var closest : AutoWayPoint;
var closestDistance = 100000.0;
for (var cur : AutoWayPoint in waypoints)
{
var distance = Vector3.Distance(cur.transform.position, pos);
if (distance < closestDistance)
{
closestDistance = distance;
closest = cur;
}
}
nextWaypoint=closest;
}
.
.
.
.
this is after edited, seems that my monster wont even move to the waypoint anymore =.
How is the monster accessing the waypoint data?
In Start() I would probably use GameObject.FindGameObjectsWithTag().
waypoints = GameObject.FindGameObjectsWithTag("Waypoint");
var speed = 3.0;
var rotationSpeed = 5.0;
var shootRange = 15.0;
var attackRange = 30.0;
var shootAngle = 4.0;
var dontComeCloserRange = 5.0;
var delayShootTime = 0.35;
var pickNextWaypointDistance = 1.0;
var target : Transform;
private var lastShot = -10.0;
// Make sure there is always a character controller
@script RequireComponent (CharacterController)
function Start() {
Patrol();
}
function Update() {
// Auto setup player as target through tags
if (target == null GameObject.FindWithTag("Player")) {
target = GameObject.FindWithTag("Player").transform;
Patrol();
}
if (target == null){
Patrol();
}
}
function Patrol ()
{
// Auto setup player as target through tags
if (target == null GameObject.FindWithTag("Player")){
target = GameObject.FindWithTag("Player").transform;
}
var curWayPoint = AutoWayPoint.FindClosest(transform.position);
while (true)
{
var waypointPosition = curWayPoint.transform.position;
// Are we close to a waypoint? -> pick the next one!
if (Vector3.Distance(waypointPosition, transform.position) < pickNextWaypointDistance)
curWayPoint = PickNextWaypoint (curWayPoint);
// Attack the player and wait until
// - player is killed
// - player is out of sight
if (CanSeeTarget ())
yield StartCoroutine("AttackPlayer");
// Move towards our target
MoveTowards(waypointPosition);
yield;
}
}
function CanSeeTarget () : boolean
{
if (Vector3.Distance(transform.position, target.position) > attackRange)
return false;
var hit : RaycastHit;
if (Physics.Linecast (transform.position, target.position, hit))
return hit.transform == target;
return false;
}
function Shoot ()
{
// Start shoot animation
animation.CrossFade("shoot", 0.3);
// Wait until half the animation has played
yield WaitForSeconds(delayShootTime);
// Fire gun
BroadcastMessage("Fire");
// Wait for the rest of the animation to finish
yield WaitForSeconds(animation["shoot"].length - delayShootTime);
}
function AttackPlayer ()
{
var lastVisiblePlayerPosition = target.position;
while (true)
{
if (CanSeeTarget ())
{
// Target is dead - stop hunting
if (target == null)
return;
// Target is too far away - give up
var distance = Vector3.Distance(transform.position, target.position);
if (distance > shootRange * 3)
return;
lastVisiblePlayerPosition = target.position;
if (distance > dontComeCloserRange)
MoveTowards (lastVisiblePlayerPosition);
else
RotateTowards(lastVisiblePlayerPosition);
var forward = transform.TransformDirection(Vector3.forward);
var targetDirection = lastVisiblePlayerPosition - transform.position;
targetDirection.y = 0;
var angle = Vector3.Angle(targetDirection, forward);
// Start shooting if close and play is in sight
if (distance < shootRange angle < shootAngle)
yield StartCoroutine("Shoot");
}
else
{
yield StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
// Player not visible anymore - stop attacking
if (!CanSeeTarget ())
return;
}
yield;
}
}
function SearchPlayer (position : Vector3)
{
// Run towards the player but after 3 seconds timeout and go back to Patroling
var timeout = 3.0;
while (timeout > 0.0)
{
MoveTowards(position);
// We found the player
if (CanSeeTarget ())
return;
timeout -= Time.deltaTime;
yield;
}
}
function RotateTowards (position : Vector3)
{
SendMessage("SetSpeed", 0.0);
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 (position : Vector3)
{
var direction = position - transform.position;
direction.y = 0;
if (direction.magnitude < 0.5)
{
SendMessage("SetSpeed", 0.0);
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);
// Modify speed so we slow down when we are not facing the target
var forward = transform.TransformDirection(Vector3.forward);
var speedModifier = Vector3.Dot(forward, direction.normalized);
speedModifier = Mathf.Clamp01(speedModifier);
// Move the character
direction = forward * speed * speedModifier;
GetComponent (CharacterController).SimpleMove(direction);
SendMessage("SetSpeed", speed * speedModifier, SendMessageOptions.DontRequireReceiver);
}
function PickNextWaypoint (currentWaypoint : AutoWayPoint)
{
// We want to find the waypoint where the character has to turn the least
// The direction in which we are walking
var forward = transform.TransformDirection(Vector3.forward);
// The closer two vectors, the larger the dot product will be.
var best = currentWaypoint;
var bestDot = -10.0;
for (var cur : AutoWayPoint in currentWaypoint.connected)
{
var direction = Vector3.Normalize(cur.transform.position - transform.position);
var dot = Vector3.Dot(direction, forward);
if (dot > bestDot cur != currentWaypoint)
{
bestDot = dot;
best = cur;
}
}
return best;
}
This is my AI script. Check it out
Ah I see, so you’ll have to put that return closest
back into FindClosest the way you’re using it. I was assuming you would do the connections by hand in the editor but I see how the RecalculateConnected works now. I was assuming you’d do the connected links by hand, thus assuring that the paths were correct. So in this case the “nextWaypoint” suggestion doesn’t quite work, that’s what you’re connected list is. I guess if you are interested in shortest linear distance in addition to small angle between waypoints you will need to add some code to PickNextWaypoint to test linear distance as well and have some threshold that will skip over waypoints that are too far away… Anyway looks pretty good.
Jeff[/i]
// The closer two vectors, the larger the dot product will be.
var best = currentWaypoint;
var bestDot = -10.0;
for (var cur : AutoWayPoint in currentWaypoint.connected)
{
var direction = Vector3.Normalize(cur.transform.position - transform.position);
var dot = Vector3.Dot(direction, forward);
if (dot > bestDot cur != currentWaypoint)
{
bestDot = dot;
best = cur;
}
}
return best;
}
do u mean this part? changing the variable best to variable closest? as well as return closest?
p/s: Mind making me a small package to see your example? might give me a clearer picture lol.
Well not changing best to closest, but having something like:
// The closer two vectors, the larger the dot product will be.
var best = currentWaypoint;
var bestDot = -10.0;
var bestDist = 100.0;
for (var cur : AutoWayPoint in currentWaypoint.connected)
{
var dist = (cur.transform.position - transform.position).magnitude;
var direction = Vector3.Normalize(cur.transform.position - transform.position);
var dot = Vector3.Dot(direction, forward);
if (dot > bestDot dist < bestDist cur != currentWaypoint)
{
bestDot = dot;
bestDist = dist;
best = cur;
}
}
return best;
}
So this SHOULD give you the closest waypoint within bestDist meters that is a small angle from the current position.
I haven’t tested this but that was my idea.
Jeff