Question for coders, about states.

The Question:
If I use logic bricks, I can only get 30 states, on an object. If I use Python instead, can I get more states than 30?
It’s for char. AI.

The Blah Blah. :slight_smile:
What I have done, is create people walking around a city randomly. They spawn move to a location, then end. Or just walk around the block, or go from store to store. Kinda like GTA. (Not making a GTA game, just testing the possibility)
But I want to use as few people as possible, maybe only 4 (a male, a female, a cop, and a bad-guy) on a hidden layer.
I change their clothes, and facial features as they spawn, and direct them to different nodes, placed in the city, with states. (The Navmesh will be uses for cops, and bad-guys, chasing the player) :slight_smile:

Right now I have six different shirts, pants, for one person. So that would give me a total of. . . what…36 combinations of persons, from one. (Math ugh) plus there are different hats, glasses, sunglasses, beards, mustaches, in the works that can be added when the person spawns.

Confusing, but it works. But I have run out of states.

Thanks

You could use empties parented to the characters for extra states… use a property sensors to decide which empty to look for your state in.

If you use python you can have infinite states, or as many as you can be bothered to program.

I don’t think you need states for controlling clothes or selecting navmeshes in python. You can just use a dictionary.

If you only use Python you don’t need states, you can just pass the correct arguments to a function a and that’s it. Or if you want to use states anyway you can use as much as you want of them in a lot of diferent ways (for example you can create behaviors and then assign them to diferent objects, instead of creating objects with diferent behaviors)

Why you use states to configure clothes?

States are useful to manage behavior.
It can tell what the individual character is currently doing. E.g. “walking”, “running”, “jumping”
or on an higher level:
“walk home”, “go to car”, “buy food” …

You see there can be several state machines (which process states) at different abstraction for different things even at the same time. For example motion states [walking, running] can be sub-states of business states [shopping, going to office].

Clothing
From your description I guess you are talking about “wearing” state. One or more states that describe what the person is wearing.

Here I would not use the build-in state machine. It makes not much sense. I would use several properties. For example:

hat, shirt, trousers, shoes

When dressing (can be a state of a different behavior) you set the properties and set the according clothes.

For example:

You change property “shoes” from “red business shoes” to “blue slippers”
The “shoe manager” recognizes the change and switches the mesh/object according to the property content.

This even works without python:


Property sensor "shoes" equals "blue slippers" -> and -> Edit Object replace mesh "Shoes.slippers.blue"

Yes, you can do it with Python too


shoeMeshesByPropertyValues = {
  "red business shoes" : "Shoes.business.red"
, "blue slippers" : "Shoes.slippers.blue"
}

...
   shoesPropertyValue = owner["shoes"]
   shoesMesh = shoeMeshesByPropertyValues[shoesPropertyValue]
   ...replaceMesh(shoesMesh)

There are many options to implement such a “cloth name to mesh/object name mapping”.

You are not limited with the number of clothes. From a certain point it is easier to use a Python file to manage the configuration.

NO NO guys, I misspoke I don’t use states to change clothes, I simply end the clothes I don’t want.

@Smoking Mirror: yes I know, (except for the dictionary part) I want to try python. Logic bricks are getting messy. Remember I’m just testing, for what works best, is least expensive, and fairly easy (For Me ) :slight_smile:

The states are used to direct the people.
Person spawns, and collides with sensor 1. changes to state 1, where, He tracks to node1, collides with node1, changes to state 2, where he tracks to node2. and so on. 4 nodes max then back to state 1. To avoid bumping into other people, I parented a plane (sensor) (instead of ray or radar) to the persons collision box, looking for property “person”. which, on collision, changes to another state that moves him diagonally to avoid the other person. But he has to continue on to his goal. Not go back to the first state. So the top 15 state slots are for direction. The bottom 15 slots are for avoiding people. There might be a better way, but I haven’t found it yet. Any idea of the best way to do the above with python?

person spawns on sensor 2 where he changes to state 5, and follows a different path, and so on.

I’m open to ideas, because as I said, just testing :slight_smile:

Sorry for the confusion. I know I’m not explaining things well.

