Skip to content

Commit

Permalink
Tweak missile physics
Browse files Browse the repository at this point in the history
  • Loading branch information
StyledStrike committed Jan 2, 2025
1 parent f315816 commit e152623
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 134 deletions.
61 changes: 61 additions & 0 deletions lua/entities/glide_missile/cl_init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
include( "shared.lua" )

function ENT:Initialize()
self.smokeSpinSpeed = math.random( 60, 110 )

-- Create a RangedFeature to handle missile sounds
self.missileSounds = Glide.CreateRangedFeature( self, 4000 )
self.missileSounds:SetActivateCallback( "ActivateSound" )
self.missileSounds:SetDeactivateCallback( "DeactivateSound" )

-- Assume we have one for now, to avoid issues with the lock-on warnings clientside
self:SetHasTarget( true )
end

function ENT:OnRemove()
if self.missileSounds then
self.missileSounds:Destroy()
self.missileSounds = nil
end
end

function ENT:ActivateSound()
if not self.missileLoop then
self.missileLoop = CreateSound( self, "glide/weapons/missile_loop.wav" )
self.missileLoop:SetSoundLevel( 80 )
self.missileLoop:Play()
end
end

function ENT:DeactivateSound()
if self.missileLoop then
self.missileLoop:Stop()
self.missileLoop = nil
end
end

local Effect = util.Effect
local EffectData = EffectData
local CurTime = CurTime

function ENT:Think()
if self.missileSounds then
self.missileSounds:Think()
end

if self:WaterLevel() > 0 then
self.smokeSpinSpeed = nil

elseif self.smokeSpinSpeed then
local eff = EffectData()
eff:SetOrigin( self:GetPos() )
eff:SetNormal( -self:GetForward() )
eff:SetColor( self.smokeSpinSpeed )
eff:SetScale( self:GetEffectiveness() )
Effect( "glide_missile", eff )
end

self:SetNextClientThink( CurTime() + 0.02 )

return true
end
214 changes: 82 additions & 132 deletions lua/entities/glide_missile.lua → lua/entities/glide_missile/init.lua
Original file line number Diff line number Diff line change
@@ -1,86 +1,7 @@
AddCSLuaFile()
AddCSLuaFile( "shared.lua" )
AddCSLuaFile( "cl_init.lua" )

ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.PrintName = "Missile"

ENT.Spawnable = false
ENT.AdminOnly = false
ENT.VJTag_ID_Danger = true

ENT.PhysgunDisabled = true
ENT.DoNotDuplicate = true
ENT.DisableDuplicator = true

function ENT:SetupDataTables()
self:NetworkVar( "Float", "Effectiveness" )
self:NetworkVar( "Bool", "HasTarget" )
end

local CurTime = CurTime

if CLIENT then
function ENT:Initialize()
self.smokeSpinSpeed = math.random( 60, 110 )

-- Create a RangedFeature to handle missile sounds
self.missileSounds = Glide.CreateRangedFeature( self, 4000 )
self.missileSounds:SetActivateCallback( "ActivateSound" )
self.missileSounds:SetDeactivateCallback( "DeactivateSound" )

-- Assume we have one for now, to avoid issues with the lock-on warnings clientside
self:SetHasTarget( true )
end

function ENT:OnRemove()
if self.missileSounds then
self.missileSounds:Destroy()
self.missileSounds = nil
end
end

function ENT:ActivateSound()
if not self.missileLoop then
self.missileLoop = CreateSound( self, "glide/weapons/missile_loop.wav" )
self.missileLoop:SetSoundLevel( 80 )
self.missileLoop:Play()
end
end

function ENT:DeactivateSound()
if self.missileLoop then
self.missileLoop:Stop()
self.missileLoop = nil
end
end

local Effect = util.Effect
local EffectData = EffectData

function ENT:Think()
if self.missileSounds then
self.missileSounds:Think()
end

if self:WaterLevel() > 0 then
self.smokeSpinSpeed = nil

