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.
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.
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.
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…
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.
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
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.
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.
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 , do all checks necessary before to add object:
if action changed -> if action == “this” -> if timeaction > 2.0: add()
should work
“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)