Python:wait for a property to equal 10

How would I make a python script wait until a property equals ten before restarting the script? My property is actually the frame in an animation and I have a script that does changes another property when the frame isn’t 1 or 10. That works, but it changes the property too much. I want it to only change the property once, wait until the frame equals 10, then restart the script. Could anybody help me?

42 views and no replies, someone has to know something about this.

You just need a property sensor that checks your property to be 10.
The sensor can trigger whatever controller you want. If it is a python controller it should check the sensor to be positive (to avoid execution when the property is not 10 anymore).

I want to check for this within the python script.

So set up a script to run every logic tick (always sensor with true pulsed) and within the script:

cont = GameLogic.getCurrentController()
own = cont.owner
if own['actionprop'] = 10:
       do something

how can I get it to just restart the script without doing anything else?

You need to explain what your doing… :wink:

Your statement “restart script” makes no real sense in this environment.

I think you need to know that a script is running once every logic tick when at least one of the connected sensors fire a pulse (positive or negative).

The sensors fire a pulse if the state of the sensor changes (from positive to negative and from negative to positive). If a pulse button is activated the sensors fires pulses at every logic frame when the sensor is in the according state.

The script is executed with every activation!

According to your initial statements:

  • Scripts should NEVER wait for anything. This would block the execution of the internal gameloop.

I do not know what you want to achive, but it sounds like you could do it with logic bricks only.

I seem to be explaining this wrong. this sis the script:

import GameLogic as g
objlist=g.getCurrentScene().getObjectList()
arm=objlist["OBArmature"]
actlist=arm.actuators
sword_swing=actlist["sword_swing"]
frame=sword_swing.frame
if frame!=1.0 and frame!=10.0:
    cont=g.getCurrentController()
    hit=cont.sensors['hit']
    for ob in hit.hitObjectList:
             ob['hp']-=1

It is for causing damage when a sword hits an object with the hp property. My problem is that it causes the enemy to receive damage the entire time the sword is being swung, but I only want it to damage it one time. I thought that to fix this that I would make it wait till the animation is at frame 10 (the end) and then start the script again. I can see from your comments that I was wrong about this. So does anyone know how I can make it only reduce the hp by 1 every time the sword is swung?

replace

if frame!=1.0 and frame!=10.0:

with

if frame == 10:

You have to make sure that the script controller receives a pulse from a sensor to activate the script.
You could for example set TRUE level triggering of the “hit” sensor (the button with the three upper dots). Or you can add a sensor that triggers the controller when sword_swing.frame is 10 (property sensor).

or
reduce the hitpoints by 0.125 (8*0.125 = 1.0; frames with damage = 8). With that the enemy can run away before the action is complete.

I hope it helps

I want 1 damage to be caused if an enemy is hit at any time the animation is playing, not just at one single frame.

In that case your code is fine. But you have to check if you already decreased the hitpoints of an enemy during your animation.

I think there are multiple ways do achive that.

Here is one:

  • Add an int property “attackRound”.
  • Everytime the action is started increase attackRound by 1.
  • to your code above replace ob[‘hp’]-=1 with this code:

if not ob.has_key('lastHitRound') \
or ob['lastHitRound']!=arm['attackRound']:    
    ob['hp']-=1 
    ob['lastHitRound']=arm['attackRound']

example:

  • Your character performs the 5th attack -> attackRound changes to 5
  • you have an enemy A hit in round 4 with 10 HP
  • you have another enemy B never hit before with 20 HP
  • you have another enemy C with 15 HP is late and will be hit with animation frame 3

animation frame 1:

  • nothing happens as you excluded frame 1

animation frame 2:

  • enemy A is in the hit list and has property ‘lastHitRound’ with value 4 (previous round):
  • 4!=5 -> HP=10-1=9, ‘lastHitRound’ = 5
  • enemy B is in the hit list and has no property ‘lastHitRound’:
  • no property ‘lastHitRound’ -> HP=20-1=19, ‘lastHitRound’ =5
  • enemy C is not in the hit list

animation frame 3:

  • enemy A is in the hit list and has property ‘lastHitRound’ with value 5 (previous animation frame):
  • 5==5 -> do nothing
  • enemy B is in the hit list and has property ‘lastHitRound’ with value 5:
  • 5==5 -> do nothing
  • enemy C is in the hit list and has no property ‘lastHitRound’:
  • no property ‘lastHitRound’ -> HP=15-1=14, ‘lastHitRound’ =5
    next animation frames:
  • all enemies have ‘lastHitRound’ with value 5 -> no changes anymore

The next attack wil have attackRound 6 and all three enemies can receive damage again.

I hope this helps

From a pure python perspective, it’s quite easy. Maybe not the most efficient, but quite easy.


hit = False
count = 0

health = 100

collision = False #this is the one where it relies on BGE. this is if they're touching

if collision == True:
    if hit == False:
        health -= 1
    count += 1
    hit = True
    if count == 10:
        hit = False
        count = 0


I hope this makes sense, and is suitable for use in BGE. I’m 99% sure it would work in pygame.

Ok, I think I understand Monster, so i need a attackround property on the sword, and a lasthitround property on the enemy? then attackround will keep on adding up through out the game, unless I reset it right? And what is arm in your script?
@Fake: I didn’t understand how that would work at all.

Yes. But you don’t need to add the lastHitRound property to all the enemies as the property will be added by the script.

“arm” is your armature object (see your script that you posted earlier):

 
arm=objlist["OBArmature"]

Thanks Monster, it works pretty good now, the only problem is that sometimes it doesn’t do damage, or that it does 2 damage. I think it’s because the way I have it now it adds to attackRound every whenever the animation is playing. how can I make it just add to attackRound when the animation starts, like you said above.

import GameLogic as g
objlist=g.getCurrentScene().getObjectList()
arm=objlist["OBArmature"]
actlist=arm.actuators
sword_swing=actlist["sword_swing"]
frame=sword_swing.frame
if frame!=1.0 and frame!=10.0:
    cont=g.getCurrentController()
    hit=cont.sensors['hit']
    for ob in hit.hitObjectList:
             if not ob.has_key('lastHitRound') \
            or ob['lastHitRound']!=arm['attackRound']:    
                ob['hp']-=1 
                ob['lastHitRound']=arm['attackRound']
    arm['attackRound']+=1

Your

If frame!=1.0 and frame!=10.0
decides when the damage logic takes place.
If you for example decide that damage should only appear at rame 1 you can use

if frame==2:

if you want to know what objects receive the damage you can add


...
ob['lastHitRound']=arm['attackRound']
print "damage on",ob.name, ", hp is now", ob['hp'], "at round",ob['lastHitRound'],"at frame",frame

the result should be printed within the console (I haven’t tested that).

Such output usually helps to see how the logic works and if it is that what you expect.

the only problem with, if frame==2:, is that it won’t play frame 2 every time, it depends on the frame rate which animation frames are played. I think it is working good enough for now, if it messes up on other computers then I will try to change it.

My script was intended to only let every 10th hit do something

My script was intended to only let every 10th hit do something