help on having detection radius for bot

trowa

09-02-2006 04:10:34

Currently, I'm doing a project where I've created a 3d-bot and let it move on a terrain created using setWorldGeometry('terrain.cfg'). There is no physics system in the application. And I'm currently using a RaySceneQuery to hold the bot above the terrain.

In the world i've placed somes structures and dummy players.
Now i need my bot to be able to detect whether buildings or players are around it.

I've tried using the following:

def detectObstacles(self, currentNode):
""" for detecting object in front """
uRay = ogre.Ray()
uRay.origin = currentNode.position
uRay.direction = currentNode.orientation * ogre.Vector3.UNIT_Z

self.obsRayQuery.ray = uRay
self.obsRayQuery.sortByDistance = True
self.obsRayQuery.queryMask = 0x00000011

obstacle = None

for qr in self.obsRayQuery.execute():
if qr.movable is not None:
if qr.movable.queryFlags == 0x00000001 and qr.distance < 100.0: #detect terrain
obstacle = qr.movable

if qr.movable.queryFlags == 0x00000010 and qr.distance < 50.0:
obstacle = qr.movable
break

return obstacle

the code will only allow detection which is directly infront of the bot.

I wonder is there any way to enable the bot to at least, detect in a fan-shaped fashion (ie. like how we perceive frontal things).

griminventions

09-02-2006 14:57:01

You could cast multiple rays in an arc to test for objects.

Srekel

12-02-2006 14:44:43

You can do it the way we did it for A Violent World.

getClosestTarget sets self.target to be the closest target within a certain field of view.


def getClosestTarget(self, actors):
"""
### Find the closest enemy (turrets are stupid, so they target the closest one,
### at least for now)
"""
nearDist = self.range ### This will be the distance to the nearest enemy
currDist = 0 ### This will be the distance to the currently nearest target

self.target = None

for actor in actors:
### Attackable actors only
if "Zombie" in actor.name or \
"Ninja" in actor.name or \
"Pirate" in actor.name:
### First we check if the enemy is within the cone in which the
### gun can rotate. Sinbad's explanation:
### "All you need to do is take the direction vector of the
### turret, and dot product it with the normalised vector from
### the turret to the point. The result is the cosine of the angle
### between the 2 vectors. If you define a visibility threshold in
### terms of this (1 is in the centre of the cone, 0 is 90 degrees
### away, so pick a value in between), you can determine if the
### object is within the cone. "
### So first calculate the dot product...
dotprod = self.dot(self.turret.direction,
self.normalize((actor.position[X] - self.turret.position[X],
actor.position[Y] - self.turret.position[Y],
actor.position[Z] - self.turret.position[Z])))
### Then we should check if the gun is allowed to target the enemy
### About forty (40) degrees to either side is a good limitation
### and since trig functions are slow, we just check against
### the dot product direcly.

### This is what it was first....
### if math.acos(dotprod) * 180.0 / 3.1415 < 40:
### ... but this is faster
#if dotprod > 0.6981:
if dotprod > self.spread:
### Manhattan distance.
currDist = abs(actor.position[X] - self.position[X]) + \
abs(actor.position[Z] - self.position[Z])

if currDist < nearDist:
self.target = actor
nearDist = currDist

self.calculateTargetDirection()
if self.target is None:
#print "No target!"
self.updateAIFrequency = 1.0
self.updateAITime = random.uniform(0, self.updateAIFrequency)

trowa

18-02-2006 12:11:33

To Srekel:
from my understanding, the suggested way works if a list of active actors is stored.

What I want from the bot is that itself has to detect (ie not obtaining information directly from the game simulation) what is infront of it and decide what to do.

Nevertheless your reply is still very helpful.

To griminventions:
would it be better if a single ray is used but only the direction is changed for the ray used in the rayscenequery?

griminventions

19-02-2006 03:12:02

would it be better if a single ray is used but only the direction is changed for the ray used in the rayscenequery?
Yes, it might save some CPU if you reuse the ray across multiple queries. You also might want to stagger them across frames so you can do more of them. For instance, do 6 queries but only do 2 or 3 per frame so it's not too expensive.

trowa

23-02-2006 09:33:17

would it be better if a single ray is used but only the direction is changed for the ray used in the rayscenequery?
Yes, it might save some CPU if you reuse the ray across multiple queries. You also might want to stagger them across frames so you can do more of them. For instance, do 6 queries but only do 2 or 3 per frame so it's not too expensive.



Sorry for my late reply.
But I wondering how would you stagger the ray queries across frames.

Forgive me as I have no idea of how to slice up CPU time so that a task can be done using few frames, and not in a single frame.

griminventions

23-02-2006 12:42:10

The easiest way in Python is to use generators. Simply yield at a couple places in a loop of queries. Pseudo-code:
def scan():
initialize query objects
while True:
# do 4 queries across 2 calls/frames/ticks
raysceneQuery
raysceneQuery
yield None
raysceneQuery
raysceneQuery
yield None

def logicUpdateLoop():
scanner = scan()
while gameRunning is True:
scanner.next() # perform 1 of the 2 query batches this tick
otherStuff

You'd want to structure it more than that in some kind of framework, of course, but just as an example of the gist of what I meant. In my engine, all logic updates are generators because they are not only distributable (in the sense of breaking up the processing across updates) but also faster than standard function calls since they maintain state and don't require a bunch of setup each call. So you could actually reuse the same query objects and also avoid the overhead of allocating/deallocating new ones each frame/tick.

You could also just use a counter during each update and limit the queries that way if you prefer to not use generators and instead have all the logic together in one function.

trowa

28-02-2006 04:13:02

can anyone verify that the following code will make a ray's direction change to 45 degree from the original position:

uRay.direction = currentNode.orientation * ogre.Vector3.UNIT_Z
# as the object is facing the z-axis of Ogre system by default


r = ogre.Quaternion(ogre.Degree(45), ogre.Vector3.UNIT_Y)
uRay.direction = r * uRay.direction


Is my code totally wrong?

trowa

01-03-2006 06:51:18

I think i managed to figure out on how to change the direction of the ray:
just change the ogre.Vector3.UNIT_Z vector to whatever direction you want the ray to shoot in.

To griminventions:
Thank you for your suggestions though i've only managed to implement a detection radius in a brute-force way. :)