(for example you can create behaviors and then assign them to diferent objects, instead of creating objects with diferent behaviors)

Hmm, might be better. But isn’t that what I’m doing? creating a behavior with states, and assigning it to the person as he spawns? I’ll have to check into that. I not good with python, I know a little. But I’m willing to learn.

The states are used to direct the people.
Person spawns, and collides with sensor 1. changes to state 1, where, He tracks to node1, collides with node1, changes to state 2, where he tracks to node2. and so on. 4 nodes max then back to state 1. To avoid bumping into other people, I parented a plane (sensor) (instead of ray or radar) to the persons collision box, looking for property “person”. which, on collision, changes to another state that moves him diagonally to avoid the other person. But he has to continue on to his goal. Not go back to the first state. So the top 15 state slots are for direction. The bottom 15 slots are for avoiding people. There might be a better way, but I haven’t found it yet. Any idea of the best way to do the above with python?

In your case, you can use the build in obstacle detection/avoidance of bge.
depending on how much you (ab)use it, it should create a nice effect.

here i made you an example:
obstacle avoidance.blend (532 KB)
look at the objects collision bounds (obstacle) and look at the world tab, scroll down to obstacle simulation, try both settings. Also this one uses a navmesh, so you can either use it adjust behavior even more with it, or just let it seek the end goal etc.

1 Like

Wow, that sounds complex.
For crowds I use a very simple AI.

  • Start at an origin.
  • Check all the possible neighboring locations.
  • Check which ones are not occupied by other agents.
  • Check if you have visited one of them before.
  • Chose an unvisited one randomly.
  • Add the destination to your memory and move to the target.
  • Mark the destination as occupied, mark your old origin as unoccupied.
  • Continue until there are no neighbors you haven’t visited.
  • At that point clear your memory continue.

As a modification if I want the AI to move to a target (player or other thing) I replace step 5 with:

  • chose the tile nearest to the target.

I do this with a grid, which I store as a dictionary.

Another way of doing it would be to seed a bunch of nodes around the map and initialize them so they find all their near neighbors which are accessible (do a ray casting check). The benefit of this one is that the nodes can be game objects and they can save their neighbors as a list property on themselves.

A stripped down, rather inefficient version of this would be:

import bge
import random 
# better to import the random module, more control

cont = bge.logic.getCurrentController()
own = cont.owner

if 'nodes' not in own:
    own['history'] = []
    own['nodes'] = [ob for ob in own.scene.objects if ob.get("node")]
    # if a list of nodes hasn't been created yet:
    # get all the objects in the scene with the "node" property (1)

### add some code here to check if you have reached the current target or if there is no target yet.

unvisited_nodes = [ob for ob in own['nodes'] if not ob in own['history']]

valid_node_list = [ob for ob in unvisited_nodes if not ob.get('occupied')] 
# all the nodes which are not occupied 

if valid_node_list:

     neighbor_list = [(ob.getDistanceTo(own), ob) for ob in valid_node_list] 
     # a tuple (a, b) with a being the distance from player and b being the object.

     nearest_3 = sorted(neighbor_list)[:3] 
     # sorted the list (2) and then stripped off all but the nearest 3. (3)

     if own.get('next_target'):
         own['next_target']['occupied'] = False
         # after the first run of the script you want to un-occupy the old target

     own['next_target'] = random.choice(nearest_3)[1] 
     # randomly choose the new next target, then get the second element from the tuple, the object.

     own['next_target']['occupied'] = True
     own['history'].append(own['next_target'])
     # mark the destination as occupied.

else:
    own['history'] = []

### add some code here to move the player to the next target
print (next_target)

for more info on this code see:
(1)
(2)
(3)

This will chose one of the nearest nodes.
You could use variations of this for setting up your nodes to store nearest neighbors.
If you start working like this you can make it more complex by adding walk-meshes and the like, or you can just add more nodes and keep the simple code.

I’ve had no problem with 100 agents running around with this type of system. The sorting part is the most time consuming, and you can contain that in an initiation phase by storing nearest neighbors on each node. Once you run it once you don’t have to run it again.

If some of your enemies are very smart you could adapt this code to run an A* search through the nodes too, but simple nearest neighbor is usually enough to get your enemies running in the right direction.

