Can AI be cleared by using the bricks after a task has been completed?

(modelinblender) #1


Just thought I’d see if it is possible? I don’t think it was. So a check system, AI 1 is removed, 2, 3, and then scene needs to go to another scene to give confirmation or instruction.

(BluePrintRandom) #2


if objective achieved-----and-------set property in ai

if property is = what you set------do other thing

(modelinblender) #3

Not sure how that would work. Would python code be a better and quicker option for this?

(theoldguy) #4

I personally wouldn’t use python for that. If I have an AI script on the object and then delete the object in python, AI.endObject() I usually get an error, (because I suck at python). Instead I use a logic brick to end the object. Then I get no errors.
There is a way to do it in python though, so it’s up to you.

(modelinblender) #5

Well I prefer the bricks setup, but as others have stated with what I produced, it isn’t possible to do much with them, and if so, a lot of effort, and has buggy results.

I may plan to expand on this file, using bricks to get a character moving to a location. I tried that with a WIP file last year, was inspired from a game, but it never worked out due to the problems with getting AI to go to one place and then other, so timed and all of that.

(theoldguy) #6

You can do way, way more with python, than with logic bricks. But you can still make a small game with bricks. It’s been done before. As long as you keep your expectations low. You can also use both, python and logic bricks.

you can do that with bricks. I use the track-to actuator, it’s cheap and easy.
(cheaper than navmesh I think)

place nodes where you want your character to move to. Just a simple Plane, static, invisible, ghost, and give it a property.
“N1” boolean for example. name it something, “Node1” maybe, don’t matter.

Use states. If you want the character to move when the game starts, use state 1. if not use state 2.

on state 1-- Always, level, pin it so you can re-use it on state 2.

So - Always------and-------trackto “Node1” and a motion brick and your walk/run action. So the char will move to the Node1 plane. when he collides with the “N1” plane property, change the state to do something else.
collision “N1” ----- and------state 2.

on state 2. move to another node, or play an animation, whatever you have in mind.

I made an entire city with lots of people walking here and there, from home to a store, etc. using this method.

like this
nodes test.blend (1.1 MB)

(Cotaks) #7

just use simple messages for this.

When ai dies send a message.

then on an empty (or any object) you put a receiver for messages.
now if the receiver gets a message it increase a property by 1.

now you can simply use a property brick, if property equals 3 then load new scene/blend.

(theoldguy) #8

That will work, as long as the player doesn’t toss a grenade, or use an RPG to kill all the AI (enemy?) at once. (assuming AI are spawned) If so, only one message will be sent. Even though all AI died.
That’s where Python would be needed I think. :slight_smile:

For clarity;
AI = enemy?

(Cotaks) #9

depends on enemies indeed.

if multiple different enemies they can simply send different messages (for ex. enemy_1 killed, enemy_2 killed, etc). For multiple enemies that are spawned in, it gets harder, as @theoldguy mentioned they indeed will all send the same message, the downside of messages, the same message can only be received once per frame. on the same object)

python will then be indeed the way to go.

ai = enemy in this case indeed

(theoldguy) #10

Monster wrote a script that will handle this, it’s called MessageCount and works well in this case. All enemies send the message when dead. It’s probably in his signature. if not I think I still have a copy of the blend on my HDD if anyone needs it. :slight_smile:

(Thatimster) #11

I may be wrong, but from my knowledge BGE message sensor bricks only fetch the first received message which is why this is a problem (I had an issue with round based combat in my BGMC 15 entry).

The solution is to either use a python for loop to iterate over all received messages or keep a list of the spawned objects, and update the list when a death occurs.

(Cotaks) #12

This issue should be solved now, i have rebuild his game for him, i included the score count into, simple and neat solution.

(Monster) #13

The message sensor senses any message that passes through the sensor’s filter. To get the exact amount of messages or processes them one by one you need a python controller.

(theoldguy) #14

So I was experimenting with something like this. I used parts of a track_to_closest object script.

but instead of tracking to an object, used it to send a message to a text property counting the kills. if each ai near enough to die from a grenade or RPG died it would send a message. and it worked. As each ai died one at a time, the next nearest died and so on. updating a ‘kills’ property. Not all at once, but close.

Then, for shiitts and giggles, instead of using a message, I had each ai as it died, change the ‘kills’ property directly. and that worked also.

I really suck at python.

# enemies need a property 'hp'
# grenade needs a property fl 'timer'
# grenade needs a property 'sw' (switch)
# when spawned grenade detonates after 6 sec and ends everything with prop 'hp' and adds tp kills prop
# script is on the grenade in layer 11
# use UPBGE 2.77 or 2.78

import bge

def main():
    sce = bge.logic.getCurrentScene()
    kills = sce.objects['kills']
    kills.resolution = 8.0 # for text res

def gren(cont): # what happens when a grenade is thrown
    own = cont.owner
    sce = bge.logic.getCurrentScene()
    kills = sce.objects['kills'] # text
    ai = [obj for obj in sce.objects if 'hp' in obj] # enemies with 'hp' prop
    if ai:
        ai = sorted(ai,key=lambda enemy: own.getDistanceTo(enemy))[0]
# note: give the player an 'hp' property to avoid errors
    own['timer'] += 1 / bge.logic.getLogicTicRate() # so the grenade don't explode in the players hand   
    if own.getDistanceTo(ai) < 10 and own['timer'] > 4: # if enemy near grenade, goodbye
        ai.endObject() # will end the closest, then the next closest, and so on
        kills['Text'] += 1 # will add to kills each closest dead ai
        explode(cont) # boom pow pow
    elif own['timer'] > 4.5: # ends the grenade
