Build More Cubes is now on Steam

Yes, that is what I need to understand - how to make crowd control. The problem is each unit have its own health,speed,range and special features as push back,area of effect…etc. So imagine if one archer of my army is shooting towards an enemy unit in another army , if there is a leader in enemy army,how this exact enemy unit will now that it is been shot at? The problem of crowd AI is to handle individuals in a specific situations.



I have 1 enemy AI script that is executed per enemy on each 3 ticks, only if the enemy army is in player range(bubble of interest). Otherwise enemy armies are only tracking one object(tracker) which is very fast.
However in late game…we can have multiple armies in player range with multiple units in each army…that is when fps drops down.
In other words the problem with fps starts when the fight stars(every unit in one army 100+ units - is checking every unit in the other army 100+ units - for its range,damage and health and vice versa. That is 100*100 = 10000 operations per frame if there are 2 armies with 100 units in each.

have hitting an actor leave a property you erase later and do something with?
projectile adds property ‘wasHit’ (local vector) or ‘wasShotAt’?

if 'wasHit' in actor
   doCleverThing()

also, have you seen my act script Ai?

you could store a list that was orders for each unit, and call functions based on what each list holds (no logic per unit)

MyDict = { 'run':run, 'walk':walk , 'act':act, 'toggle':toggle , 'set':set } 
cont = bge.logic.getCurrentController()
own = cont.owner
for actor in battle:
    
    if len(actor['actStrip'])>=1:
         Next = actor['actStrip'][0]
         MyDict[Next[0]](cont,Next)
    else:
         print('RemActStip')
         del actor['actStrip']
         actor['Active']=False

Cool script! I’ll surely make use of it.
However the problem with mass units in the game is not making them do things, but deciding which unit should do things or not.
If we have 100vs100 units…how to decide how many of these 200 units are in range of each other so they can do things.
That is what is slowing the game - checking units ranges not units behavior.

I was thinking that your problem was 200 objects controlling themselves. Rather than 10 objects controlling 20 sub-objects…or so

what about adding a property, like units in range, and a value for the distance,

have your units sorted by attack range, and once you get past the distance, break the loop?

so we have,

navigate cluster, (every 3 frames)
check distance (every 3 frames but offset +1 from nav)
decide to attack( every 3 frames but offset +2 from nav)

attack code

for units in group:
   if distance<units['MaxDistance']:
       attack
   else:
       break

saving you cpu time for units not in range*

you can also use

if bge.logic.getRandomFloat()>.9:
    continue

10 % chance to skip proccessing this unit*

As BluePrintRandom suggests I would replace all scripts per unit into one master script to evaluate all objects. And store all units per army to loop over.

def run(cont):

    player_army # list of all cubes in your army
    armies_in_range # list of all armies, that were checked to be in the bubble range
    unit_responses # dictionary with unit types and associated unit functions

    enemies = []
    for army in armies_in_range:
        enemies.extend(army)

    for n in range(0, len(player_army)):
        # you could break this for loop that every frame max 50 units are evaluated,
        # which makes it very scalable because update frequency scales with total number of units
        unit = player_army[n]
        distance = unit.getDistanceTo #might be faster to pre-allocate a often used function
        type = unit["type"]
        for enemy in enemies:
            dist = distance(enemy)
            #sort out response of player unit, e.g. is new target better than current one
            unit_responses[type](unit, dist, enemy) 
            #sort out response of enemy unit
            unit_responses[type](enemy, dist, unit)             
     
    # after updating responses evaluate units for actions, again put this in a for loop over a list which you could
    # break to evaluate a max number of units per logic tick. Although you have to take frequency changes into account
    # not to make units moving twice as fast if there are only 10 or so :)

On the other hand there are probably smarter methods to sort out AI that does not involve checking every unit with every other enemy unit. Simple things would be, was unit attacked and can it strike back. Or is the enemy that did the most acumulated damage in range.

haidme, I know that this would be additional complex task, but… I think you need to add in formation. Basically some auto-created formations for enemy(e.g. swordmen in line 1, archers in line 2, wizards in line 3, knights or such in line 4) aswell as player being able to click on one of the formation settings somewhere on screen(maybe prepare 3 of them by yourself and let the player create 2 more) which makes his army automaticly format itself(each soldier approximately works to place where he is expected to be). This would make game more exciting and require more tactics. It’d also add some realism. For sure - this is just an idea.

Cool game, keep working on it, I look forward for the finished game.

Thanks Wraaah and Blue, The script that is checking(looping through units is only one, set in one place. Per unit scripts are only for their behavior. I’ve already tried something similar(sorting and checking only portion of all units in the army), it works fine, however I can’t see fps improvement…not sure but it is a bit complicated…it is really a matter of seconds to reduce greatly the units numbers, when two armies collide(many units are dying instantly) and checking only a portion of an army count becomes useless very fast.
I think the real problem is while fighting with one or two armies to check other armies that are in range but not fighting with my army yet. I need to know the range of every unit in those armies constantly also if some of my range units are attacking some of other enemy units with their range attack, so I can tell the enemy army to “turn around” and return to fire. There are many other factors that can trigger “attack” of my or enemy units…so for insurance best is to check every unit in the bubble range. Using as less loops as possible.

@ adriansnetlis - I was thinking about formations and additional control of the units.It is very easy to slip on this surface, because it really will look cool. But it will totally change the fun factor and casual idea behind the game. I want this to be as casual as it can be with no additional complications for the player. Just to play a few minutes and relax.

If I read it well enough, one persistent problem you have is how to let an army know one of its units is attacked. I would guess a simple solution would be to have all units have a link (unit[“leader”]) to the army controller, so when a unit is damages you can send a signal up this line for the army to respond. Some clever linking this way can probably give a very efficient network. Maybe just create a whole army hierarchy with officers to control smaller squads etc.

And if the CPU is frying and needs some time to sort it out maybe it is fun to throw blood and cube guts on the screen so the player is none the wizer if funny things happen :stuck_out_tongue:

One other thing I was thinking about is that it might be cool to differentiate units on their behavior. An assasin might want to infiltrate and kill the wizards, legionairs might bunch together in tight groups, archers might run away if melee comes too close, a barbarian might try a final brutal charge with cubes flying around in its death throes, and fast (cavelry?) cubes might circle around trying to pick off individual cubes.

create a whole army hierarchy with officers to control smaller squads etc.

Thanks! I thought I can workaround this, however you are the second person suggesting it…it seems it is the right way to go. Ok I’ll try to do something with this in my mind.

One other thing I was thinking about is that it might be cool to differentiate units on their behavior. An assasin might want to infiltrate and kill the wizards, legionairs might bunch together in tight groups, archers might run away if melee comes too close, a barbarian might try a final brutal charge with cubes flying around in its death throes, and fast (cavelry?) cubes might circle around trying to pick off individual cubes.

Very cool ideas. I’ve already done the basic logic for units different behavior. I might try and do something with your suggestions.
Thanks!

Have not read every comment so I’m sorry if I’m off here. If the problem is unit update why not simply do it alot less? Make every unit update once every say 120 frame, if that unit is in range to say atack an other unit, let it atack and force an early update on the unit being attacked. Flag the units (or groups) that are in active combat ant make them update more often. Always keep control of your updates, do so by using controlled stacks and dictionarys for links (hash keys are fast). And make sure to run everything from one master script, not on every unit. Using this methods will likely reduce the CPU usage alot. Other things to think about is collition control, if every unit is a actor/colider consider changing them to nocolition as this is mutch faster. Just some quick ideas from me, hope you at least find some value in it :slight_smile:

if each actor is simple static bound accept the leader, and the rest parent to the leader, then you have WAAAY less objects to think about, the parent is marked ‘compound’ in phyiscs

then each army can have a list (local units)

so you never iterate per unit unless the whole platoon is in range,
and then you only itterate per unit in those platoons, (not all)

hitting = check which unit is closest to hitpoint

Thanks,
I’ve already tried many things with logic but what I found is…all units are physical objects and I’m using real physic to control them. I think, that is the right way to do it. Otherwise there will be much more problems concerning movements, paddings between units and also grouping.
I come to the conclusion that actually physics it self consumes almost half of the processor time. Logic is actually not the problem in 200vs600 units on the map.
Now, I’ll try different physics setups and see which one works better(bounds types,material frictions, physics update…etc.)

But there is something else…very strange…when I start the game with a preset of 150 units in my army vs ~500 units in enemy armies the game runs with 30-40 fps for about 2-3 minutes. Then suddenly the fps drops to about 15 fps…with no visible reason. My units are still ~ 150 and enemy units are still ~ 500 but the game runs with 15 fps…any suggestions…memory leak maybe?

This might be the thing that fooled me in the first place…when I start the game with 5 units in my army vs 20 in enemy and continue to the point when there are 200 in my army and 600 in enemy the game drops fps slowly and it seemed it is because of logic and units count. However, when I start the game with 200vs600 units there is no problem with fps for about 2-3 minutes. It seems not logic, but something else is eating processor time slowly.

Or maybe I am missing something…like deleting dead units form dictionaries but still checking all units that have been spawned…but I triple check this kind of problems and everything seems alright. So, it still seems there is something weird going on.

what about only thinking for X units per frame and gives orders that are carried out over the course of time, so the ‘thinking’ part of the code is seperate from the actions that happen over time?

(so each unit only calls a small snippet per frame but some manager is giving all the orders of what to do)

(walk to pos,basic attack)

so the code that carries out the orders is dumb, but the ‘smart’ code only proccess x units per frame, so even if it takes 10 frames to think for each unit, they are all acting longer then that anyways

hard to explain it so I will just pass you a .blend

I kind of understand what you mean but it will be really better if you post a blend file, so I can be sure of this strategy.

so my ActStripBeta -

is

function1()

function2()

function3()

function4()

dict = { “function1”:function1, “function2”:function2 , etc}

and main does

command = commandList[0]

call function and feed it data*

http://www.pasteall.org/74548/python

so the code that does the over time stuff, will only be calling the relevant function per actor, and not looping through any other stuff,

so the ‘thinking’ code I will write tonight and try and drive as many actors as I can with as little overhead.

in this example, a switch or a piece of scenery can feed an action strip

next we need to do it with your ai instead.
http://www.pasteall.org/blend/43140

Interesting. I had done something like this for Krum combos execution order. I never thought It can be used in this kind of situation. Thank you.

Ok guys, this game is coming along nicely so far. I’m almost done with the core gameplay and interface. Now it needs world map and mission objectives. Here is the start screen, what do you think?

Hey guys, this is what I’ve done so far for the game - main screen,world map,several levels, quest system and interface. Hope you like it:

This game is looking awsome! Really liked krum and tomato jones, but this one i really relly want to play it.