• Make Scout Run
    5 replies, posted
Hello. So, I've managed to make a ragdoll walk by means of constraining its bones to a NPC's bones, like following its animation cycle(s). But not all models have an NPC script where I can call on certain actions (enumerations). I'm now looking to do stuff with the TF2 characters, for example the Scout. As a start I'm looking to see about making a Scout run around a bit. However, there doesn't seem to be any Scout NPC that I can send walk/run commands to. Tried creating various npc_ with the Scout model, but either it resulted in ERROR or the NPC's default model. I thought of an alternative which is to play the running animation on a prop while applying the appropriate velocity. However, there seem to be a few problems. 1: I try to play a running sequence with ResetSequence (in a timer loop) but the Scout isn't animating. I tried other animations but none were of that running type. 2: I spawn the Scout as a prop_physics so that SetVelocity or ApplyForce will work on him, but he seems to tilt to one side at first, then rolls around as he is being pushed. What other entity classes can I use instead? Or should I constrain him to another physics object that doesn't roll?
Yo. TF2 models uses an entirely different set of animations/activities as Garry's Mod, so you need to make sure you set all those accordingly.
There's a tool called the animated props tool. Try it. It lets you set animations on props/ragdolls.
You know, I was a little skeptical if buu342 understood what I really wanted, but turns out the tool was more or less what I was looking for. And as wauterboi said, yeah, there does seem to be more needed for "player" animations. After studying the code from the tool, I found that I just needed to add SetPoseParameter("move_x",1) and, well, now the Scout isn't standing still anymore, but more like running still. That is he seems to be paused on his first frame in the running animation (one leg up). I changed the class to prop_dynamic and now he is animating properly. Down side is not being able to push him about. But I guess that means I'll have to attach the Scout to another physics object to push around.
Well, looks like I've run into a new problem. When trying to "attach" the bones of the ragdoll Scout onto the dynamic Scout, the limbs do snap to the position of the Scout's running animation's First Frame. The ragdoll does not seem to follow the animation fully to making the ragdoll run with the dynamic. This is what I've used in a timer loop (0.01 seconds): [code] for i=0,ragdoll:GetPhysicsObjectCount()-1 do local phys = ragdoll:GetPhysicsObjectNum(i) local b = ragdoll:TranslatePhysBoneToBone(i) local pos,ang = animBase:GetBonePosition(b) phys:EnableMotion(true) phys:Wake() phys:SetAngles(ang) phys:SetPos(pos) if string.sub(ragdoll:GetBoneName(b),1,4) == "prp_" then phys:EnableMotion(false) phys:Wake() end end [/code] Are there any alternative "attachment" functions I should look for if I want the ragdoll to mimic the animation being played?
Ah, hey, look what I found from a long time ago! [code]function GM:HandlePlayerJumping(pl) if not pl.anim_Jumping and not pl:OnGround() and pl:WaterLevel() <= 0 then if not pl.anim_GroundTime then pl.anim_GroundTime = CurTime() else --[[if CurTime() - pl.anim_GroundTime > 0.2 then]] pl.anim_Jumping = true pl.anim_FirstJumpFrame = false pl.anim_JumpStartTime = 0 end end if pl.anim_Jumping then local firstjumpframe = pl.anim_FirstJumpFrame if pl.anim_FirstJumpFrame then pl.anim_FirstJumpFrame = false pl:AnimRestartMainSequence() end if pl:WaterLevel() >= 2 or --[[(CurTime() - pl.anim_JumpStartTime > 0.2 and]] pl:OnGround() --[[)]] then pl.anim_Jumping = false pl.anim_GroundTime = nil pl:AnimRestartMainSequence() if pl:OnGround() then pl:AnimRestartGesture(GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND, true) end end if pl.anim_Jumping then if pl.anim_JumpStartTime == 0 then if pl.anim_Airwalk then pl.anim_CalcIdeal = ACT_MP_AIRWALK else return false end elseif not firstjumpframe and CurTime() - pl.anim_JumpStartTime > pl:SequenceDuration() then pl.anim_CalcIdeal = ACT_MP_JUMP_FLOAT else pl.anim_CalcIdeal = ACT_MP_JUMP_START end return true end end pl.anim_Airwalk = false return false end function GM:HandlePlayerDucking(pl, vel) if pl:Crouching() then local len2d = vel:Length2D() if len2d > 0.5 then pl.anim_CalcIdeal = (pl.anim_Deployed and ACT_MP_CROUCH_DEPLOYED) or ACT_MP_CROUCHWALK else pl.anim_CalcIdeal = (pl.anim_Deployed and ACT_MP_CROUCH_DEPLOYED_IDLE) or ACT_MP_CROUCH_IDLE end return true end return false end function GM:HandlePlayerSwimming(pl) if pl:WaterLevel() >= 2 then if pl.anim_FirstSwimFrame then pl:AnimRestartMainSequence() pl.anim_FirstSwimFrame = false end pl.anim_InSwim = true pl.anim_CalcIdeal = (pl.anim_Deployed and ACT_MP_SWIM_DEPLOYED) or ACT_MP_SWIM return true else pl.anim_InSwim = false if not pl.anim_FirstSwimFrame then pl.anim_FirstSwimFrame = true end end return false end function GM:UpdateAnimation(pl, velocity, maxseqgroundspeed) local maxspeed = 200 if (pl:OnGround() and pl:Crouching()) then maxspeed = maxspeed * 0.3 elseif pl:WaterLevel() > 1 then maxspeed = maxspeed * 0.8 end local vel = 1 * velocity vel:Rotate(Angle(0,-pl:EyeAngles().y,0)) vel:Rotate(Angle(-vel:Angle().p,0,0)) pl:SetPoseParameter("move_x", vel.x / maxspeed) pl:SetPoseParameter("move_y", -vel.y / maxspeed) local pitch = math.Clamp(math.NormalizeAngle(-pl:EyeAngles().p), -45, 90) pl:SetPoseParameter("body_pitch", pitch) if not pl.PlayerBodyYaw or not pl.TargetBodyYaw then pl.TargetBodyYaw = pl:EyeAngles().y pl.PlayerBodyYaw = pl.TargetBodyYaw end local diff diff = pl.PlayerBodyYaw - pl:EyeAngles().y if velocity:Length2D() > 0.5 or diff > 45 or diff < -45 then pl.TargetBodyYaw = pl:EyeAngles().y end local d = pl.TargetBodyYaw - pl.PlayerBodyYaw if d > 180 then pl.PlayerBodyYaw = math.NormalizeAngle(Lerp(0.2, pl.PlayerBodyYaw+360, pl.TargetBodyYaw)) elseif d < -180 then pl.PlayerBodyYaw = math.NormalizeAngle(Lerp(0.2, pl.PlayerBodyYaw-360, pl.TargetBodyYaw)) else pl.PlayerBodyYaw = Lerp(0.2, pl.PlayerBodyYaw, pl.TargetBodyYaw) end pl:SetPoseParameter("body_yaw", diff) if CLIENT then pl:SetRenderAngles(Angle(0, pl.PlayerBodyYaw, 0)) --pl:SetRenderAngles(Angle(0, pl:EyeAngles().y, 0)) end end function GM:CalcMainActivity(pl, vel) pl.anim_CalcIdeal = (pl.anim_Deployed and ACT_MP_DEPLOYED_IDLE) or ACT_MP_STAND_IDLE pl.anim_CalcSeqOverride = -1 if self:HandlePlayerDriving(pl) or self:HandlePlayerSwimming(pl) or self:HandlePlayerJumping(pl) or self:HandlePlayerDucking(pl, vel) then -- do nothing else local len2d = vel:Length2D() if len2d > 0.5 then pl.anim_CalcIdeal = (pl.anim_Deployed and ACT_MP_DEPLOYED) or ACT_MP_RUN end end return pl.anim_CalcIdeal, pl.anim_CalcSeqOverride end function GM:DoAnimationEvent(pl, event, data) local w = pl:GetActiveWeapon() if event == PLAYERANIMEVENT_JUMP then pl.anim_Jumping = true pl.anim_FirstJumpFrame = true pl.anim_JumpStartTime = CurTime() pl:AnimRestartMainSequence() return ACT_INVALID end end local meta = FindMetaTable("Weapon") local OldSendWeaponAnim = meta.SendWeaponAnim function meta:SendWeaponAnim(act) if not act then return end --MsgN(Format("SendWeaponAnim %d %s",act,tostring(self))) if IsValid(self.Owner) and self.Owner:IsPlayer() and IsValid(self.Owner:GetViewModel()) and self.ViewModelOverride then self:SetModel(self.ViewModelOverride) self.Owner:GetViewModel():SetModel(self.ViewModelOverride) end OldSendWeaponAnim(self,act) end[/code] Kilburn helped me put this together. It's for player animations, but perhaps you can pick stuff from it. [editline]17th March 2015[/editline] Oops, it's missing the translations for activities, and I can't find TF2-specific activities. HMM. Working on it!
Sorry, you need to Log In to post a reply to this thread.