Hi, I've been told numerous ways to code melee weapons and... I'm just lost, some say ply.TraceHullAttack, and the wiki page for it sucks, I can't find any examples of it on garrysmod.org, they all use simple traces...which doesnt work most of the time unless your target doesn't move...
What method should I use for tracing and can you explain in detail how to use it?
The best way is to actually use util.TraceHull ( [url]http://wiki.garrysmod.com/?title=Util.TraceHull[/url] ). It gives you more control and flexibility over what you want to do.
For a true melee weapon (eg a sword), tracehull is ideal because it can then "slash" persay.
Oh ok, the reason I'm asking is cause on my server I tried using traces to find the entity the player was looking at, but sometimes it didn't apply the damage...
[QUOTE=Andriko1;30331172]Oh ok, the reason I'm asking is cause on my server I tried using traces to find the entity the player was looking at, but sometimes it didn't apply the damage...[/QUOTE]
Depends on the latency between players. Source is notorious for trailing hitboxes. If someone is lagging than their hitbox may not update with where you see the player as.
In my opinion its better to check the dot product of the players view angle to see if they're within a certain "view cone", check the distance, and if they match the aforementioned conditions, apply slash damage with Entity:TakeDamageInfo()
What's wrong with using ply:TraceHullAttack()?
Also =S what is a hull?
Also...how would I deal damage the entity this way? I'm looking at other melee weapons and all they have is a simple line trace and ply:FireBullets()
[QUOTE=Andriko1;30363977]What's wrong with using ply:TraceHullAttack()?
Also =S what is a hull?
Also...how would I deal damage the entity this way? I'm looking at other melee weapons and all they have is a simple line trace and ply:FireBullets()[/QUOTE]
A hull is the bounds of a player or entity.
Say an entity is 32 by 32 by 72 units (like players)
You retrieve the hull by getting one of the bottom corners (I believe the forward left) and the opposite top corner (back right).
You do this by using entity:OBBMins() and entity:OBBMaxs() respectively. (There is also entity:OBBCenter() which gives you the center of the entity)
Using these functions on their own will give you a local vector, that is, a vector that only has magnitude in relation to the entity you are calling it on. To translate these vectors into world coordinates (a world vector), you use entity:LocalToWorld(entity:OBBMins()) and chaning out Mins for Maxs or Center for whichever you are using.
On a player, player:OBBMins() would return Vector(-16.0000, -16.0000, 0.0000)
player:OBBMaxs() would return Vector(16.0000, 16.0000, 72.0000)
Thus constructing the 32 by 32 by 72 box mentioned above.
TraceHullAttack would work fine, iirc it's just a wrapper for a TraceHull and TakeDamageInfo, which is one of the methods suggested above.
Do NOT use ply:FireBullets() in a melee SWEP, it's the lazy way of doing it but unless you create checks for certain things the bullets can shoot through things (like fence props, they have a certain mask that lets bullets through)
To do damage like I was suggesting with TakeDamageInfo, look at this wiki page: [url]http://wiki.garrysmod.com/?title=Entity.TakeDamageInfo[/url]
You construct a DamageInfo object, set its values, then feed the object to entity:TakeDamageInfo()
The function list for the DamageInfo object can be found here: [url]http://wiki.garrysmod.com/?title=CTakeDamageInfo[/url]
I don't remember how to check view angles with the dot product off the top of my head and I can't find any of my code that uses it, but it's simple trigonometry to figure it out (its a quarter to 3 am for me as I'm posting this, so math isn't going to work in my brain right now)
I think I'm gonna use [b][url=http://wiki.garrysmod.com/?title=Player.TraceHullAttack]Player.TraceHullAttack [img]http://wiki.garrysmod.com/favicon.ico[/img][/url][/b], but in the parameters, they ask for vectors(I don't like :( ) about StartPos and EndPos, I'm guessing this is for the trace, does it trace a line or a box or what? Then it has 2 more vectors, sizemin and sizemax...all I want are darn zombie claws what do I do lol
Player:TraceHullAttack( Vector StartPos, Vector EndPos, Vector SizeMin, Vector SizeMax, Integer Damage, Enum DamageType, Float DamageForce, Boolean DamageAnyNPC )
StartPos - startpos of the trace (vector) just like a normal trace
EndPos - endpos of the trace (vector) just like a normal trace
SizeMin - lower bound of the tracehull (vector)
SizeMax - upper bound of the tracehull (vector)
iirc it traces along the entire hull (the box) and returns the first thing that is found by it.
I don't get it lol, how would I set it up for simple zombie claws melee
Something like this
[lua]
local startpos = self.Owner:GetShootPos()
local endpos = startpos + self.Owner:GetAimVector() * 75
local minbox = Vector(-10,-10,-10)
local maxbox = Vector(10,10,10)
local damage = 15
local dtype = DMG_SLASH
local dforce = 5
local damageall = true
self.Owner:TraceHullAttack(startpos, endpos, minbox, maxbox, damage, dtype, dforce, damageall)
[/lua]
Separated all arguments into variables for ease of reading.
Untested, so you may have to adjust the bounding box.
Is ply:GetAimVector() the center of the screen where the player is aiming? why did you multiply it by 75? Sorry I'm new to sweps and this is really hard to visualize, especially the minbox and maxbox stuff...
Ok... is this ok for the SWEP:PrimaryAttack()?
[lua]
function SWEP:PrimaryAttack()
if ( self.ShootafterTakeout > CurTime() ) then return end
self.Weapon:SetNextPrimaryFire( CurTime() + .4 )
local ply = self.Owner
local pos = ply:GetPos()
local ang = ply:GetAimVector()
local phtr = ply:GetEyeTrace()
local trace = util.TraceHull( tracedata )
local tr = util.TraceLine(trace)
local ph = phtr.Entity:GetPhysicsObject()
if (ply:GetPos() - tr.HitPos):Length() < 100 then
if tr.Entity:IsPlayer() or string.find(tr.Entity:GetClass(),"npc") or string.find(tr.Entity:GetClass(),"prop_ragdoll") or tr.Entity.MatType == "MAT_GLASS" then
if self.hit == 1 then
self.Weapon:EmitSound( self.FleshHit1 )
self.hit = 2
elseif self.hit == 2 then
self.Weapon:EmitSound( self.FleshHit2 )
self.hit = 3
elseif self.hit == 3 then
self.Weapon:EmitSound( self.FleshHit3 )
self.hit = 4
else
self.Weapon:EmitSound( self.FleshHit4 )
self.hit = 1
end
ply:SetAnimation( PLAYER_ATTACK1 );
self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK );
local startpos = self.Owner:GetShootPos()
local endpos = startpos + self.Owner:GetAimVector() * 75
local minbox = Vector(-10,-10,-10)
local maxbox = Vector(10,10,10)
local damage = 15
local dtype = DMG_SLASH
local dforce = 5
local damageall = true
self.Owner:TraceHullAttack(startpos, endpos, minbox, maxbox, damage, dtype, dforce, damageall)
else
util.Decal("ManhackCut", tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
self.Weapon:EmitSound(self.WallSound,100,math.random(95,110))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
if not tr.HitWorld and not string.find(tr.Entity:GetClass(),"prop_static") then
if SERVER then ph:ApplyForceCenter(self.Owner:GetAimVector()*5000) end
end
end
else
self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
end
self.Owner:SetAnimation( PLAYER_ATTACK1 ) --3rd Person Animation
end
[/lua]
Haven't tested yet... 1am...going to bed lol
Thinking of instead of tracing 2 things maybe just use ply.TraceHullAttack() somehow to detect what material it's attacking...tomorrow xD.... oh and... how would I get the return value of this?
GetShootPos returns the position between the eyes of a player - so yes, where you are looking.
If you use that and add the players aim vector, you get the direction their looking.
You multiply it by 75 to get the distance of the trance that you would like. 75 was just an example, it can be anything really.
It's not giving errors and not causing damage or any sort of hit against any surface
Bump, still can't figure out what's wrong
Try grabbing the value from the TraceHullAttack, on the wiki it says it returns an entity
do
[lua]
local hitEnt = self.Owner:TraceHullAttack(startpos, endpos, minbox, maxbox, damage, dtype, dforce, damageall)
print("Hull Attack Hit: " .. tostring(hitEnt))
[/lua]
If it's even being called it'll print something, if you get no print then your If statement is mesed up, if it prints "Hull Attack Hit: nil" then you have a problem with what you are passing to the TraceHullAttack. That's my best guess, it looks alright just looking at it.
Does TraceHullAttack() make the player do any animations, or leave decals on the ground?
[QUOTE=Andriko1;30473041]Does TraceHullAttack() make the player do any animations, or leave decals on the ground?[/QUOTE]
Nope to the animations. I think it depends on the damage type for the decals.
It doesn't do either. All it does is a util.TraceHull and Entity:TakeDamageInfo, you have to call the animation you want to use and draw the decals yourself.
[lua]
function SWEP:PrimaryAttack()
if ( self.ShootafterTakeout > CurTime() ) then return end
self.Weapon:SetNextPrimaryFire( CurTime() + .5 )
local phtr = self.Owner:GetEyeTrace()
local ph = phtr.Entity:GetPhysicsObject()
local startpos = self.Owner:GetShootPos()
local endpos = startpos + self.Owner:GetAimVector() * 100
local minbox = Vector(-10,-10,-10)
local maxbox = Vector(10,10,10)
local damage = 15
local dtype = DMG_SLASH
local dforce = 50
local damageall = true
local tr = self.Owner:TraceHullAttack(startpos, endpos, minbox, maxbox, damage, dtype, dforce, damageall)
if ValidEntity( tr ) then
if tr:IsPlayer() or tr:IsBot() or string.find(tr:GetClass(),"npc") or string.find(tr:GetClass(),"prop_ragdoll") or tr.MatType == "MAT_GLASS" then
if self.hit == 1 then
self.Weapon:EmitSound( self.FleshHit1 )
self.hit = 2
elseif self.hit == 2 then
self.Weapon:EmitSound( self.FleshHit2 )
self.hit = 3
elseif self.hit == 3 then
self.Weapon:EmitSound( self.FleshHit3 )
self.hit = 4
else
self.Weapon:EmitSound( self.FleshHit4 )
self.hit = 1
end
self.Owner:SetAnimation( PLAYER_ATTACK1 );
self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK );
else
self.Weapon:EmitSound(self.WallSound,100,math.random(95,110))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
end
else
self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
end
self.Owner:SetAnimation( PLAYER_ATTACK1 ) --3rd Person Animation
end
[/lua]
Ok... I tried editing it a bit, now it does the damage, but for some reason tracehullattack returns null and no sounds or decals are played/made at all
Thinking of switching to util.TraceHull() and Entity.TakeDamageInfo()
EDIT: Ok, now I'm using TraceHull() and Entity.TakeDamageInfo()
[lua]
function SWEP:PrimaryAttack()
if ( self.ShootafterTakeout > CurTime() ) then return end
self.Weapon:SetNextPrimaryFire( CurTime() + .5 )
local ply = self.Owner
local pos = ply:GetPos()
local ang = ply:GetAimVector()
local tracedata = {}
tracedata.start = pos
tracedata.endpos = pos + ( ang * 100 )
tracedata.filter = ply
tracedata.mins = ply:OBBMins()
tracedata.maxs = ply:OBBMaxs()
local tr = util.TraceHull( tracedata )
local phtr = self.Owner:GetEyeTrace()
local ph = phtr.Entity:GetPhysicsObject()
if (self.Owner:GetPos() - tr.HitPos):Length() < 100 then
if tr.Entity:IsPlayer() or tr.Entity:IsNPC() or string.find(tr.Entity:GetClass(),"prop_ragdoll") or tr.Entity.MatType == "MAT_GLASS" then
if self.hit == 1 then
self.Weapon:EmitSound( self.FleshHit1 )
self.hit = 2
elseif self.hit == 2 then
self.Weapon:EmitSound( self.FleshHit2 )
self.hit = 3
elseif self.hit == 3 then
self.Weapon:EmitSound( self.FleshHit3 )
self.hit = 4
else
self.Weapon:EmitSound( self.FleshHit4 )
self.hit = 1
end
self.Owner:SetAnimation( PLAYER_ATTACK1 );
self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK );
local dmginfo = DamageInfo()
dmginfo:SetDamage( 25 ) --25 damage
dmginfo:SetDamageType( DMG_SLASH ) --Bullet damage
dmginfo:SetAttacker( self.Owner )
dmginfo:SetDamageForce( ply:GetAimVector()*5000 )
tr.Entity:TakeDamageInfo( dmginfo ) --Take damage!
else
util.Decal("ManhackCut", tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
self.Weapon:EmitSound(self.WallSound,100,math.random(95,110))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
if not tr.HitWorld and not string.find(tr.Entity:GetClass(),"prop_static") then
if SERVER then ph:ApplyForceCenter(ply:GetAimVector()*5000) end
end
end
else
self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
end
self.Owner:SetAnimation( PLAYER_ATTACK1 ) --3rd Person Animation
end
[/lua]
I can only get damage to be dealt while in a crouching position and looking slightly up at the target while next to it... also the decals aren't placed... and I got an error message saying TraceHullAttack() was null, the line was on the only line with TraceHullAttack()
[QUOTE=Andriko1;30481888]snip
I can only get damage to be dealt while in a crouching position and looking slightly up at the target while next to it... also the decals aren't placed... and I got an error message saying TraceHullAttack() was null, the line was on the only line with TraceHullAttack()[/QUOTE]
The first problem is because starting the trace in the wrong position: a player’s GetPos() returns the location of their feet. The method you’re looking for is GetShootPos.
[lua]
function SWEP:PrimaryAttack()
if ( self.ShootafterTakeout > CurTime() ) then return end
self.Weapon:SetNextPrimaryFire( CurTime() + .5 )
local ply = self.Owner
local pos = ply:GetShootPos()
local ang = ply:GetAimVector()
local tracedata = {}
tracedata.start = pos
tracedata.endpos = pos + ( ang * 100 )
tracedata.mask = MASK_PLAYERSOLID
tracedata.filter = ply
tracedata.mins = ply:OBBMins()
tracedata.maxs = ply:OBBMaxs()
local tr = util.TraceHull( tracedata )
local phtr = self.Owner:GetEyeTrace()
local ph = phtr.Entity:GetPhysicsObject()
if (self.Owner:GetShootPos() - tr.HitPos):Length() < 100 then
if !tr.Entity and !tr.Entity:IsValid() and !tr.HitWorld and !string.find(tr.Entity:GetClass(),"prop_static") then return false end
if tr.Entity:IsPlayer() or tr.Entity:IsNPC() or string.find(tr.Entity:GetClass(),"prop_ragdoll") or tr.Entity.MatType == "MAT_GLASS" then
if self.hit == 1 then
self.Weapon:EmitSound( self.FleshHit1 )
self.hit = 2
elseif self.hit == 2 then
self.Weapon:EmitSound( self.FleshHit2 )
self.hit = 3
elseif self.hit == 3 then
self.Weapon:EmitSound( self.FleshHit3 )
self.hit = 4
else
self.Weapon:EmitSound( self.FleshHit4 )
self.hit = 1
end
self.Owner:SetAnimation( PLAYER_ATTACK1 );
self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK );
local dmginfo = DamageInfo()
dmginfo:SetDamage( 25 ) --25 damage
dmginfo:SetDamageType( DMG_SLASH ) --Slash damage
dmginfo:SetAttacker( self.Owner )
dmginfo:SetDamageForce( ang*5000 )
tr.Entity:TakeDamageInfo( dmginfo ) --Take damage!
else
util.Decal("ManhackCut", tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
self.Weapon:EmitSound(self.WallSound,100,math.random(95,110))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
if not tr.HitWorld and not string.find(tr.Entity:GetClass(),"prop_static") then
if SERVER then ph:ApplyForceCenter(ang*5000) end
end
end
else
self.Weapon:EmitSound(self.MissSound,100,math.random(90,120))
self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
end
self.Owner:SetAnimation( PLAYER_ATTACK1 ) --3rd Person Animation
end
[/lua]
OK I changed it to GetShootPos() and the tracing looks ok now...except for this one weird thing where if the target is up against a wall or near walls or something, like under the ramp across from spawn next to that garage like thing linking to the dark and light room in gm_construct, it seems to be thinking it's hitting the wall again, unless I crouch and hit the player looking up
EDIT: Also there's the same errors, TakeDamageInfo() being nil/null or whatever, and the entity being handled by the trace being null
Ok I recoded everything and got it to work, but for some reason the console is saying this whenever I hit a player/bot/npc/stuff that takes damage: [weapons\zc_banshee\shared.lua:141] attempt to call method 'TakeDamageInfo' (a nil value)
Other than that everything is working fine
[QUOTE=Andriko1;30508693]Ok I recoded everything and got it to work, but for some reason the console is saying this whenever I hit a player/bot/npc/stuff that takes damage: [weapons\zc_banshee\shared.lua:141] attempt to call method 'TakeDamageInfo' (a nil value)
Other than that everything is working fine[/QUOTE]
Make sure you're only calling it on the server. You're probably getting a client error because TakeDamageInfo is server only.
Lol how do you have like all the answers, are you a wizard? [url]http://www.myfacewhen.com/90/[/url]
Thanks! testing...
[QUOTE=Andriko1;30513393]Lol how do you have like all the answers, are you a wizard? [url]http://www.myfacewhen.com/90/[/url]
Thanks! testing...[/QUOTE]
Cause I've been doing this for 5 years and know the silly little mistakes people can make (including myself)
Sorry, you need to Log In to post a reply to this thread.