Delay in bullet impact.

Is there a way to make it where a “shot” is fired only at a certain point in a weapon’s animation? I’m trying to make some melee SWEPs, but it’s odd how the weapon hits a surface before the animation is at the right frame where it looks like it’s hitting something.

You could use a timer.Simple where the ShootBullets function is called with some math to determine a reasonable delay for impact depending on the distance of the trace.

Sorry, I’m not all that familiar with how to implement this in my lua. Here’s a snippet of the PrimaryAttack function:


function SWEP:PrimaryAttack()

	local tr = {}
	tr.start = self.Owner:GetShootPos()
	tr.endpos = self.Owner:GetShootPos() + ( self.Owner:GetAimVector() * 85 )
	tr.filter = self.Owner
	tr.mask = MASK_SHOT
	local trace = util.TraceLine( tr )

self:DoIdle(1)

self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
	self.Owner:SetAnimation( PLAYER_ATTACK1 )

	if ( trace.Hit ) then

	if (trace.Hit) and (trace.Entity:IsWorld()) then
	util.Decal("ManhackCut", trace.HitPos + trace.HitNormal, trace.HitPos - trace.HitNormal)
	self:EmitSound("Weapon_Knife.HitWall")
	local effectdata = EffectData()
	effectdata:SetOrigin(trace.HitPos)
	effectdata:SetEntity(self.Owner:GetViewModel())
	effectdata:SetStart(trace.HitPos)
	effectdata:SetNormal(trace.HitNormal)
	effectdata:SetScale( 1.5 )
	effectdata:SetRadius( 0.9 )
	effectdata:SetMagnitude( 0.6 )
	util.Effect( "Sparks", effectdata )	
	end

		if trace.Entity:IsPlayer() or string.find(trace.Entity:GetClass(),"npc") or string.find(trace.Entity:GetClass(),"prop_ragdoll") then
			self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
			bullet = {}
			bullet.Num    = 1
			bullet.Src    = self.Owner:GetShootPos()
			bullet.Dir    = self.Owner:GetAimVector()
			bullet.Spread = Vector(0, 0, 0)
			bullet.Tracer = 0
			bullet.Force  = 10
			bullet.Damage = 35
			self.Owner:FireBullets(bullet) 
			self.Weapon:EmitSound( "weapons/knife/knife_hit" .. math.random(1, 4) .. ".wav" )
		else
			self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
			bullet = {}
			bullet.Num    = 1
			bullet.Src    = self.Owner:GetShootPos()
			bullet.Dir    = self.Owner:GetAimVector()
			bullet.Spread = Vector(0, 0, 0)
			bullet.Tracer = 0
			bullet.Force  = 10
			bullet.Damage = 35
			self.Owner:FireBullets(bullet) 
			self.Weapon:EmitSound(self.WallSound,100,math.random(90,120))		
			util.Decal("ManhackCut", trace.HitPos + trace.HitNormal, trace.HitPos - trace.HitNormal)
		end
	else
		self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
		self.Weapon:SendWeaponAnim(ACT_VM_MISSCENTER)
self.Weapon:SetNextSecondaryFire(CurTime() + 0.8)
	end
end

Try this:


function SWEP:PrimaryAttack()
   timer.Simple(0.5,function()
	local tr = {}
	tr.start = self.Owner:GetShootPos()
	tr.endpos = self.Owner:GetShootPos() + ( self.Owner:GetAimVector() * 85 )
	tr.filter = self.Owner
	tr.mask = MASK_SHOT
	local trace = util.TraceLine( tr )
end)
self:DoIdle(1)

self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
	self.Owner:SetAnimation( PLAYER_ATTACK1 )

	if ( trace.Hit ) then

	if (trace.Hit) and (trace.Entity:IsWorld()) then
	util.Decal("ManhackCut", trace.HitPos + trace.HitNormal, trace.HitPos - trace.HitNormal)
	self:EmitSound("Weapon_Knife.HitWall")
	local effectdata = EffectData()
	effectdata:SetOrigin(trace.HitPos)
	effectdata:SetEntity(self.Owner:GetViewModel())
	effectdata:SetStart(trace.HitPos)
	effectdata:SetNormal(trace.HitNormal)
	effectdata:SetScale( 1.5 )
	effectdata:SetRadius( 0.9 )
	effectdata:SetMagnitude( 0.6 )
	util.Effect( "Sparks", effectdata )	
	end

		if trace.Entity:IsPlayer() or string.find(trace.Entity:GetClass(),"npc") or string.find(trace.Entity:GetClass(),"prop_ragdoll") then
			self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
			bullet = {}
			bullet.Num    = 1
			bullet.Src    = self.Owner:GetShootPos()
			bullet.Dir    = self.Owner:GetAimVector()
			bullet.Spread = Vector(0, 0, 0)
			bullet.Tracer = 0
			bullet.Force  = 10
			bullet.Damage = 35
			self.Owner:FireBullets(bullet) 
			self.Weapon:EmitSound( "weapons/knife/knife_hit" .. math.random(1, 4) .. ".wav" )
		else
			self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
			bullet = {}
			bullet.Num    = 1
			bullet.Src    = self.Owner:GetShootPos()
			bullet.Dir    = self.Owner:GetAimVector()
			bullet.Spread = Vector(0, 0, 0)
			bullet.Tracer = 0
			bullet.Force  = 10
			bullet.Damage = 35
			self.Owner:FireBullets(bullet) 
			self.Weapon:EmitSound(self.WallSound,100,math.random(90,120))		
			util.Decal("ManhackCut", trace.HitPos + trace.HitNormal, trace.HitPos - trace.HitNormal)
		end
	else
		self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
		self.Weapon:SendWeaponAnim(ACT_VM_MISSCENTER)
