Ray Casting shapes?

Hey guys,

Is it possible to ray cast a full shape? I want to do a field of vision type ray for my AI field of vision, but the ray sensor I believe only shoots a line out, rather than a shape in the form of a face.

So like if I had a cone parented to my enemies head, I would want it so it can cast a ray out in that circular cone end style shape, rather than just hope the player walks into the center of the vision and gets detected.

I was initially trying to make it work with the sensor, but thinking about now using the rayCast instead in python, is there maybe a way to dynamically change the rays position on the object like a scanning effect?

Could somebody maybe post an example of how to do something like that?

Thanks

The simplest way to do it is to start with a radar sensor for the cone of vision (this will tell you what is inside the field of vision but it ignores walls). Then you can cast a ray at the object and see if the ray hits anything. This isn’t a perfect solution, since the ray would be cast to the center of the object (so the AI wouldn’t be able to see, say, an arm sticking around a corner unless the corner wasn’t blocking the center of gravity of the character) but it’s a pretty standard solution for many games.

@ Veg

Very interesting, it looks like it could be very useful/cool for any game that wants pretty smart and trickable AI.

How is it on a realistic usablilty scale though have you tried? I mean do we see any framerate drop as the games scale increases and there is more foliage/walls that need to calculate? Or if you had a more complex shape, even a basic squarish robot shape would have a lot of pixels to count, which could cause lots of lag yes?

@ Cap Obliv,

So if I am understanding you actually, it would be basically checking if there is anything there in the first place, then it shoots the ray at it to see if it is covered by a wall or something?

If you use python

  • cast a ray at a potential target, if it hits, use it to:
  • get the angle between that and the ai’s forward direction

check this out :smiley:

Logic+python

each plane is added at a detection point, you could instead set a target in another object etc.

replace the plane adding code with

object[‘target’]=sens.hitObject

etc

Attachments

ConeScan.blend (456 KB)

That’s pretty freaky BPR.

Actually sdfgeoff is right, just get the vector from your AI to any targets that need to be checked, then compare that vector with your AI’s forward vector (which should be straight ahead on the y axis i.e. (0.0,1.0,0.0) though you can use any axis).

You can usethis code to compare two vectors and return an angle.

getVectTo also returns a distance to the target object, so you can discard any objects which are too far way.

Finally, for every object which is within the viewing angle and is not too far away you can usea ray casting checkto see if it is blocked by terrain.

Your code should be like this:

def ai_view_code(cont):
    own = cont.owner
    
    scene = get_scene_by_name("Scene")     
    
    ### get a list of all the objects you want to check for visibility
    agent_list = [ob for ob in scene.objects if ob.get("agent")]  
    
    viewing_distance = 500.0
    viewing_angle = 0.3 ### radians, not degrees
    
    
    for agent in agent_list:
        visible = False
        
        ### get vect to returns three things, we need distance and local vector
        
        distance,global_vector,local_vector = own.getVectTo(agent)
        
        
        ### if the distance is not too long        
        if distance < viewing_distance:
            
            ###we get the angle to the target                    
            target_angle = local_vector.angle([0.0,1.0,0.0])
            
            ### if the angle is less than the stated viewing angle            
            if target_angle < viewing_angle:
                
                ### make a collision check using a ray
                ### objects which block vision have the blocking property
                hit = own.rayCastTo(agent, 0.0, "blocking")
                
                if not hit:
                    visible = True
        
        ### you can now do anything you want with the visible object, 
        ### either make it visible, or add it to a targeting list or whatever.  
        ### here I'm just changing its color for debugging.
        ### you need to give it a material with "object color" enabled for this to work.                              
        if visible:                      
            agent.color = [0.0,1.0,0.0,1.0]
        else:
            agent.color = [1.0,0.0,0.0,1.0]

It works fine because I just checked it for my own project.

Wow thanks guys, it’s amazing how many different ways there are to do something like this! I tried the above code with the vectors, and it worked after replacing the line with .get() with a different way of getting the appropriate objects - for some reason get() was not working, my understanding of it’s functionality must be mistaken.

get() will return the value of the property.

If it is True the above code will work. If it is 0 or False or an empty String it won’t work.

it’s like saying:

property = True

if property:
    do something

Happy Blending! I’ll be using a similar script in my own project, I’m happy it can also benefit others.

I will just note that if you change:

hit = own.rayCastTo(agent, 0.0, “blocking”)

            if not hit:
                visible = True

To

hit = own.rayCastTo(agent, 0.0, “agentProp”)

            if hit:
                visible = True

It will have the same effect of looking for players with the agentProp and vision is blocked by walls and stuff without needing to add the blocking property to all items that block. Does the same thing, just may save you some work if there are a lot of items that would need blocking property.

Yes, that’s an interesting point.

I suggest being very careful how you organize your game with regards to rays, detection properties and physical properties.
Rays cast by rayCastTo() will be blocked and triggered by any physical object, even by ghost objects or transparent objects, like explosions or glass windows or things like that, if they are not set up as no-collision.

I used rayCastTo() in the above code because it seemed like it would be a little faster than rayCast() but actually after testing it wasn’t.

It’s probably best to use rayCast() with x-ray enabled and then set up as I have in the code above. That way you can specify what objects block vision and which don’t. So you can have a transparent window or a barred cell door, which you can’t walk through but which doesn’t block vision. It’ll also stop other agents from triggering the ray, that bizarre situation when two guards face each other and so neither of them can see because they block each other’s view completely. Another useful case would be smoke which blocks vision but can be walked through (a ghost object with the “blocking” property).

These are things you should think about when designing your game, because you will probably be making other collision or raycasting checks against other objects and you have to decide how the game is going to handle them while keeping your AI viewing script working as intended.