Little API to make an enemy see the player or objects

Hi there,

i just want to show you a few classes. You can use them very easily to make objects see other objects. For example enemys that can see the player. Let me know what you think about that or if there is something similar to that. I think AI is the most difficult part. After seeing that Norman has released a great Navmesh pathfinding api, i thought the next step could be to make enemys see you. Well, my version here is just in proof-of-concept state. Everything seems to work fine but i think there is a lot of space for correction because i’m neither a game developer nor very good in mathematics stuff ^^. Ok just tell me what you think about it:

Well first of all i show you the way the SightControl becomes implemented:

Vector3f sightPointSize = new Vector3f(0.1f, 0.1f, 0.1f);
playerSightObject = new SightObject(assetManager, “Player”); //This is just a node containing the “sightpoints” the SightControl can see
playerSightObject.addSightPoint(“foot_left”, new Vector3f(sightPointSize), new Vector3f(-0.6f, -2.4f, 0), ColorRGBA.Orange); //every sightpoint becomes added to the SightObject
playerSightObject.addSightPoint(“foot_right”, new Vector3f(sightPointSize), new Vector3f(0.6f, -2.4f, 0), ColorRGBA.Orange); //This SightObject will be later the player. It’s position and rotation becomes synchronized with the camera.
playerSightObject.addSightPoint(“knee_left”, new Vector3f(sightPointSize), new Vector3f(-0.6f, -1f, 0), ColorRGBA.Orange); //The SightControl of an Enemy will be able to “see” this SightObject.
playerSightObject.addSightPoint(“knee_right”, new Vector3f(sightPointSize), new Vector3f(0.6f, -1f, 0), ColorRGBA.Orange);
playerSightObject.addSightPoint(“bodyside_left”, new Vector3f(sightPointSize), new Vector3f(-0.4f, -0.2f, 0), ColorRGBA.Orange);
playerSightObject.addSightPoint(“bodyside_right”, new Vector3f(sightPointSize), new Vector3f(0.4f, -0.2f, 0), ColorRGBA.Orange);
playerSightObject.addSightPoint(“shoulder_left”, new Vector3f(sightPointSize), new Vector3f(-0.8f, 1.2f, 0), ColorRGBA.Orange);
playerSightObject.addSightPoint(“shoulder_right”, new Vector3f(sightPointSize), new Vector3f(0.8f, 1.2f, 0), ColorRGBA.Orange);
playerSightObject.addSightPoint(“torso”, new Vector3f(sightPointSize), new Vector3f(0, 0.8f, 0), ColorRGBA.Orange);
playerSightObject.addSightPoint(“head”, new Vector3f(sightPointSize), new Vector3f(0, 1.8f, 0), ColorRGBA.Orange);

sightControl = new SightControl(assetManager, rootNode); //the debugnode with the visible rays becomes added to this node
sightControl.addSightObject(playerSightObject); //Every SightObject you add can be seen by the SightControl
sightControl.setSightAngle(40f); //Sets the sightangle. If a SightObject is within this angle, the SightControl sees it
sightControl.setEnableDebug(true); //enables visible debug rays
sightControl.setDebugRayCount(30f); //count of the sightangle. Only visible if debug is enabled

Box enemyBoxShape = new Box(Vector3f.ZERO, 1f, 1f, 1f); //Load the enemy that will be able to see you, in this case it’s the evil monkey :wink:
Geometry enemy = new Geometry(“Bleed-through color cube”, enemyBoxShape);
Material mat_tls = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
mat_tls.setTexture(“ColorMap”, assetManager.loadTexture(“Textures/ColoredTex/Monkey.png”));
mat_tls.setColor(“Color”, new ColorRGBA(1f, 0f, 1f, 1f));

SightNode enemySight = new SightNode(sightControl, enemy); //The SightNode creates another node in it that contains the enemy’s geometry.
enemySight.setLocalTranslation(0, 0, -10); //It is just a helper. With this you can specify an offset to the point from where the rays come from.
rootNode.attachChild(enemySight); //If you attach the SightControl directly to the geometry the rays come from the center of the enemy’s geometry.
enemySight.setSightOffset(new Vector3f(0, 0, -1.2f)); //So the rays will always detect the enemy’s geometry as closest collision.
//We use an offset to make the rays start directly in front of the enemy’s face (in that case the box)
followCamControl = new SightHelper.FollowCameraController(cam); //This helper synchronizes the playerSightObject with the camera’s location and rotation.
followCamControl.setGunBaseOffset(new Vector3f(0, -1.8f, 0));

You can use this in update - loop to check if the SightControl sees something:
//If at least one SightPoint of the SightObject is seen and the sight-ray does not collide with an other
// geometry, the SightObject is considered to be seen and becomes added to the visible-objects-list. Call this in update-loop.
//Now for example you can move the enemy towards this position for example with the Navmesh pathfinder.
List visibleSightObjects = sightObject.getVisibleSightObjects();