Thank you guys, I appreciate all the feedback. I’ll check all those out. That’s a lot to digest, but I will do it.
:slight_smile:

But I want to use as few people as possible, maybe only 4 (a male, a female, a cop, and a bad-guy)

Is this efficient with Blender? Giving all the states and logic? I read somewhere that a lot of big name games (AAA games) use this method, but is it worth it with blender?

@Monster,
Good info as usual. Thanks for the script example, even tho it’s related to clothes, The scripts will help me in the future.

@cotax;
Finally got the time to look at your blend, yeah, I can see where that would clear up some states. So you don’t really need a ray or sensor, it just knows that there’s an obstacle. I’ll test that out on my example.

@Smoking Mirror;
wow that is really complicated, When you say that script is not efficient, why is it not? should I not use it for testing?
I can see I won’t learn this over night. I booked-marked the Python links for further testing.

One thing is for sure, if I did want to develop a game, it would be best to hire a programmer. :slight_smile:

When considering programming efficiency:

  • It’s best to do as much calculation as you can before the game starts. So if you know something isn’t going to change in game you can hard code it.
  • Next best is to do as much calculation as you can only once when the game starts, since some of the data generated can’t be represented (like instances of characters, or randomly generated terrain) outside the engine.
  • Next most efficient is to calculate only when something changes. When a character arrives at a new node for example, or when it runs in to an obstacle. Usually this is handled by callbacks, or state changes.
  • Almost the least efficient is to calculate something at set intervals (like a logic brick set to pulse mode and an interval time of 12). Some of those calculations are going to be unnecessary.
  • Least efficient of all is to calculate something every frame. Programmers should only do this when absolutely necessary, like collision detection for very fast moving objects or other physics simulations, or when rendering.

The script above would be at number 3. But you could improve it by doing the neighbor calculations during the first frame of the game (2) and then choose the next tile from the current node’s neighbors. Because this script loops through a list of all nodes, it’s not as efficient as if you only calculated the current neighbor nodes.

It’s fine to use for testing though. If you have less than 50 nodes I don’t see it causing a big slow down at first. But if you have 100 nodes and a 100 people that’s a lot of calculations…

I think python isn’t that hard to learn. A good place to improve your python skills quickly would be code academy. I know a few people who used it and improved beyond recognition in a few weeks. Although I know at least one person who didn’t get any benefit from it at all and likely will never learn to code. Some people are just built that way.
Reading through an article on a specific function of python can be helpful, but unless you’re actually using the function at the time you probably won’t absorb the content.

@cotax;
Finally got the time to look at your blend, yeah, I can see where that would clear up some states. So you don’t really need a ray or sensor, it just knows that there’s an obstacle. I’ll test that out on my example.

Indeed the obstacle simulation already handles that for you, but be warned, abusing this method can eat lots of resources.
if you want to use this method, combine it with Smoking_mirror suggestion. use some kind of node system, and either build your checks for enemies behavior/obstacle avoidance or use the bge engine to avoid it (less objects with obstacle turned on the faster bge is).

I put together a little AI demo based on the suggestions above.
It could do with a little more development to clean it up, but it’s getting late here so I haven’t got time today.
I’ve tried to keep the code as simple as possible, no classes or anything like that.
If you uncheck set_debug on the main empty you can see the simulation without the guides.

Press 1 to add another agent (I added loads and logic was still very low)
press 2 to restart the scene with new random buildings
press 3 to toggle “hunting” in this mode the agents will try to get close to the player (green cone)

Some limitations:
Because it uses the servo motion actuator and physics sometimes the agents can got batty. They will fly about or start to flicker ans the servo actuator tries to keep them under control. With games that simulate a lot of agents I prefer not to use physics at all. IMHO Blender physics is overkill for what most games need.

I’ll do a video later, expand it and add it as a resource.

AI_demo.blend (902 KB)

Calculate at game start is only efficient if this calculation is based on data that is not available before the game starts. Otherwise point one would be the better choice.

I would rephrase this point as “only once when there is time and before the data is needed”. The game start is indeed a good time, as a possible lag would not be obvious. But there are many other cases, when it can be later than game start (e.g. when switching levels, when showing menu, when loading, …).

