Bullet Trails
Seconal
Join Date: 2012-02-24 Member: 147354Members
<div class="IPBDescription">Simulate trails for hitscan weapons</div>Here's a visual...
Without the bullet tracer:
<img src="http://img.gistifi.com/ns2-bullettrail2.jpg" border="0" class="linked-image" />
With the bullet tracer:
<img src="http://img.gistifi.com/ns2-bullettrail3.jpg" border="0" class="linked-image" />
Without the bullet tracer:
<img src="http://img.gistifi.com/ns2-bullettrail2.jpg" border="0" class="linked-image" />
With the bullet tracer:
<img src="http://img.gistifi.com/ns2-bullettrail3.jpg" border="0" class="linked-image" />
Comments
(and they obviously arn't shown every shot, because they shouldn't be on every bullet anyway.)
sounds like a bug in the calculations, any lua fluent scripter looking at that right now?
Edit: Unfortunately, I'm only fluent in C/C++ and some Java and Python. Hopefully, I will spend a bit of time enough learning Lua to take a further in-depth look into this non-issue.
By default the tracer has a 30% chance to draw with a set limit:
<i>TracerMixin.lua:</i>
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// Limiting the number of tracers fired will decrease the amount of network traffic required.
local kTracerNumberWrapAround = 250<!--c2--></div><!--ec2-->
<i>Pistol.lua:</i>
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Pistol:OnCreate()
ClipWeapon.OnCreate(self)
InitMixin(self, TracerMixin, { kTracerPercentage = 0.3 }) // Changed this to 1 for 100%
InitMixin(self, PickupableWeaponMixin)
InitMixin(self, LaserMixin)
self.altMode = false
self.emptyPoseParam = 0
self.timeLastShot = 0
end<!--c2--></div><!--ec2-->
It seem as though making a slight change to the cinematic file has fixed the tracers:
<img src="http://img.gistifi.com/FixedTracer.png" border="0" class="linked-image" />
The following file: <a href="http://tmp.gistifi.com/tracer.zip" target="_blank"><i>Tracer.zip</i></a> can be unzipped into the following directory:
<i>C:\[Program Files (x86) or Program Files]\Steam\steamapps\common\natural selection 2\ns2\cinematics\marine</i>
This is how the client defines the tracer along with the pistol clip-weapon weapon:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Client.lua <- Tracer_Client.lua
^
|
Shared.lua <- Pistol.lua <- TracerMixin.lua
^
|
ClipWeapon.lua <- Weapon.lua<!--c2--></div><!--ec2-->
From the ClipWeapon.lua:
<b>ClipWeapon</b> which is a parent of <b>Pistol</b> handles a state in which a weapon can fire and calls
the <b>FireBullets</b> function. In this function, it checks if the Tracer Mixin is defined within it's child <b>Pistol</b> and then calls TriggerTracer():
<i>ClipWeapon.lua</i>
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> if Server and HasMixin(self, "Tracer") then
self:TriggerTracer(trace.endPoint)
end<!--c2--></div><!--ec2-->
From the TracerMixin.lua:
The TracerMixin.lua holds of number of tracers to be fired based on a percentage.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function TracerMixin:TriggerTracer(endPoint)
assert(Client == nil)
local randomProvider = self:GetMixinConstants().kRandomProvider
local randomNumber = (randomProvider and randomProvider()) or math.random()
if randomNumber < self:GetMixinConstants().kTracerPercentage then
self.tracerEndPoint = endPoint
self.numberTracersFired = self.numberTracersFired + 1
if self.numberTracersFired > kTracerNumberWrapAround then
self.numberTracersFired = 0
end
end
end
AddFunctionContract(TracerMixin.TriggerTracer, { Arguments = { "Entity", "Vector" }, Returns = { } })<!--c2--></div><!--ec2-->
Then calls the <b>CreateTracer</b> function <b>onUpdateRender</b> time:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function TracerMixin:OnUpdateRender()
assert(Server == nil)
if self.oldNumberTracersFired ~= self.numberTracersFired then
local tracerStart = self:GetBarrelPoint()
local tracerVelocity = GetNormalizedVector(self.tracerEndPoint - tracerStart) * kTracerSpeed
CreateTracer(tracerStart, self.tracerEndPoint, tracerVelocity)
self.oldNumberTracersFired = self.numberTracersFired
end
end
AddFunctionContract(TracerMixin.OnUpdateRender, { Arguments = { "Entity" }, Returns = { } })<!--c2--></div><!--ec2-->
This function then calls <b>CreateTracer</b> defined in Client.lua.
From Client.lua:
The client initializes a single tracer and stores that in the tracersList table defined in Client.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function CreateTracer(startPoint, endPoint, velocity)
if not Shared.GetIsRunningPrediction() then
local tracer = BuildTracer(startPoint, endPoint, velocity)
table.insert(Client.tracersList, tracer)
end
end<!--c2--></div><!--ec2-->
The <b>BuildTracers</b> function that was called is defined in Tracer_Client.lua.
From Tracer_Client.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function BuildTracer(startPoint, endPoint, velocity)
local tracer = Tracer()
tracer.tracerEffect = Client.CreateCinematic(RenderScene.Zone_Default)
tracer.tracerEffect:SetCinematic(Tracer.kTracerEffect)
tracer.tracerEffect:SetRepeatStyle(Cinematic.Repeat_Endless)
tracer.velocity = Vector(0, 0, 0)
VectorCopy(velocity, tracer.velocity)
tracer.startPoint = Vector(0, 0, 0)
VectorCopy(startPoint, tracer.startPoint)
// Calculate how long we should live so we can animate to that target
tracer.lifetime = (endPoint - startPoint):GetLength() / velocity:GetLength()
tracer.timePassed = 0
return tracer
end<!--c2--></div><!--ec2-->
This is the beautiful part, the class <b>'Tracer'</b> is defined in this file, which precaches the "<b>tracer.cinematic</b>" emitter:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->class 'Tracer'
Tracer.kMapName = "tracer"
Tracer.kTracerEffect = PrecacheAsset("cinematics/marine/tracer.cinematic")<!--c2--></div><!--ec2-->
The Client_Tracer.lua also handles the how the cinematic is played.
The client handles the drawing of this tracer and the list of tracers. As defined in TracerMixin.lua, the server just knows what the rate each client is shooting out tracers based on a percentage, which then stores each tracer in the clients tracer list. This is done per-weapon so that you should see each weapon that has TracerMixin should store tracers into your clients tracerlist and render them on screen (client-sided).