Question: Timing animations

Hi, I was wondering if there was a way to find out or otherwise calculate the exact amount of seconds that a particular animation takes. I’m guessing you calculate it using number of frames and framerate right? But would it always take the same amount of seconds then, for varying framerate?

It’s because I want to use a timer property in conjunction with animations, as I’m not using frame properties in this case.

Thanks

BGE uses 24 fps (animation frame rate) at default.
If you have an animation of 60 frames then it will take 2.5 seconds.

So yes, you take: animation frame rate/animation frame count = outcome in seconds.

Animation frame rate can be found at the render tab(1st tab of the properties menu) scroll to display and there u find it.

using a property to play a animation, means you have total control of the framerate,

Ok thanks. But wouldn’t different PCs (better/worse) have different framerate?

Basically I want to make a timer property go to 0 when I play an animation, then after a certain amount seconds it will trigger a property sensor and add an object. It’s for drawing and sheathing weapons. I believe I’ve addressed this question before, though, but this is the specific method that I’m attempting this time around.

I think you can use system time.vs frame tick, to get framerate, and using that you could manipulate a property, that handled a action.

In the grand scheme of things however,

If you advance a property that is the actions frames, this means you always know right where the animation is :smiley:

If anim = 36 add thing

Oh yeah I know what you mean, that’s how you had it set up in your files that you sent me before. I’ll look into it but I would have to change a LOT of code and stuff. Well, maybe not too much, but idk. I might just trial and error it.

you can handle the property with python
:smiley:

Attachments

PropertyManagedActionPython.blend (402 KB)

you can also read the frame of the actuator.

ex:


    if not "old_frame_rounded" in own:
  own["old_frame_rounded"] = None
        
    fr = cont.actuators["name"].frame
    frame_rounded = round(fr)
if frame_rounded != own["old_frame_rounded"]:
  own["old_frame_rounded"] = frame_rounded
  f = frame_rounded
  if   f == 18 : do this()
  elif f == 89 : do this()
  elif f == 118 : do this()
  elif f == 258 : do this()

in this way you are sure that the frame new come only one time

PS: also if to me the animation is purely a detail , i not give to it the responsability to shoot bullet or something like this, is the animation that must be sinced to the logic, not the inverse…

Yar, I use the logic to sequence events, it’s just a bonus to be able to handle the animation with the same precision,

check this out

I call it clock work :smiley:

press space

Attachments

Clockwork.blend (443 KB)

Thanks but I’m not using actuators for the animations.

So I guess it remains as such; is there a way do to what you guys are doing if I’m using the .playAction() method instead of actuators, or should I change to actuators? There would be a lot of actuators that way I think.

Just use 1 actuator or 2, and change which animations it’s playing using python

I guess that would work. I guess I can change the type as well right, whether it’s flipper or play etc?

If you use python, you can use: object.getActionFrame(layer), it is the same that MarcoIT said, but with python.

Thanks carlo697 but that won’t work because I need the frame to be a sensor.

In general (as stated above) the animation system plays animations that they match the animation frame rate regardless the logic frame rate. [This might not work very well if the logic frame rate drops below 20% because of lags. In that case you have other problems ;).]

Therefore you can use a fixed formula as stated above. The fps is the ratio to convert between frames and seconds (frames per second).

This depends on. There are several different approaches to implement that.

I suggest to use a state machine:
State “opening pocket”:
When entering state -> play “opening pocket” animation
when “opening pocket” animation ends -> next state “draw weapon”

State “draw weapon”:
When entering state
-> add weapon
-> parent weapon to hand
-> play “draw weapon” animation
When “draw weapon” animation ends -> next state “ready to fight”

There are several ways to detect if the animation ends:
A) check the currently played frame with a property. (as suggested above)
Disadvantage: you need to configure the end twice (at the action setup and at the sensor)
Advantage: it is simple

B) use a timer. (as you asked)
Disadvantage: you need to configure the end twice + different values to configure
Advantage: it would work even without playing an animation

C) check if the animation is still playing see How to: create Action sequences with logic bricks - the power of the ActuatorSensor.
Advantage: you configure the animation end just once at one place
Disadvantage: more complicated + depends on the animation

D) check if the animation is still playing via Python.
Disadvantage: constantly running Python controller.

Thanks monster. The thing is it can’t just be either the animation is over or playing, it has to be specific parts of the animation as well, such as when to send a hit message. This would be when the frame is between a certain value, when the weapon is extended far enough. I think I want to use a property because a timer wouldn’t work as different weapons take longer or faster to play the animation, so an exact value is better anyway. So I have to figure out how to write the code BPR style.

I think you can set a frame property. so the animation sets it to the frame (using the actuator)

I have never used it however so I don’t know it’s behavior

if your playing the actions why python directly you can just getActionFrame(layer that action) , and then do something when it hits it or goes greater. I have something like this




player_armature = scene.objects[My characers armature]
print(player_armature.getActionFrame(1)) #prints the frame so I know whats frame

if player_armature.isPlayingAction(1):
        if player_armature.getActionFrame(1) > own["desired_frame"]: # wherever your frame variable is
               do this



I also use playAction()

Edit: Sorry I didnt see where someone had a reply similar to mine earlier, You could still use the method. just store getActionFrame(layer) to a property, then use the property sensor to tigger whatever it is your doing, But I dont see the need to trigger another sensor, just do whatever your going to do directly. I use the above method to trigger hits, So it does it at the right time, (actually with the swing, towards the end). Also I use it when parenting a weapon into a characters hand or holster\scabbard. That way it looks like they are grabbing it instead of it just jumping into their hand. I do the parenting towards the end of the animation so its smooth. And different weapons, ccharacters, stats, may have different swing rates or unsheath times. Finding a way to establish the property and change it as needed would be a start, so you can use the same code everyime and just change the variable you need. I store it on the weapons themselved, then when they are equipped I have a “holster_key_frame” property and a “contact_trigger_hit” property in a easily accessable place, that change when the weapon is swapped or equipped, that way i can reuse only the short code, all I have to worry about is changing the properties.

I could probably show you a crude example

if you had to manage only one action at time , you can use -> string & timer

action_name : str[“idle”]
action_time : timer [0.0]

bricks:
property changed (“action_name”) -> and -> property assign(“action_time”): 0.0

in this way you had just to change the string with the name of action and automagically the timer is reset.
be aware just that the timer operation require one(or two?) logic-tic

with calm :slight_smile: , do all checks necessary before to add object:

if action changed -> if action == “this” -> if timeaction > 2.0: add()

should work :wink:

B) use a timer. (as you asked)
Disadvantage: you need to configure the end twice + different values to configure
Advantage: it would work even without playing an animation

that is ever a good thing (ie : no dependence with animation details)

implementation:

import time


class MonoAction:
    def __init__(self, name=""):
        self.set(name)
    def set(self, name=""):
        self.name = name
        self._time = time.clock()
    @property
    def time(self):
        return time.clock() - self._time
        


usage:


if not "monoaction_instance" in own:
    own["monoaction_instance"] = MonoAction("shoot")


action = own["monoaction_instance"]


if action.name == "shoot":
    if action.time > 0.2:
        action.set("shooting")
        
elif action.name == "shooting":
    if action.time > 1.0:
        action.set("ready_to_shoot")



PS: i read now that you want multiple actions,
in this case can be better have a dictionary that contain all actions (instances)
each action can contain all sort of information (time, frame and all stuff of animation)
is not a my idea ,but i use a method similar.
i can post the code if can interest (just is bit complex due to optimization)