Btw. Using the build in states is very efficient unless you switch states very often (every frame or every second frame). The reason is simple: sensors of inactive states are not evaluated. This can be used to reduce the processing time of the heavy sensors such as near and radar sensors.

Are these individual people or types of people. I mean do you have exactly one male or several males (but with different clothes)?

What is the difference between these people? Do they behave differently? I mean is there a difference between female and cop (a cop can be female)?

I assume you want to use states to describe abilities (such as walking, waiting …). What abilities should a character have?

Sure, thats right.
It’s rather difficult to pass some data to the game engine like game objects lists, dictionaries or such unless you are using a lot of python.
If you have a level which is pre-made and never changes you could save the array of nodes and neighbors as a JSON dictionary and dump it in a text file to be loaded with the game. But you’d have to identify the nodes by ID number, maybe a property of each node… because references to game objects can’t be saved outside the engine.

You could use a bpy script to first add id number properties, then raycast to check viable path between nodes then sort by distance, cull distand neighbors and save to the dictionary.

@Smoking Mirror

When considering programming efficiency . . .

OK I see, I didn’t know any of that. That helps. This is gonna take some time, because I have a lot to learn. Thanks for that blend, I’ll check it out later.

If you have a level which is pre-made and never changes

The city with nodes could be made so it didn’t change. except with LOD.

Gawd, I feel like a two year old having a conversation with Einstein. LOL

@cotax
When you say node system, do you mean using track to actuator to a mesh (node)?
That’s the way I’m doing it now
Or is that a python keyword, or function, or something???
I probably will abuse obstacle simulation to see what it can and can’t do. :slight_smile:

@ Monster;

Yes the male and female are the same. They share the same actions. I crammed my old male and female mesh made with 2.49, onto an armature in resources (2.76a) with pre animated actions, not rigged perfectly, there is some mesh stretching, but that’s Ok for this test. (saved some time)

One female, with different clothes, hats, hair etc. (in the works)
One male with different clothes, baseball cap, fedora, straw hat, beard, mustache, etc. so far. I simply use the end object actuator to get rid clothes etc. I don’t need when person spawns.

It would be easier to create 30 or so copies of the people, and spawn them.

These people only walk from one place to the next, and are like “extras” in a movie.
They can be shot and killed, complete with death animation. But they don’t chase, or attack the player. They all are human figures with armatures, with walking, running, death animations.

I use planes as nodes placed around the city, Track to actuator, Motion, walking action, actuators to move them from one node to the other. The armature and collision box are interconnected. (select collision box shift select armature, draw a wire from the collision box to the armature) The collision box does all the thinking.
The armature only plays the action. (no animation properties)

using Blender 2.76a.

It’s confusing I know.

I plan to also have the people stop, and talk on the cell phone (like GTA) or something else. (Not sure what yet)
They are dynamic so they can move up and down ramps, move with motion, LocY This has been the most efficient method in my tests so far.

I tried track to closest scripts, and the Navmesh to simulate this. With the track to script, sometimes the people just stopped, same with Navmesh. (maybe something I did wrong)

So far I can spawn 35 people, and the FPS stays at 60. I even have a First Person shooter, still stays at 60. I’m going to expand the city and double that to see what happens.

One cop, one bad-guy. they are a little different from each other, and the people., but share the same actions as people, more actions will be added for fighting the player (not done yet) I probably won’t spawn more than 5 cops at one time.

(I don’t have any bad guys yet) but I have the cops that walk a beat, using the nodes, the same as the people do. But if the player shoots, (discharges) his weapon. The cop switches to state 2, and uses the steering actuator, and navmesh to chase the player. He has a ray (eyes), when he sees the player he he switches states, stops, shoots, with a shooting animation, a delay brings him back to chasing state after a few seconds. So far this works well.

I will do something similar with the bad guys. (not sure what yet)

So far what I have works really well. I’l hit play, walk away, come back a few minutes later. Still working.

I thought by using python It would be easier. Maybe something like “if collision with node1 own state 2”
“if ray.positive own state 3” But it looks way more complex than that.
:slight_smile: