Jump to content

TylerH

Members
  • Posts

    525
  • Joined

  • Last visited

Everything posted by TylerH

  1. I have a nice update for everyone. I was able to convert everything over to the class-based system nicely. Here is a newer draft-draft pre-alpha weapon.lua script with all the functionality I want currently except Secondary Fire mode, Melee attack, and the handling of automatic fire: Here is the gold_xix.lua first, so you can see how relatively easy it is (this is all you have to do for your gun setup-wise): dofile("scripts/classes/weapon.lua") GoldXIX = { } GoldXIX_WeaponTable = { ViewModel = "abstract::HUD.gmf", Offset = Vec3(0.0,-0.005,0.05), Scale = Vec3(0.04,0.04,0.04) } GoldXIX = CreateWeapon(GoldXIX_WeaponTable) -- Properties GoldXIX.Primary.Delay = 400 -- Animations GoldXIX:AddAnimation("WEAPON_IDLE", 277.0, 302.0, 1.0) GoldXIX:AddAnimation("WEAPON_ZOOM_IDLE", 212.0, 238.0, 1.0) GoldXIX:AddAnimation("WEAPON_EMPTY_IDLE", 779.0, 804.0, 1.0) GoldXIX:AddAnimation("WEAPON_MOVE", 304.0, 326.0, 2.0) GoldXIX:AddAnimation("WEAPON_ZOOM_MOVE", 239.0, 261.0, 2.0) GoldXIX:AddAnimation("WEAPON_EMPTY_MOVE", 805.0, 829.0, 2.0) GoldXIX:AddAnimation("WEAPON_TO_ZOOM", 180.0, 187.0, 2.0, true) GoldXIX:AddAnimation("WEAPON_FROM_ZOOM", 188.0, 194.0, 2.0, true) GoldXIX:AddAnimation("WEAPON_FIRE", 62.0, 74.0, 3.0, true) GoldXIX:AddAnimation("WEAPON_ZOOM_FIRE", 262.0, 274.0, 3.0, true) GoldXIX:AddAnimation("WEAPON_FULL_RELOAD", 82.0, 150.0, 3.0, true) GoldXIX:AddAnimation("WEAPON_TACTICAL_RELOAD", 640.0, 690.0, 3.0, true) GoldXIX:AddAnimation("WEAPON_MINIMAL_RELOAD", 581.0, 639.0, 3.0, true) GoldXIX:AddAnimation("WEAPON_TAKE_OUT", 50.0, 58.0, 1.0, true) GoldXIX:AddAnimation("WEAPON_PUT_AWAY", 152.0, 159.0, 1.0, true) -- Initial Animation GoldXIX:SetState(WEAPON_IDLE) -- Sounds GoldXIX:AddSound("Fire", "abstract::fire.ogg", 65) GoldXIX:AddSound("ZoomFire", "abstract::fire.ogg", 265) GoldXIX:AddSound("EmptyFire", "abstract::fire.ogg", 697) GoldXIX:AddSound("WEAPON_DRYFIRE", "abstract::dryfire.ogg", 0) GoldXIX:AddSound("FullReload", "abstract::reload.ogg", 85) GoldXIX:AddSound("TacticalReload", "abstract::reload.ogg", 644) GoldXIX:AddSound("MinimalReload", "abstract::reload.ogg", 585) GoldXIX:AddSound("FullCock1", "abstract::cock2.ogg", 135) GoldXIX:AddSound("FullCock2", "abstract::cock2.ogg", 143) GoldXIX:AddSound("MinimalCock", "abstract::cock2.ogg", 629) And here are the snippets for all that you have to call in your render loop (this will be abstracted into its own little thing and use a simple WeaponSystem:Update() or something to check all weapons in the table): GoldXIX:Update() if (KeyHit(KEY_W)-KeyHit(KEY_S) ~= 0 or KeyHit(KEY_A)-KeyHit(KEY_D) ~= 0 and GoldXIX:GetState() == WEAPON_IDLE) then GoldXIX.Moving = true end if (KeyDown(KEY_W)-KeyDown(KEY_S) == 0 and KeyDown(KEY_A)-KeyDown(KEY_D) == 0 and GoldXIX:GetState() == WEAPON_MOVE) then GoldXIX.Moving = false end if (MouseHit(2) == 1) then GoldXIX:ToggleIronsights() end if (KeyHit(KEY_1) == 1) then GoldXIX:Toggle() end if KeyHit(KEY_R)==1 then GoldXIX:Reload() end if MouseHit(1)==1 then GoldXIX:PrimaryFire() end The library is pretty robust for the 546 lines that comprise the weapon.lua, and 231 lines in bullet.lua. They will both receive their upgrades as I start working my way through the rest of the feature tree, starting with the core stuff, and working towards eye candy and fun stuff (like akimbo and laz0rs ). Note that the commandset called in the game-loop is really that easy. The weapon's finite state logic and update loops will handle itself efficiently and properly, and has built in checks for commonly missed things like firing while reloading, etc. though bugs may exist and it will be improved. With permission I will either put a section with an API for this on the Wiki, or in its own thread. weapon.lua: dofile("scripts/utilities.lua") -- Defaults -- States WEAPON_IDLE = 0 WEAPON_TAKE_OUT = 1 WEAPON_PUT_AWAY = 2 WEAPON_AWAY = 3 WEAPON_FIRE = 4 WEAPON_RELOAD = 5 WEAPON_ZOOM_IDLE = 6 WEAPON_ZOOM_FIRE = 7 WEAPON_TO_ZOOM = 8 WEAPON_TO_NORMAL = 9 WEAPON_MOVING = 10 WEAPON_ZOOM_MOVING = 11 -- Globals WEAPON_SCALE = 0.6 -- Global scale shared by all weapons. Gun specific scaling is multiplied by this factor. It allows guns of different scales to appear similarly sized. -- Variables firstweapon=nil lastweapon=nil -- Weapons Table weapons={} function CreateWeapon( weapon_table ) local weapon = {} -- Sub Tables weapon.Animations = { } -- Table containing all animations weapon.Sounds = { } -- Table containing all sounds weapon.Effects = { } -- Table containing all effects (emitter, muzzle flash, brass, etc.) weapon.Attachments = { } -- Table containing attachments (ironsights, scopes, etc.) -- Properties weapon.AnimationBlending = 0.5 weapon.SwayScale = 0 -- X Axis Movement weapon.BobScale = 0 -- Y Axis Movement weapon.Zoomed = false weapon.Moving = false weapon.AutoReload = false -- Gun will automatically go to reload state if you try to fire with an empty clip weapon.Visible = true -- Start with the gun visible weapon.Selected = true -- Start with the gun selected -- Sound weapon.Volume = 1.0 weapon.Pitch = 1.0 -- Animation weapon.AnimationStartTime = AppTime() weapon.CurrentAnimation = "" weapon.CurrentAnimationFrame = 0 weapon.Animating = false -- Primary weapon.Primary = { } weapon.Primary.ClipSize = 12 -- Number of rounds in the clip weapon.Primary.Clip = 12 -- Current number of rounds in the clip weapon.Primary.Ammo = 240 -- Current total ammo (not including current clip) weapon.Primary.Damage = 0 -- Damage done per round weapon.Primary.ShotCount = 0 -- Bullets ejected per round weapon.Primary.Cone = 0 -- Spread cone (X,Y) weapon.Primary.Delay = 0 -- Time between current shot and next shot weapon.Primary.NextFire = AppTime() -- Time next shot can be fired -- Secondary weapon.Secondary = { } weapon.Secondary.ClipSize = 0 weapon.Secondary.Clip = 0 weapon.Secondary.Ammo = 0 weapon.Secondary.Damage = 0 weapon.Secondary.ShotCount = 0 weapon.Secondary.Cone = 0 weapon.Secondary.Delay = 0 weapon.Secondary.NextFire = AppTime() -- Finite State Logic weapon.State = 0 -- Weapons's current logic state -- World/View Models weapon.WorldModel = nil -- World View Model weapon.ViewModel = LoadMesh(weapon_table.ViewModel) -- First Person View Model weapon.ViewModel:SetParent(fw.main.camera,0) weapon.GunOffset = weapon_table.Offset weapon.GunScale = weapon_table.Scale weapon.ViewModel:SetPosition(Vec3(weapon.GunOffset.x*WEAPON_SCALE,weapon.GunOffset.y*WEAPON_SCALE,weapon.GunOffset.z*WEAPON_SCALE),0) weapon.ViewModel:SetScale(Vec3(weapon.GunScale.x*WEAPON_SCALE,weapon.GunScale.y*WEAPON_SCALE,weapon.GunScale.z*WEAPON_SCALE)) weapon.ViewModel:SetShadowMode(0,1) AppLog("We loaded and positioned the view model...") -- AABB Culling Fix... weapon.ViewModel.localAABB.x0=-3 weapon.ViewModel.localAABB.x1=3 weapon.ViewModel.localAABB.y0=-3 weapon.ViewModel.localAABB.y1=3 weapon.ViewModel.localAABB.z0=-3 weapon.ViewModel.localAABB.z1=3 weapon.ViewModel:UpdateAABB() -- Positioning / Offsets weapon.Offset = weapon.ViewModel.position:Copy() local gundisplayposition = weapon.ViewModel:GetPosition() local positionentity = FindChild(weapon.ViewModel,"FIRESPOT") or weapon.ViewModel -- Entity used for firespot location local displayposition = EntityPosition(positionentity) weapon.FireSpot = positionentity -- Muzzleflash weapon.Effects.MuzzleFlash = CreatePointLight(3) weapon.Effects.MuzzleFlash:SetParent( weapon.ViewModel ) local muzzleflash_color = weapon_table.muzzleflash_color or Vec4(1,0.6,0.0,1.0) weapon.Effects.MuzzleFlash:SetColor(muzzleflash_color) weapon.Effects.MuzzleFlash:SetPosition( displayposition ) weapon.Effects.MuzzleFlash:SetShadowMode(0) weapon.Effects.MuzzleFlash:Hide() function weapon:Update() if (not self.Selected and not self.Visible) then return end -- Idle State if (self:IsIdle()) then if (self:IsZoomed() and not self:IsPrimaryClipEmpty()) then if (self:IsMoving()) then self:PlayAnimation("WEAPON_ZOOM_MOVE") else self:PlayAnimation("WEAPON_ZOOM_IDLE") end else if (self:IsMoving()) then if (self:IsPrimaryClipEmpty()) then self:PlayAnimation("WEAPON_EMPTY_MOVE") else self:PlayAnimation("WEAPON_MOVE") end else if (self:IsPrimaryClipEmpty()) then self:PlayAnimation("WEAPON_EMPTY_IDLE") else self:PlayAnimation("WEAPON_IDLE") end end end -- Fire State elseif (self:IsFiring()) then -- Zoom Fire State if (self:IsZoomed()) then self:SetAnimating(true) self:PlayAnimation("WEAPON_ZOOM_FIRE") -- Normal Fire State else self:SetAnimating(true) self:PlayAnimation("WEAPON_FIRE") end if (not self:IsAnimating()) then self:SetState(WEAPON_IDLE) end -- Reloading State elseif (self:IsReloading()) then if (self:GetPrimaryClip() == 0) then self:PlayAnimation("WEAPON_FULL_RELOAD") else if (self:GetPrimaryClip() >= self:GetPrimaryClipSize()/2) then self:PlayAnimation("WEAPON_TACTICAL_RELOAD") else self:PlayAnimation("WEAPON_MINIMAL_RELOAD") end end if (not self:IsAnimating()) then self:SetState(WEAPON_IDLE) self:DoReload() end -- Taking Out State elseif (self:IsTakingOut()) then self:PlayAnimation("WEAPON_TAKE_OUT") if (not self:IsAnimating()) then self:SetState(WEAPON_IDLE) end -- Putting Away State elseif (self:IsPuttingAway()) then self:PlayAnimation("WEAPON_PUT_AWAY") if (not self:IsAnimating()) then self:SetState(WEAPON_AWAY) self.Selected = false self.Visible = false self.ViewModel:Hide() end -- No State? (Idle) else self:PlayAnimation("WEAPON_IDLE") end self.ViewModel:SetPosition(self.Offset:Copy()) self:UpdateSounds() end function weapon:Think() -- This can be used for AI, etc. Implement it if you want end -- Animation function weapon:AddAnimation(name,startframe,endframe,speedmodifier,oneshot) self.Animations[name] = {Name = name, StartFrame = startframe, EndFrame = endframe, Length = (endframe-startframe), Modifier = speedmodifier, OneShot = oneshot or false, Running = false} end function weapon:LoopAnimation(animation) local time = ((AppTime() - self.AnimationStartTime) / 100.0) local currentanim = self.Animations[animation] self.CurrentAnimationFrame = ((time * currentanim.Modifier * HOST_TIMESCALE) % currentanim.Length) + currentanim.StartFrame if (self.CurrentAnimationFrame < currentanim.StartFrame) then self.CurrentAnimationFrame = currentanim.StartFrame end if (self.CurrentAnimationFrame > currentanim.EndFrame) then self.CurrentAnimationFrame = currentanim.EndFrame end self.ViewModel:Animate(self.CurrentAnimationFrame, self.AnimationBlending, 0, 1) end function weapon:SetAnimation(animation) if (self.CurrentAnimation ~= "") then self.Animations[self.CurrentAnimation].Running = false end self.CurrentAnimation = animation self.Animations[animation].Running = true self.Animating = true self.AnimationStartTime = AppTime() end function weapon:PlayAnimation(animation) if (not self.Animating) then return end if (animation == nil or animation == "") then return end local time = (AppTime() - self.AnimationStartTime) / 100.0 local currentanim = self.Animations[animation] currentanim.Running = true if (not self.Animating) then currentanim.Running = false end self.CurrentAnimationFrame = (time * currentanim.Modifier * HOST_TIMESCALE) % currentanim.Length + currentanim.StartFrame if (self.CurrentAnimationFrame < currentanim.StartFrame) then self.CurrentAnimationFrame = currentanim.StartFrame end if (self.CurrentAnimationFrame > currentanim.EndFrame) then self.CurrentAnimationFrame = currentanim.EndFrame end self.ViewModel:Animate(self.CurrentAnimationFrame, self.AnimationBlending, 0, 1) if ((currentanim.OneShot and self.CurrentAnimationFrame >= currentanim.EndFrame-1.0) or currentanim.Running == false) then self.Animating = false currentanim.Running = false end end -- Sound function weapon:AddSound(name,soundfile,frame) local sound = LoadSound(soundfile) local sound_table = {Name = name, Frame = frame, Sound = sound, Source = CreateSource(sound)} local Weapon = self function sound_table:Update() self.Source:SetVolume(Weapon.Volume) self.Source:SetPitch(Weapon.Pitch*HOST_TIMESCALE) end function sound_table:Play() self:Update() -- Update volume and pitch self.Source:Play() -- Play source end self.Sounds[name] = sound_table end function weapon:UpdateSounds() for k,v in pairs(self.Sounds) do if (v.Frame == math.floor(self.CurrentAnimationFrame)) then v:Play() end end end function weapon:PlaySound(name) if (self.Sounds[name] ~= nil) then self.Sounds[name]:Play() end end -- States function weapon:GetState() return self.State end function weapon:SetState(state) self.State = state self.AnimationStartTime = AppTime() self.Animating = true end function weapon:IsIdle() return self.State == WEAPON_IDLE or self.State == WEAPON_ZOOM_IDLE end function weapon:IsFiring() return self.State == WEAPON_FIRE end function weapon:IsReloading() return self.State == WEAPON_RELOAD end function weapon:IsZoomed() return self.State == WEAPON_ZOOM_IDLE or self.State == WEAPON_ZOOM_FIRE or self.Zoomed end function weapon:IsEmpty() return self:IsPrimaryClipEmpty() end function weapon:IsAnimating() return self.Animating end function weapon:IsMoving() return ((KeyDown(KEY_W) - KeyDown(KEY_S)) ~= 0) or ((KeyDown(KEY_A) - KeyDown(KEY_D)) ~= 0) end function weapon:IsTakingOut() return self.State == WEAPON_TAKE_OUT end function weapon:IsPuttingAway() return self.State == WEAPON_PUT_AWAY end function weapon:IsAway() return self.State == WEAPON_AWAY end function weapon:IsSelected() return self.Selected end function weapon:IsVisible() return self.Visible end function weapon:Toggle() if (self:GetState() == WEAPON_IDLE) then self:SetState(WEAPON_PUT_AWAY) else self.Selected = true self.Visible = true self.ViewModel:Show() self:SetState(WEAPON_TAKE_OUT) end end function weapon:SetAnimating(anim) self.Animating = anim end -- Weapon Functionality -- Reload function weapon:CanDoReload() return (weapon:IsIdle() and weapon:GetPrimaryClip()<weapon:GetPrimaryClipSize()) end function weapon:Reload() if (not self:CanDoReload()) then return end self:SetState(WEAPON_RELOAD) end -- Performs actual clip reloading math function weapon:DoReload() if (self:GetPrimaryAmmo() >= self:GetPrimaryClipSize()) then if (self.Zoomed) then self:ToggleIronsights() end self.Primary.Clip = self:GetPrimaryClipSize() self.Primary.Ammo = self.Primary.Ammo - self:GetPrimaryClipSize() elseif (self:GetPrimaryAmmo() > 0) then if (self.Zoomed) then self:ToggleIronsights() end self.Primary.Clip = self:GetPrimaryAmmo() self.Primary.Ammo = 0 end end -- Primary Fire Mode function weapon:GetPrimaryClip() return self.Primary.Clip end function weapon:GetPrimaryClipSize() return self.Primary.ClipSize end function weapon:GetPrimaryAmmo() return self.Primary.Ammo end function weapon:IsPrimaryClipEmpty() return self.Primary.Clip <= 0 end function weapon:CanPrimaryFire() return (AppTime() >= self:GetNextPrimaryFire()) and (not self:IsReloading()) and (not self:IsPrimaryClipEmpty()) end function weapon:SetNextPrimaryFire(time) self.Primary.NextFire = time end function weapon:GetNextPrimaryFire() return self.Primary.NextFire end function weapon:TakePrimaryAmmo(num) self.Primary.Clip = self.Primary.Clip - num end function weapon:PrimaryFire() if (not self:CanPrimaryFire()) then if (self:IsEmpty() and not self:IsReloading()) then self:PlaySound("WEAPON_DRYFIRE") end if (self.AutoReload and self:GetPrimaryAmmo() > 0) then self:Reload() else return -- We can not perform a primary fire end end self:SetNextPrimaryFire(AppTime() + self.Primary.Delay) self:SetNextSecondaryFire(AppTime() + self.Secondary.Delay) self:SetState(WEAPON_FIRE) self:SetAnimation("WEAPON_FIRE") self:TakePrimaryAmmo(1) if (HOST_TIMESCALE == 1.0) then CreateBullet(self.FireSpot:GetPosition(1), fw.main.camera.mat:K():Scale(100)) else CreateBullet(self.FireSpot:GetPosition(1), fw.main.camera.mat:K():Scale(50*HOST_TIMESCALE)) end end -- Secondary Fire Mode function weapon:GetSecondaryClip() return self.Secondary.Clip end function weapon:GetSecondaryClipSize() return self.Secondary.ClipSize end function weapon:GetSecondaryAmmo() return self.Secondary.Ammo end function weapon:IsSecondaryClipEmpty() return self.Secondary.Clip <= 0 end function weapon:CanSecondaryFire() return (AppTime() >= self:GetNextSecondaryFire()) and (self:IsIdle()) and (not self:IsSecondaryClipEmpty()) end function weapon:SetNextSecondaryFire(time) self.Secondary.NextFire = time end function weapon:GetNextSecondaryFire() return self.Secondary.NextFire end function weapon:TakeSecondaryAmmo(num) self.Secondary.Clip = self.Secondary.Clip - num end function weapon:SecondaryFire() if (not self:CanSecondaryFire()) then return end -- We can not perform a secondary fire self:SetNextPrimaryFire(AppTime() + self.Primary.Delay) self:SetNextSecondaryFire(AppTime() + self.Secondary.Delay) end -- Melee Fire Mode function weapon:PrimaryMeleeAttack() -- TODO: Implement melee state, animation, sounds, and functionality end function weapon:SecondaryMeleeAttack() -- TODO: Implement melee state, animation, sounds, and functionality end -- Ironsights / Zoom function weapon:ToggleIronsights() if (self:IsPrimaryClipEmpty()) then self.Zoomed = false else if (self.Zoomed) then self.Zoomed = false self:SetAnimation("WEAPON_FROM_ZOOM") else self.Zoomed = true self:SetAnimation("WEAPON_TO_ZOOM") end end end -- Weapons Table Hierarchy if lastweapon==nil then firstweapon=weapon lastweapon=weapon else lastweapon.next=weapon weapon.prev=lastweapon end weapons[weapon]=weapon function weapon:Free() weapons[self]=nil end -- All weapons created from CreateWeapon inherit the base functionality implemented in this file weapon.Base = weapon return weapon end Questions? Comments? Concerns? etc.? A demo will be out soon, think within the week-ish. Another video will precede the demo.
  2. No, every single frame containing leg motion involved movement from the model's origin.
  3. In which case you wouldn't need any Lua setup other than looping the animation. Following AI Nodes and a Spline path is different from running an animation to give the illusion of the animal wondering around.
  4. They probably did, but then disabled it so they could have something new for CryEngine 3.
  5. That would be awesome. How about a portion where someone in the dexsoft viper falls through a hole in the terrain, but a character walks overtop it fine. Would be pretty humorous if you throw in some cheesy comments.
  6. For whatever use I would be I could voice. I have done machinima before.
  7. TylerH

    Hook System

    I don't disagree, I am just saying that a system to allow us to setup our own callbacks, however many, would be the best solution, though I guess that isn't easily doable since we can't play around in the engine (source) itself.
  8. My point was, that you can't create a script to have that cow follow waypoints, because the animation, over its 2500 frames, leads to cow to move around a 5 - 10 meter space. So no matter what, your cow will never be aligned to the movement of its character controller. You obviously don't understand that I was saying that your animation cycle is way too complex. You need a simple animation for the cow that has its legs or whatever move, but doesn't lead the cow to actually move 2-5 meters AWAY from its origin after 15 seconds.
  9. I am not sure how doable this is, because I don't know how much of the lighting system is internal to Leadwerks, but I would like to be able to create a given light and pass in my own shaders. Namely so that I can have both point lights and area lights, add dome lights, and just generally tweak the shaders to get my own creations. So either a light command where you can pass your own shader, or a bit of documentation how the lighting system works internally would be of use to me, and I am sure anyone else who is going to also be using Leadwerks for pure-visualization purposes.
  10. TylerH

    Hook System

    That seems a bit too specialized. Then you will have people who want an UpdateMatrix, Render, Draw2D, Draw3D, UpdatePhysics, OnCulled, OnCollision, all kinds of callbacks. It is better if people can implement things theirselves. I think the simplest set of callbacks for an entity would be: Pre-Update Pre-Draw Post-Update Post-Draw Then you can use them for whatever you want.
  11. TylerH

    Hook System

    File Name: Hook System File Submitter: TylerH File Submitted: 13 Dec 2009 File Category: Lua Scripts This is a relatively simple hook system, a near duplicate of the functionality offered in Garry's Mod. The API is rather simple: GetHooks - Returns the entire table of hooks Add(event_name, name, func) - Adds your callback function with the unique name to be called under event_name. Remove(event_name, name) - Removes your previously set callback with the name from event_name Call(event_name, ...) - Triggers all callbacks for the given event_name, passing the arguements ... (any that you want). Will also return any return values. Here is a simple example: In your entity, module, whatever: function DrawMy****() DrawRect(50,50,500,500) DrawText("Cake",0,60) end hook.Add("HUDPaint","MyEntity_DrawMy****", DrawMy****) In your fpscontroller.lua: require('hook') ... while ... RenderWorld() hook.Call("HUDPaint") Flip() end Pretty easy...works for everything from core functionality up to high level game logic. People in Garry's Mod really abuse this system, yet it is somehow rather fast. Click here to download this file
  12. This is exactly what you would use a hook system for...
  13. niosop tells you the truth. This is how I handle weapons going from idle animation to moving animation and back. Basically, everytime the animation state changes I reset the weapon.LastAppTime value, so that the animations play from where I want them, when I want them to.
  14. You can use ray tracing for almost everything related to lighting. It always was the best solution to the lighting equation in my opinion, but CPU ray tracers were always very slow.
  15. That final error is the HDR going bezerk. It happens quite often to me, I have to reload the map entirely. The iris adjustment doesn't like extreme changes to white or black or gray, it will just start flashing or just make the scene 10x bright.
  16. Umm, LoadScene does everything for me...lights, models, etc. It basically runs the Lua script for every entity it loads...
  17. I didn't know refraction could be used as the shadowshader. Does it even have an effect?
  18. You can add me on MSN messenger, jamesbond92393 [at] aol.com I can help you out.
  19. Oh! Since AddForceAtPoint is a global function, and the force and such you are adding is Local, you need to transform from the body's local space into global space. Switch nil and mesh1 positioning in the Transform command so mesh1 is first and nil is second, which should work properly
  20. I am curious how exactly you got the glass to work? My attempts using my own explained method had no luck...
  21. There are obvious sacrifices between the approaches. The state based approach makes it piss easy to do things like align sound frames exactly with animation frames, fire bullets at exact frames, etc. Not having states wouldn't make hardly any difference, and are kind of redundant since the weapon only really reacts based on the animation being set. How else would you handle it?
×
×
  • Create New...