Modifying view angles on shoot?
Hey, I've been trying to simulate weapon recoil by adding some pitch and yaw to the view angles when a weapon is fired, but I've had no luck so far. I'm not sure how to add to the view angles correctly. All my attempts have just led to a mass of console errors. If someone could give me a few hints I'd appreciate it. I should really do more lua tutorials but it's much more fun to get changes working in-game.
Comments
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->currentpitch = player:GetViewAngles().pitch
Client.SetPitch(currentpitch + 0.5)<!--c2--></div><!--ec2-->
Although the recoil seems to accumulate so after the first few bullets the gun is always going to the max pitch. I don't know why.
I'm also getting this error in console: attempt to index global 'Client' (a nil value)
I assume that means Client hasn't been defined yet, but I don't understand why the SetPitch() function is still working then.
I guess I will have to create a function to add the recoil somewhere else (where client is not a nil value) and then only call it at the end of FireBullets(). I don't know where the best place to create that function is though.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->currentpitch = player:GetViewAngles().pitch
Client.SetPitch(currentpitch + 0.5)<!--c2--></div><!--ec2-->
Although the recoil seems to accumulate so after the first few bullets the gun is always going to the max pitch. I don't know why.
I'm also getting this error in console: attempt to index global 'Client' (a nil value)
I assume that means Client hasn't been defined yet, but I don't understand why the SetPitch() function is still working then.
I guess I will have to create a function to add the recoil somewhere else (where client is not a nil value) and then only call it at the end of FireBullets(). I don't know where the best place to create that function is though.<!--QuoteEnd--></div><!--QuoteEEnd-->
The nil is because that code is being executed on the server as well. You could add "if Client" before it.
The recoil is in fact not accumulating, but it has a weird behaviour. It works fine if the crosshair is below the horizon (90degrees straight out from the player) by changing the pitch by a small amount. Yet if you look above the horizon then fire, the pitch is instantly changed to look directly down at the floor.
I'm not sure of the exact output of the function GetViewAngles(), I tried to get it to print to the hud so I could debug it but I've had no luck so far.
[EDIT] I got it to print the viewangles to console. I still don't understand though. I can add to the yaw fine and it works as you would expect, but the pitch seems to reset when I try to add anything to it when it is above the horizon.
The values for pitch seem to go from 0 - 1.57 (0 at the horizon and 1.57 looking straight down) and 6.28 - 4.71 (6.28 is looking very slightly above the horizon and 4.71 is looking directly up.)
I would have thought that just setting the pitch to the current pitch - 0.5 would make the gun always go up, but it doesn't. Once you go above the horizon it seems to reset and when you fire the gun it just points directly towards the floor.
In the console it prints the pitch when -0.02 recoil is applied like so: 0.08, 0.06, 0.04, 0.00, 6.26, 1.57
I don't understand why it goes to 1.57 instead of continuing to move up.
If the developers have decided to make the horizon 0 pi that's fine.
2 cases:
(Current = below horizon) you want to go closer to 0 which means subtracting from your current (which is betwn 0 and pi/2)
(Current = above horizon) you want to go closer to 3pi/2 which means subtracting from your current (which is betwn 2pi and 3pi/2)
This isn't conventional spherical coordinates: theta should start from 'up' which UWE has called 'y'.
Either way, there are a handful of ways to solve this problem. You could also handle the 2 cases. I'm interested in seeing the 'correct' solution to this problem as well.
I don't know how to handle the 2 cases since I have no idea how to add recoil when the pitch is above the horizon.
So what you are doing is right, just when you go negative, add 2pi to it and you'll be A-OK as far as I can tell.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->client.pitch -= shake
if client.pitch < 0 then
client.pitch += math.pi * 2
end<!--c2--></div><!--ec2-->
I think your diagram is incorrect at least according to what I read out from the console. I think this is it:
<img src="http://i.imgur.com/MxWKr.jpg" border="0" class="linked-image" />
The first quadrant is looking between the floor(pi/2) and the horizon(0 or 2pi) and then once you pass the horizon and begin to look up you enter the fourth quadrant with 3pi/2 being your pitch when looking directly up.
I think it is a problem with the Client.SetPitch being limited to the first quadrant. I have tried various other ways of setting the pitch with SetViewAngles or SetCoords, but I've had no success.
[EDIT] I worked it out! <victory dance> You need to use a negative value for Client.SetPitch in order for it to tilt the screen upward.
Client.SetPitch between 0 and 1.57 is down, and between 0 and -1.57 is up.
I guess GetViewAngles().pitch and Client.SetPitch are using different values.
Glad to hear you could get it working. Some games are finicky with angles, and by that I mean some use degrees, some allow negative, some allow >360 degrees.
It would be nice to get some official docs on allowed angles and best practices for mod makers. What I mean is distinctions between aimangles and viewangles for source engine and its analog in NS2, also things like what angles are up/down left/right in the coordinate system and how we should be setting a client's pitch for a clientside and serverside mod.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local currentpitch = player:GetViewAngles().pitch
local currentyaw = player:GetViewAngles().yaw
local pitchup = currentpitch - math.pi*2 // This converts currentpitch so it works with setpitch
local recoilamount = 0.02
if Client then
if currentpitch > math.pi/2 then
Client.SetPitch(pitchup - recoilamount)
else
Client.SetPitch(currentpitch - recoilamount)
end
end<!--c2--></div><!--ec2-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Client.SetPitch(number absPitch)<!--c2--></div><!--ec2-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> if Client.GetOptionBoolean(kInvertedMouseOptionsKey, true) then //make recoil work with inverted mouse
if currentpitch > math.pi/2 then
Client.SetPitch(-pitchup + recoilamount)
else
Client.SetPitch(-currentpitch + recoilamount)
end
else...<!--c2--></div><!--ec2-->
I tried testing absPitch, but I can't get it to work.
I was just showing debug documentation for that function (it was pulled out of NS2.exe). Just thought the "abs" (absolute) part might help understand what the function takes as an argument.
At first I thought it was because I just suddenly added the recoil and that I had to try and smooth it out over 100ms or so. But then I realized that with recoil set to 0 it still has this problem.
I guess a solution might be to use another method of adding to the viewangles rather than SetPitch(), but I don't know how to do that. Any ideas?
local angles = Angles(modPitch, yaw, 0)
Player:SetViewAngles(angles)
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Client.GetLocalPlayer():SetViewAngles(Angles(pitch, yaw, 0))<!--c2--></div><!--ec2-->
Player:SetViewAngles(angles)<!--c2--></div><!--ec2-->
When I put this in ClipWeapon I get, attempt to call method 'SetViewAngles' (a nil value)
[EDIT] Fixed the error, no capital at the start of player. It's the same as below though, no effect.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Client.GetLocalPlayer():SetViewAngles(Angles(pitch, yaw, 0))<!--c2--></div><!--ec2-->
No errors with this but it didn't add to the viewangles no matter what values I used.
(turns out they do, it is referenced in ./Weapons/Marine/Flame.lua)
---
Still, there is always a correct time/place to add recoil/take control of a player's view/movement. IDK when it is. If a dev comes across this thread, please drop some knowledge on us folks. No one (at least not me) wants a shaky jittery screen!
At first I thought it was because I just suddenly added the recoil and that I had to try and smooth it out over 100ms or so. But then I realized that with recoil set to 0 it still has this problem.
I guess a solution might be to use another method of adding to the viewangles rather than SetPitch(), but I don't know how to do that. Any ideas?<!--QuoteEnd--></div><!--QuoteEEnd-->
Hah. That sounds like the problems I had with my first person spectator mod since build 219. I tried everything. I even tried creating a new render camera on every prediction frame to see if it helps and wrote my own prediction code for view angles.
Things I found while doing that:
<ul><li>The reported view angles are totally correct and change every prediction frame.</li><li>The render camera doesn't report changes in view angles during prediction frames, but that doesn't necessarily mean the problem exists there.</li><li>Changing view pitch is 100% smooth, changing view yaw is "jerky". This may be a product of network optimization since many variables are "rounded" (i.e. a few bits cut off) before being networked, but not sure how to fix it.</li><li>The only code changes concerning yaw I found in build 219 were concerning velocity.</li></ul>
Of course, this could be a totally different problem, but I just wanted to give my input in case it's the same issue.
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/qA254-YQdi4"></param><embed src="http://www.youtube.com/v/qA254-YQdi4" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
I still need to try GetOwner or moving some code to the player's class and using SetViewAngles instead.
I took a few days off as I was waiting for 1.0 so I could rely on my code not breaking every week. But tonight I got curious and I was trying to use SetViewAngles() but that just makes your bullets go in a different direction without moving the crosshair. But then I decided to try my old code out and noticed it was different in this build. I can now control the mouse much more while shooting!!
If I set recoil to 0 it is still somewhat jerky though, which does interfere with fast mouse movements. Ideally with the recoil set to 0 it would be identical to normal ns2 mouse movement, as the actual recoil amount should be the only thing effecting the crosshair. It shouldn't be harder to aim just a result of using SetPitch(). I guess I really need some way to add to the current viewangles without ever taking away from them, so if you are moving the mouse quickly in the same direction as the recoil it wouldn't pull your mouse back.
It might be okay as it is currently, I'll need to play with it a bit and see how it goes.
Here is a video with recoil set to 0 in the current build. As you can see when the mouse is static then it works fine, but when you start moving the mouse around then it gets very jerky and erratic.
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/EY0JClBQqRo"></param><embed src="http://www.youtube.com/v/EY0JClBQqRo" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Here is a video with recoil set to 0 in the current build. As you can see when the mouse is static then it works fine, but when you start moving the mouse around then it gets very jerky and erratic.
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/EY0JClBQqRo"></param><embed src="http://www.youtube.com/v/EY0JClBQqRo" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center><!--QuoteEnd--></div><!--QuoteEEnd-->
I had started to try to code a solution but hot-loading isn't working for me. Is it still in the game? Does it still get triggered on a file save or do I need to run a command?
Looking at the recoil are you setting it server or client side? Also from what i saw the yaw is stored in full precision but pitch isnt, which may also be adding to your issue.