Blender game light detection

Hello guys,
In my game, I have a flashlight that can be turned on or off. I want to detect whether the flashlight is shone on a particular object.how do I do this?

I came up with an idea:
I can use a cone mesh and detect collisions without having the mesh to collide. Is there an easier way to do this?

cast a ray from the flashlight to the position you point at, if ray hit something in set range(flashlite range) then do something.

But it’s a flashlight which means that I have to check if the ray is in the correct direction as well.
I thought that a cone would be easier.
Btw I need help with the raycasting end everything bcoz I’m noob and dont know anything about rays.

Depends what you wanna do with it.

option 1: cone shaped plane with collision sensor
option 2: flashlight object with a ray sensor
option 3: cast ray with python

option 3 will be the lightest of them all. But it’s all up to what you want/need.

How do I do option 2 or 3?

option 2: is as simple as slapping on a ray sensor, set it’s direction and do whatevery you like with it when it get’s positive. (so all logic bricks)

option 3:

hook up this script to your flashlight.
always -> python (module(hit script button) mode)-> scriptname.test (scriptname in text editor should end with .py.

def test(cont):
    
    own = cont.owner
    
    distance = 10
    vec_y = own.worldPosition - own.worldOrientation.col[1]
    
    ray = own.rayCast(own,vec_y,distance)
    
    if ray[0]:
        
        hit_obj = ray[0]
        dist = own.getDistanceTo(hit_obj)
        
        if dist<= distance:
            print('Object', hit_obj, 'is lit')

assuming you modelled it in the y direction as forwards

Use the Radar logic-brick sensor :slight_smile:

I get what you’re doing in the script (option 3) but the flashlight is a cone and not just a single ray.

your script detects if the player is directly looking at an object but should also accept over other angles through the vertex of a cone.

what your script detects:
image

but I also want to detect:
image

[I just need to detect if the monkey/suzane is in the range of the flashlight]

[btw, @RandomPerson, I managed to pull off the overlay transparency as you can see in the image]

The easiest way is to parent a cone shaped sensor object to your flashlight that matches the size of your light cone with a collision sensor attatched to it. You could either set the collision brick to detect a property or a material or use specific collision groups on your sensor and detectable objects.

The only drawback to this is that it will detect your objects through walls or other things in the way. That’s where the raycast comes in handy. When your cone detects an object, you cast a ray at it. If it hits the object, you know it’s actually in sight of your flashlight.

This also has a slight problem. A collision sensor doesn’t return a hit point, only the object or a list of objects. So, if your object is sticking out from behind a wall but the origin is still behind the wall, the ray cast won’t see it because it is firing at the object’s origin. That is why I recommend using a collision callback on the cone since it does return hit points. This is slightly more advanced scripting. If this situation won’t ever be an issue then don’t worry about it.

1 Like

I get your Idea of raycasting (and Cotaks’ idea too).
I need a way to get angle between the cast ray and the player’s local Y axis.
by doing this, i can simply check if the angle is less than the fov of the flashlight.
how do I do that?

I guess your flashlight moves independently of your player? Usually you would keep the flashlight locked to the camera and the camera is usually locked to the player’s forward axis(though x axis is made independant to look up and down). But you may be doing things differently so…

To get the angle between the two, you need the vectors corresponding to your desired axis.
The player’s Y+ axis vector is player_object.getAxisVect([0,1,0])
Use the same method to get the flashlight’s forward vector. Depending on how you built the flashlight, forward would be [1,0,0] if X+ is forward, [0,1,0] for Y+, [0,0,1] for Z+.

When you have the two vectors, you get the angle with angle = vector1.angle(vector2)

This returns in radians. If you’re more comfortable with degrees, you will have to import the math module - import math and use the degrees() method
angle = math.degrees(vector1.angle(vector2))

There may be much simpler ways to do this but it all depends on how you have constructed your player-flashlight hierarchy. There’s no one right way to do it but most of the time there are more efficient ways to do it that will save CPU/GFX resources.

No, the flashlight follows the player.
your post may help me but im noob and know nothing about rays or vectors.
let me illustrate the problem of my previous post.

imagine that this is the top-down view of the scene:


[made with paint]
you see what i mean?
if that angle is less than half the angle of the triangle, the object is in the range of the flashlight.

Yes, i am comfortable with radians.

The issue with this approach is you will have to check the angle of every object in the entire game to see if it is in the flashlight’s FOV. And then it would also have to be in the distance you chose. Even if you differentiate them by properties you still have to check all of them for the property first and then check if they are in range. If your map has 1000 objects(pretty easy to do when everything is an object), that’s 1000 things you are looking at every frame.

Imagine this code running every single frame:

for obj in owner.scene.objects: # Could be 1000's of objects
    vecTo = owner.getVectTo(obj) 
    angle = mathutils.Vector([0,1,0]).angle(vecTo[2]) # Create temp local Y+ vector and compare it to the local vector returned by getVectTo
    if angle < pi/4 and vecTo[0] < some_distance:
        print("Object in light field.") # Or whatever happens with it.

You can decrease this overhead by making sure you are only checking the angle of objects within a certain distance to the player. But you won’t know the distance until you check it’s distance. So again you are looking at every object in the map. There are other ways you can mitigate this brute force searching for objects like populating a list of only things you want to detect at the start of the map and then searching that smaller list later but these methods are only slightly better(and you would have to maintain the list manually as things come and go from the map).

This is why collision sensors are so useful. They don’t interact with something unless they are touching it. By using a cone shaped sensor object that matches your flashlight cone, you will detect everything the light would hit. When you turn off the flashlight, you can turn off the sensor and vice-versa.

I understand that this method is inefficient but i have to check this only for the ‘enemy’ objects.
that reduces the clutter but the cone is way better.
I just learnt about radar sensors that @RandomPerson mentioned and it does exactly what I wanted.
sorry for the delay and inconvenience

1 Like

I have encountered another problem.
as soon as the radar detects an object (even just one object) , the framerate drops to like 5fps.
any help?
is there a more efficient way?

option 1, 10 chars

what does “chars” mean?

characters, 10 are needed else you can’t post a message lol

another problem.
the cone goes through the wall and detects enemies that way.

yup the power of bricks, that’s why everyone should learn python, easiest language on the world.

cast ray to the collosion.hitObjectList, and see if they are hit instead of the wall or scale the plane to adjust it’s size, both wich require python