elseif self.smokeSpinSpeed then
local eff = EffectData()
eff:SetOrigin( self:GetPos() )
eff:SetNormal( -self:GetForward() )
eff:SetColor( self.smokeSpinSpeed )
eff:SetScale( self:GetEffectiveness() )
Effect( "glide_missile", eff )
end

self:SetNextClientThink( CurTime() + 0.02 )

return true
end
end

if not SERVER then return end
include( "shared.lua" )

function ENT:Initialize()
self:SetModel( "models/glide/weapons/homing_rocket.mdl" )
Expand All @@ -97,18 +18,23 @@ function ENT:Initialize()
phys:SetDragCoefficient( 0 )
phys:EnableGravity( false )
phys:SetMass( 20 )
phys:SetVelocityInstantaneous( self:GetForward() * 200 )
phys:SetVelocityInstantaneous( self:GetForward() * 500 )

self:StartMotionController()
end

self.radius = 350
self.damage = 100
self.lifeTime = CurTime() + 6
self.maxSpeed = 3000
self.acceleration = 12000
self.turnEfficiency = 7
self.acceleration = 8000
self.maxSpeed = 4000 -- This appears to be the default limit of the physics engine
self.turnRate = 50 -- degrees/s
self.missThreshold = 0.9

self.target = NULL
self.missThreshold = 0.9
self.speed = 0
self.aimDir = nil

self.applyThrust = true
self.flareExplodeRadius = 200 * 200

Expand All @@ -117,7 +43,14 @@ end

local IsValid = IsValid

--- Prepare the missile.
function ENT:OnRemove()
local phys = self:GetPhysicsObject()

if IsValid( phys ) then
self:StopMotionController()
end
end

function ENT:SetupMissile( attacker, parent )
-- Set which player created this missile
self.attacker = attacker
Expand All @@ -126,6 +59,9 @@ function ENT:SetupMissile( attacker, parent )
self:SetOwner( parent )
end

--- Set the target this missile will track.
--- If the target is a player, seat, or a Glide vehicle, this will send
--- a network event to let the target know a missile is coming.
function ENT:SetTarget( target )
if not target:IsPlayer() then
-- Just use the target entity
Expand Down Expand Up @@ -188,12 +124,34 @@ function ENT:Explode()
self:Remove()
end

function ENT:PhysicsCollide( data )
-- Silently remove this missile when hitting the skybox
if data.TheirSurfaceProps == 76 then
self:Remove()
return
end

self:Explode()
end

function ENT:OnTakeDamage( dmginfo )
-- Don't explode when other Glide missiles damaged this missile.
if dmginfo:IsExplosionDamage() then
local inflictor = dmginfo:GetInflictor()

if IsValid( inflictor ) and inflictor:GetClass() == "glide_missile" then
return
end
end

if not self.hasExploded then
self:Explode()
end
end

local FrameTime = FrameTime
local Approach = math.Approach

local GetClosestFlare = Glide.GetClosestFlare
local ExpDecayAngle = Glide.ExpDecayAngle
local ZERO_ANGVEL = Vector()

function ENT:Think()
local t = CurTime()
Expand All @@ -205,38 +163,29 @@ function ENT:Think()

self:NextThink( t )

local dt = FrameTime()
local phys = self:GetPhysicsObject()

if not self.applyThrust or not IsValid( phys ) then
return true
end

self:SetEffectiveness( Approach( self:GetEffectiveness(), 1, dt * 4 ) )

if self:WaterLevel() > 0 then
self.applyThrust = false
phys:EnableGravity( true )
return true
end

local fw = self:GetForward()
local vel = phys:GetVelocity()

-- Accelerate
local speed = vel:Length()

if speed < self.maxSpeed then
speed = speed + self.acceleration * dt
end
local dt = FrameTime()

vel = fw * speed
self:SetEffectiveness( Approach( self:GetEffectiveness(), 1, dt * 4 ) )