self.Weapon:SetNextSecondaryFire(CurTime() + 0.8)
	end
end

Fortune,

Now it’s saying “attempt to index global ‘trace’ (a nil value).”

The line it points out is the “if ( trace.Hit ) then” statement.

Woops hang on, replace this:


 timer.Simple(0.5,function()
	local tr = {}
	tr.start = self.Owner:GetShootPos()
	tr.endpos = self.Owner:GetShootPos() + ( self.Owner:GetAimVector() * 85 )
	tr.filter = self.Owner
	tr.mask = MASK_SHOT
	local trace = util.TraceLine( tr )
end)

With this:


timer.Simple(0.5,function()
	local tr = {}
	tr.start = self.Owner:GetShootPos()
	tr.endpos = self.Owner:GetShootPos() + ( self.Owner:GetAimVector() * 85 )
	tr.filter = self.Owner
	tr.mask = MASK_SHOT
	trace = util.TraceLine( tr )
end)

I forgot that it would become local to the timer, that should fix it.

That won’t help. Give me a moment, I’ll fix it up.

Edited: Give this a whirl.

[lua]

local hitdelay = 0.5-- Edit this variable to your liking

function SWEP:PrimaryAttack()
local tr = {}
tr.start = self.Owner:GetShootPos()
tr.endpos = self.Owner:GetShootPos() + ( self.Owner:GetAimVector() * 85 )
tr.filter = self.Owner
tr.mask = MASK_SHOT
local trace = util.TraceLine( tr )

self:DoIdle(1)


self.Weapon:SetNextSecondaryFire(CurTime() + 0.5)
self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
self.Owner:SetAnimation( PLAYER_ATTACK1 )

self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
-- Woosh sound no matter what

if ( trace.Hit ) then
	if (trace.Entity:IsWorld()) then
		util.Decal("ManhackCut", trace.HitPos + trace.HitNormal, trace.HitPos - trace.HitNormal)
		self:EmitSound("Weapon_Knife.HitWall")
		local effectdata = EffectData()
		effectdata:SetOrigin(trace.HitPos)
		effectdata:SetEntity(self.Owner:GetViewModel())
		effectdata:SetStart(trace.HitPos)
		effectdata:SetNormal(trace.HitNormal)
		effectdata:SetScale( 1.5 )
		effectdata:SetRadius( 0.9 )
		effectdata:SetMagnitude( 0.6 )
		
		timer.Simple(hitdelay, function()
			util.Effect( "Sparks", effectdata )	
		end)
	elseif trace.Entity:IsPlayer() or string.find(trace.Entity:GetClass(),"npc") or string.find(trace.Entity:GetClass(),"prop_ragdoll") then
		self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
		bullet = {}
		bullet.Num    = 1
		bullet.Src    = self.Owner:GetShootPos()
		bullet.Dir    = self.Owner:GetAimVector()
		bullet.Spread = Vector(0, 0, 0)
		bullet.Tracer = 0
		bullet.Force  = 10
		bullet.Damage = 35
		
		local wep = self.Weapon
		local own = self.Owner
		
		timer.Simple(hitdelay, function()
			if (!wep or !own or !own:IsValid() or !wep:IsValid()) then return end
		
			own:FireBullets(bullet) 
			wep:EmitSound( "weapons/knife/knife_hit" .. math.random(1, 4) .. ".wav" )
		end)
	else
		self.Weapon:SendWeaponAnim(ACT_VM_HITCENTER)
		bullet = {}
		bullet.Num    = 1
		bullet.Src    = self.Owner:GetShootPos()
		bullet.Dir    = self.Owner:GetAimVector()
		bullet.Spread = Vector(0, 0, 0)
		bullet.Tracer = 0
		bullet.Force  = 10
		bullet.Damage = 35
		
		local wep = self.Weapon
		local own = self.Owner
		
		timer.Simple(hitdelay, function()
			if (!wep or !own or !own:IsValid() or !wep:IsValid()) then return end
			
			own:FireBullets(bullet) 
			wep:EmitSound(self.WallSound,100,math.random(90,120))		
			util.Decal("ManhackCut", trace.HitPos + trace.HitNormal, trace.HitPos - trace.HitNormal)
		end)
	end
else
	self.Weapon:SendWeaponAnim(ACT_VM_MISSCENTER)
	self.Weapon:SetNextSecondaryFire(CurTime() + 0.8)
end

end[/lua]

KingofBeast, it works excellently! Thanks a bunch for your help. The only remaining problem now is that for some reason when I strike the world, the weapon doesn’t go through an animation at all.

EDIT: Also, I have noticed that in order to actually hit someone, you have to be in range, no matter how long the delay is. Is it possible to make it where the weapon only detects the distance between you and the enemy when the delay is over?

What about delay based on how far what you are shooting is? That would be cool.