def explode(cont): # function to explode only once
    own = cont.owner
    sce = bge.logic.getCurrentScene()
    if own['sw'] == False:
        sce.addObject("pow", own, 150)
        sce.addObject("dusttracker", own, 300)
        sce.addObject("explodetracker", own, 15)
        own['sw'] = True
def reset_gren(cont): # so grenade will kill again. wip. not done yet
    own = cont.owner
    sce = bge.logic.getCurrentScene()

Let me know if you think it’s useful. Or to expensive.

Open with UPBGE 2.77 or 2.78 or explosion material won’t work

grenade damage script.blend (1.0 MB)

(Cotaks) #15

is it not better to throw grenade, timer cooldown then at boom, it adds a plane (circle/sphere at sensor type) in a set size or animate it (like a shockwave) then on that plane you place a collision check, then simply loop trough the sens.hitObjectList and subtract hp from objects that holds hp?

Way better then using a script to find out what objects are near the grenade.

here is my take on a grenade:
grenade.blend (609.6 KB)

only code used here is:

# grenade by cotaks

# hit p  then hit spacebar to throw grenade

def boom(cont):
    own = cont.owner
    damage = 50
    sens = cont.sensors['Collision']
    if sens.positive:
        objects = sens.hitObjectList
        if objects:
            for obj in objects:
                if 'health' in obj:
                    obj['health'] -= damage
                    if obj['health'] <= 0:
                        #code here to add score
                        #score_count += 1

#oops you can remove the true pulse from the property timer.

(theoldguy) #16

Yes, I’ve used that technique. But the OP wanted to change to a different scene when all ai was dead. So if you toss a grenade in, and kill all ai, you only get 1 kill. Even though all ai are dead. Never changing to the new scene.
My solution adds 1 to “kills” for every ai that died.

I tried adding a message to your script, but it only counted one ai.
But as I said, i’m not good at Python.

i still like your idea tho.

yes of course, my FPS throws the grenade, he can also cook the grenade to make sure it explodes at the right time.
This is just a basic blend example, as my FPS is much to large, messy and complex of a blend.
Still, I should have thrown the granade like your example. My bad.

(Cotaks) #17

Sorry, it was not meant as your demo should throw it, was meant like in steps, throw, wait timer, explode

Anyway it works perfectly fine here, using messages is a no go, as said before only 1 per frame per object(receiver). Als don’t know if you readed it but i rebuilded his blends into an game.

so this wil work perfectly:
(put score property on the empty)

# grenade by cotaks

# hit p  then hit spacebar to throw grenade

def boom(cont):
    own = cont.owner
    damage = 50
    sens = cont.sensors['Collision']
    if sens.positive:
        objects = sens.hitObjectList
        if objects:
            #name of the objects holding the 'score' property
            score_holder = own.scene.objects['Empty']
            for obj in objects:
                if 'health' in obj:
                    obj['health'] -= damage
                    if obj['health'] <= 0:
                        score_holder['score'] += 1

Now simply put a property brick on the empty:
property-score-greater then 4 -> and -> change to winning scene

so 5 points/kills and you won the game

But with python you can directly do it in the script like this:

# grenade by cotaks

# hit p  then hit spacebar to throw grenade

def boom(cont):
    own = cont.owner
    damage = 50
    points_to_win = 5
    sens = cont.sensors['Collision']
    if sens.positive:
        objects = sens.hitObjectList
        if objects:
            #name of the objects holding the 'score' property
            score_holder = own.scene.objects['Empty']
            for obj in objects:
                if 'health' in obj:
                    obj['health'] -= damage
                    if obj['health'] <= 0:
                        score_holder['score'] += 1
                        if score_holder['score'] >= points_to_win:

Here working example:
grenade.blend (641.9 KB)

But in general a grenade should not be the one who sets a new scene.
a global ‘score’ check script should do this, else you have all weapons that checks for it, only getting a mess.

(Monster) #18

You need to be careful:

  • all enemies are dead


  • number of kills == number of enemies

are not necessary the same condition.

Both have different situations you need to think about.


  • you check how many enemies are alive

    • When you start without enemies you immediatly win?
  • you count kills

    • what if there are less enemies than kills?
    • what if there are more enemies that needed kills?
    • what is enemies respawn or needs to be killed twice or more?

Such Win conditions needs to be formulated very carefully. I also agree with Cotaks, win conditions should be handled by a separate instance.

When you find it inefficient to check the conditions all the time, you could establish a notification system that triggers the win condition checks when certain conditions change or might have changed e.g. when an enemy dies a message notifies the condition checker (it does not check the conditions by itself.). The checker checks the situation and decides if there is a win or not.

just some thoughts

(theoldguy) #19

OK guys, thanks. I guess I got excited that I actually wrote a script that worked, even if for the wrong reason. LOL.
I guess Monsters “MessageCount” script is still the best solution for multiple kills sending a message on the same frame.

Oh snap. Didn’t know. Good on ya mate.
So this should be marked solved.

(BluePrintRandom) #20

if health <1 ----------python

import bge

cont = bge.logic.getCurrentController()
count = 0
for object in cont.owner.scene.objects:
    if 'Enemy' in object:

if count<=1:
    #all bad guys are dead