-- Point towards the target
local target = self.target
local myPos = self:GetPos()
local fw = self:GetForward()

-- Or towards a nearby flare
local flare, flareDistSqr = GetClosestFlare( myPos, self:GetForward(), 1500 )
local flare, flareDistSqr = GetClosestFlare( myPos, fw, 1500 )

if IsValid( flare ) then
target = flare
Expand All @@ -254,43 +203,44 @@ function ENT:Think()
local dir = targetPos - myPos
dir:Normalize()

local decay = self:GetEffectiveness() * self.turnEfficiency
local myAng = self:GetAngles()
local targetAng = dir:Angle()

myAng[1] = ExpDecayAngle( myAng[1], targetAng[1], decay, dt )
myAng[2] = ExpDecayAngle( myAng[2], targetAng[2], decay, dt )
myAng[3] = ExpDecayAngle( myAng[3], targetAng[3], decay, dt )

phys:SetAngles( myAng )

-- If the target is outside our FOV, stop tracking it
if math.abs( dir:Dot( fw ) ) < self.missThreshold then
self.target = nil -- We've missed
self.target = nil
self.aimDir = nil
else
-- Let PhysicsSimulate handle this
self.aimDir = dir
end
else
self:SetHasTarget( false )
end

phys:SetVelocityInstantaneous( vel )
phys:SetAngleVelocityInstantaneous( ZERO_ANGVEL )

return true
end

function ENT:PhysicsCollide( data )
if data.TheirSurfaceProps == 76 then
self:Remove()
return
local ApproachAngle = math.ApproachAngle
local ZERO_VEC = Vector()

function ENT:PhysicsSimulate( phys, dt )
if not self.applyThrust then return end

-- Accelerate to reach maxSpeed
if self.speed < self.maxSpeed then
self.speed = self.speed + self.acceleration * dt
end
self:Explode()
end

function ENT:OnTakeDamage( dmginfo )
if dmginfo:IsExplosionDamage() then
local inflictor = dmginfo:GetInflictor()
if IsValid( inflictor ) and inflictor:GetClass() == "glide_missile" then
return
end
if self.aimDir then
local myAng = self:GetAngles()
local targetAng = self.aimDir:Angle()
local rate = self.turnRate * dt

myAng[1] = ApproachAngle( myAng[1], targetAng[1], rate )
myAng[2] = ApproachAngle( myAng[2], targetAng[2], rate )
myAng[3] = ApproachAngle( myAng[3], targetAng[3], rate )

phys:SetAngles( myAng )
end
if not self.hasExploded then self:Explode() end

phys:SetAngleVelocityInstantaneous( ZERO_VEC )
phys:SetVelocityInstantaneous( self:GetForward() * self.speed )
end
18 changes: 18 additions & 0 deletions lua/entities/glide_missile/shared.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
AddCSLuaFile()

ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.PrintName = "Missile"

ENT.Spawnable = false
ENT.AdminOnly = false
ENT.VJTag_ID_Danger = true

ENT.PhysgunDisabled = true
ENT.DoNotDuplicate = true
ENT.DisableDuplicator = true

function ENT:SetupDataTables()
self:NetworkVar( "Bool", "HasTarget" )
self:NetworkVar( "Float", "Effectiveness" )
end
1 change: 0 additions & 1 deletion lua/entities/glide_missile_launcher.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ function ENT:Think()
missile.radius = self.explosionRadius
missile.damage = self.explosionDamage
missile.lifeTime = t + self.missileLifetime
missile.acceleration = 20000
end

self:NextThink( t )
Expand Down
2 changes: 1 addition & 1 deletion lua/weapons/glide_homing_launcher.lua
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ function SWEP:PrimaryAttack()
missile:Spawn()
missile:SetupMissile( user, user )
missile.lifeTime = CurTime() + 10
missile.turnEfficiency = 9
missile.turnRate = 200

local target = self:GetLockTarget()

Expand Down

0 comments on commit e152623

Please sign in to comment.