The pink box is the enemy with a sightangle of 40 degrees. The orange points are the sightpoints that can be seen by the enemy. If ray between the enemy and the sightpoints are red, the enemy does not see the sightpoint. If it is green, the enemy sees the sightpoint (only if there are no other objects that collides with the ray).

The next step will be to make an enemy hear you. It will be rudimentary as this but i think it will help someone to create some hide-and-seek games like amnesia or slenderman or what ever.

Okay that’s it. Let me know what you think about it and tell me if it’s usefull or crap or if there are better solutions for this.

I think I see what you are talking about, correct me if I am wrong: you specify several points of an opponent’s mesh to see if an opponent is visible, as opposed to just the center point of the opponent. That’s a good idea, especially if some part of the opponent is peeking around a corner, say their head, you can see that but not the center point of the body.
To make the problem of colliding with yourself go away, as you have in this line:enemySight.setSightOffset(new Vector3f(0, 0, -1.2f));
there is a bug to add in collision groups to picking/collision. It’s on my todo list, but I might implement it sooner rather than later since it could be very useful in cases like this. However generally in an FPS you don’t render the main body of the character. The arms and gun are rendered in a different viewport and won’t collide with the ray since they are on a different root node.
If implementing this for a bot, I would only want to specify its field of view, in degrees, and its view range. The control would look at the rotation and location of the node and compute the rays accordingly. So I wouldn’t bother with the Sight Node, just have the sight control that attaches to that player node. In the control you would then just call getSpatial() to find the transforms of that node it is attached to.

Your stuff is looking good, keep it up. Anything like this goes through many iterations to get it just right.

Cool stuff. If it does what it should and you make sense of what you wrote still ( :wink: ) then it definitely was not pointless even if there was algos that did it 10.000x more efficiently :slight_smile: Hard to tell anything about the details but for a FPS-style or general update loop based and especially “designed visuals driven” games (UDK, Unity, jME SDK, eherm) it looks like it very much makes sense and is nicely extensible.

I guess you let it look for the “important” objects around it or “in range” and then check those in range more specifically right? That should pan out well for quite a while, you can easily extend it to use physics controls or geometry based raytrace checking for ultimate detail. You can add the needed metadata via Controls in the SDK as well as check for other existing relevant Controls (RigidBody / RagDoll etc.) easily to incorporate them into the results. This way the other systems wouldn’t have to adapt too much and by the use of Controls you could even try it all out directly in the SDK while you edit your levels when I finally get around to add support for custom AppStates like for custom Controls :slight_smile: (Edit: unless your Controls already work with a blank constructor, then you can already do it now :o)

Yes, that is the way i do it. You can specify as much “points-of-interest” of an object as you want. In this example i choose the players feet, head, shoulders, torso etc. So if the player hides somewhere that does not hide his feet, the enemy is still able to see him.

However generally in an FPS you don’t render the main body of the character. The arms and gun are rendered in a different viewport ...
That is interessenting. I did not knew that. But the problem is that the rays come from the enemy model and go to the player in that case. Because i want the enemy model, that is somewhere inside the scene, to see me. So i have to place the ray-starting-point in front of the model or ignore the enemy model if it is found in the collisionresults. The SightNode is just a helper so you dont have to wrap 2 nodes inside manually to create that offset. First i tried to calculate that offset mathematically by rotating the ray-starting-point around the geometrys position. I tried with quaternion and rotationmatrix. But i failed due to stupidity :D. But the SightNode-Solution has the same effect.

Yes i compute the visible object and check stuff like distance and sight angle (a bigger angle inside the range means that it is in the corner of the eye of the enemy - the chance for the player to be discovered by the enemy is lower). That’s why i should better return a list of an object with all needed infos (visibility of whole sightobject in percent or what ever, distance, angle of each sightpoint - and the stuff you suggested) But i think iam not deep enough into it to extend it in a reasonable way. Well actually i have no idea what could be the benefit by computing the rigidbody, ragdoll or physicsinformation or what “geometry based raytrace checking” is =) .

But i there is one question left for now: Is there a way to control how much a pixel or a geometry is illuminated? Then the player could hide in the dark. My first thoughts were to check how far all light sources are and check the properties of them (radius or direction of spotlight and there intensity etc.). But that could be a lot of work for a result that i don’t really like. Maybe there is an easier, more practical way?

I think you are making your program work hard not smart, and need to think more about the big picture of what you want to achieve and how it will work. See if you can come up with smart ways to do it rather than complicated.

For example you record brightness levels for various parts of the map, then that tells you the shadow level there which then says how easy it is to hide. etc.

Where can I get the source code for these classes?