Skulk View Rotation
Fluid Core
Join Date: 2007-12-26 Member: 63260Members, Reinforced - Shadow
in Modding
<div class="IPBDescription">Very crude, how to improve it?</div>So I figured I'd finally give a try to get a rotation view for the skulk, as I feel it greatly enhances your wallwalking abilities. I found what I thought I wanted in Skulk_Client.lua. Sure enough, I got the view to rotate, but it is very crude.
Mainly because I haven't changed the movement vectors, and it seems like they aren't tied to camera rotation. What this means, is that when you are standing on a wall, left-right mouse movements becomes up-down, and up-down becomes left-right. W and S works like normally, but A and D give strange results. The view also changes orientation at certain angles, rotation your view almost a full circle while you just looked slightly in one direction. It's really hard to explain, it is right now pretty much unplayable. Anyone here who knows how to to fix it/who have already done it? A quick search didn't give me anything.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 1
Skulk.kCameraRollTiltModifier = 1
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time *
Skulk.kCameraRollSpeedModifier))
end
local gEnableTilt = true
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
if self.wallWalkingNormalCurrent and gEnableTilt then
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallWalkingNormalCoords = BuildCoords(self.wallWalkingNormalCurrent, cameraCoords.zAxis)
local wallWalkingRoll = Angles()
wallWalkingRoll:BuildFromCoords(wallWalkingNormalCoords)
wallWalkingRoll = wallWalkingRoll.roll
self.goalCameraRoll = (wallWalkingRoll * Skulk.kCameraRollTiltModifier)
if self.currentCameraRoll then
viewModelTiltAngles.roll = viewModelTiltAngles.roll + self.currentCameraRoll
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
return cameraCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
Mainly because I haven't changed the movement vectors, and it seems like they aren't tied to camera rotation. What this means, is that when you are standing on a wall, left-right mouse movements becomes up-down, and up-down becomes left-right. W and S works like normally, but A and D give strange results. The view also changes orientation at certain angles, rotation your view almost a full circle while you just looked slightly in one direction. It's really hard to explain, it is right now pretty much unplayable. Anyone here who knows how to to fix it/who have already done it? A quick search didn't give me anything.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 1
Skulk.kCameraRollTiltModifier = 1
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time *
Skulk.kCameraRollSpeedModifier))
end
local gEnableTilt = true
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
if self.wallWalkingNormalCurrent and gEnableTilt then
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallWalkingNormalCoords = BuildCoords(self.wallWalkingNormalCurrent, cameraCoords.zAxis)
local wallWalkingRoll = Angles()
wallWalkingRoll:BuildFromCoords(wallWalkingNormalCoords)
wallWalkingRoll = wallWalkingRoll.roll
self.goalCameraRoll = (wallWalkingRoll * Skulk.kCameraRollTiltModifier)
if self.currentCameraRoll then
viewModelTiltAngles.roll = viewModelTiltAngles.roll + self.currentCameraRoll
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
return cameraCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
Comments
I will have a look tomorrow maybe we can do something.
I compute the angle of the wall (zero is floor, pi is ceiling) and if it's close enough to pi I flip the view upside down. So there is only ceiling walking here, just because it's easy to transform the inputs for it.
Then I use Skulk:OverrideInput(input) to transform the inputs, i.e. change the sign of the yaw and pitch (yaw is looking left-right with the mouse and pitch up and down), I also flip the strafing with input.move.x.
There is a lot of problems with the transitions, because when you change the sign of the input it's like moving the mouse, so you camera can move quite a bit when going on the ceiling.
About the spinning view it's probably an angle flipping from -pi to pi or something, you can print in the console using Print(ToString(self.goalCameraRoll)) and figure out what happens.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 0.5
Skulk.kCameraRollTiltModifier = 0.05
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
//self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time * Skulk.kCameraRollSpeedModifier))
end
function Skulk:OverrideInput(input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(coords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
if math.abs(math.abs(wallAngle)-math.pi) < 1 then
input.pitch = -input.pitch
input.yaw = -input.yaw
input.move.x = -input.move.x
end
//Print(ToString(input.yaw))
end
local gEnableTilt = true
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
//Print(ToString(wallAngle))
if math.abs(math.abs(wallAngle)-math.pi) < 1 then
self.goalCameraRoll = self.goalCameraRoll + 0.04*(math.pi - self.goalCameraRoll)
else
self.goalCameraRoll = self.goalCameraRoll + 0.04*(0 - self.goalCameraRoll)
end
viewModelTiltAngles.roll = self.goalCameraRoll
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
About the spinning view it's probably an angle flipping from -pi to pi or something, you can print in the console using Print(ToString(self.goalCameraRoll)) and figure out what happens.<!--QuoteEnd--></div><!--QuoteEEnd-->
Thanks alot, I'll take a look right away. You are probably right about the spinning, it sounds very reasonable. I suppose the game spin the camera one direction for positive angles and another for negative, instead of spinning in the direction the normal changes. Since this is how it works for all the negative and positive angles respectively, I don't see why there is a different implementation for -pi and pi. If the angle of the normal would increase it should turn the same direction regardless of angle, and for decreasing angle it should turn the other direction. Generally I'm not very fond of negative angles at all :P
<i>Renamed my official Skulk_Client.lua to Skulk_ClientOriginal.txt and named the one you created into the Skulk_Client.lua. When I try to start the game I get a <b>Steam - Warning: Steam was unable to sync your files for Natural Selection 2 with Steam Cloud</b>. I could run it regardless, but when I tried to create a server I got an authentication failed. Trying with the real one right now, but the same thing happend, restarted steam to see where the issue is.</i>
<i>Same thing again, it seems like there's some issue with steam. Taking a look at TF2 to see if it's there too.</i>
<i>It's steam, same thing with TF2. To bad, looked forward to trying it out.</i>
<!--quoteo(post=1888811:date=Dec 6 2011, 11:29 PM:name=Yuuki)--><div class='quotetop'>QUOTE (Yuuki @ Dec 6 2011, 11:29 PM) <a href="index.php?act=findpost&pid=1888811"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec--><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Skulk:OverrideInput(input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(coords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
if math.abs(math.abs(wallAngle)-math.pi) < 1 then
input.pitch = -input.pitch
input.yaw = -input.yaw
input.move.x = -input.move.x
end
//Print(ToString(input.yaw))
end<!--c2--></div><!--ec2--><!--QuoteEnd--></div><!--QuoteEEnd-->
I understand what you are doing there. However, wouldn't a more elegant approach be to turn the input vectors around the Z axis to align with the normal vector of the wall? Something like (can't remember the exact wording in lua, think I saw eighter cross product or scalar product somewhere).
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->input.move.x=math.crossproduct(wallWalkingNormalGoal,math.abs(wallWalkingNormalGoal.z))*input.move.x<!--c2--></div><!--ec2-->
By wallWalkingNormalGoal.z I mean the "forward" vector, it should be the same direction as I made out, but perhaps there's a more clean vector describing it. On second thought, it might just be a scalar instead of a vector, it needs a 0,0,1 directional vector to work as wanted. Standing in the ceiling would make input.move.x = -input.move.x since the y-component of the wallWalkingNormalGoal would be negative. Might have to make a special case for when standing on a vertical surface, as the y-component then is 0.
<!--quoteo(post=1888811:date=Dec 6 2011, 11:29 PM:name=Yuuki)--><div class='quotetop'>QUOTE (Yuuki @ Dec 6 2011, 11:29 PM) <a href="index.php?act=findpost&pid=1888811"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec--><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->local gEnableTilt = true
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
//Print(ToString(wallAngle))
[b]if math.abs(math.abs(wallAngle)-math.pi) < 1 then
self.goalCameraRoll = self.goalCameraRoll + 0.04*(math.pi - self.goalCameraRoll)
else
self.goalCameraRoll = self.goalCameraRoll + 0.04*(0 - self.goalCameraRoll)
end[/b]
viewModelTiltAngles.roll = self.goalCameraRoll
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2--><!--QuoteEnd--></div><!--QuoteEEnd-->
I don't quite get why you made the bold part like that. Since we don't set GoalCameraRoll at another point in the code, they will start out at as 0 in the start:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end<!--c2--></div><!--ec2-->
If I interpreted it correctly, when you are standing on the ceiling (Or well, if the angle -1+pi<abs(wallAngle)<1+pi) then the camera will approach being orientated as pi regardless of the wall angle as you loop the function. If you don't stand on the ceiling then the angle will approach 0. I can understand the choice for the ceiling, might make it less disorientating to have another "mode" for on the ceiling regardless (to an extent) of the angle of it, but won't the walls be strange? You would need to make something similar for them as for the ceiling. Also, why did you choose 0.04?
<i>And just a quick question, in lua, do you write x=1 or 1=x? I assume the former as in for example MATLAB.</i>
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Skulk:OverrideInput(input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(coords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
input.pitch = math.cos(self.wallWalkingNormalGoal.y)*input.yaw+math.sin(self.wallWalkingNormalGoal.y)*input.pitch
input.yaw = math.sin(self.wallWalkingNormalGoal.y)*input.yaw+math.cos(self.wallWalkingNormalGoal.y)*input.pitch
input.move.x = math.sin(self.wallWalkingNormalGoal.y)*input.move.x
input.move.y = math.cos(self.wallWalkingNormalGoal.y)*input.move.x
end
//Print(ToString(input.yaw))
end<!--c2--></div><!--ec2-->
Tried it out. The pitch/yaw modification makes the mouse go absolutely crazy, even when on ground and holding ctrl. The strafing seem to work when you are standing on an overhanging area, and not always in the direction you'd expect. Works fine in the ceiling tho.
I tried it and it kind of work, but there is still a problem that when you move on the wall, then the angle change and the inputs change, which is bad because it's like you moving your mouse but you're not. The result is crazy incontrollable camera movements.
I think we need to transform only the differences and not the whole value.
For example your are on the floor with a yaw of 2, then you strafe on the wall your yaw becomes your pitch, so you look in a different direction. Instead changes in pitch should cause changes in yaw, but not a immediate exchange of the values.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Skulk:OverrideInput(input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(coords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
pitch=input.pitch
yaw=input.yaw
input.pitch = self.wallWalkingNormalGoal.y*yaw+math.sin(wallAngle)*pitch
input.yaw = math.sin(wallAngle)*yaw+self.wallWalkingNormalGoal.y*pitch
moveX=input.move.x
input.move.x = math.sin(wallAngle)*moveX
input.move.y = self.wallWalkingNormalGoal.y*moveX
//Print(ToString(input.yaw))
end<!--c2--></div><!--ec2-->
Have to run of to the uni now, but I'll try it later :)
On the ground, when you pitch, your vision yaws. When you yaw, your vision pitch. Moving forward-backward acts like normal. Strafing moves you forward-backward.
On the wall, pitching and yawing is like you'd normal. So is strafing.
On the ceiling, same pitch and yaw problems as on the ground. Your strafing however, moves you up (towards the floor since the vision is turned) and down towards the ceiling.
Confusing I tell you. I really don't get why it's changed at all on the floor. But I will try to look into it. Probably some minor math fail on my part...
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
pitchy=input.pitch
yawx=input.yaw
input.pitch = math.sin(wallAngle)*yawx+math.cos(wallAngle)*pitchy
input.yaw = math.cos(wallAngle)*yawx+math.sin(wallAngle)*pitchy
moveX=input.move.x
input.move.x = math.cos(wallAngle)*moveX
input.move.y = math.sin(wallAngle)*moveX<!--c2--></div><!--ec2-->
Got it to work now, it moves you in the right direction (or opposite...) on the right plane atleast. On some angles the strafing or pitch/yaw invertes. Probably got to do with negative angles, you can get negative from both pitch and angle.
Oh well. The only good thing is that it does work on public servers. Not that it's usefull now, but if we eventually got one working it would truly be up to personal taste to use it then.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 0.5
Skulk.kCameraRollTiltModifier = 0.05
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
//self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time * Skulk.kCameraRollSpeedModifier))
end
function Skulk:OverrideInput(input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(coords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
pitchy=input.pitch
yawx=input.yaw
moveX=input.move.x
input.move.x = math.cos(wallAngle)*moveX
input.move.y = -math.sin(wallAngle)*moveX
input.pitch = -yawx*math.sin(wallAngle)^2+pitchy*math.cos(wallAngle)^2
input.yaw = yawx*math.cos(wallAngle)^2+pitchy*math.sin(wallAngle)^2
//Print(ToString(input.yaw))
end
local gEnableTilt = true
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
if self.wallWalkingNormalCurrent and gEnableTilt then
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
// Don't rotate if too close to upside down (on ceiling).
if math.abs(self.wallWalkingNormalCurrent:DotProduct(Vector.xAxis)) > 0.05 then
local wallWalkingNormalCoords = BuildCoords(self.wallWalkingNormalCurrent, cameraCoords.zAxis)
local wallWalkingRoll = Angles()
wallWalkingRoll:BuildFromCoords(wallWalkingNormalCoords)
wallWalkingRoll = wallWalkingRoll.roll
self.goalCameraRoll = wallWalkingRoll
else
self.goalCameraRoll = 0
end
if self.currentCameraRoll then
viewModelTiltAngles.roll = viewModelTiltAngles.roll + self.currentCameraRoll
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
return cameraCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 0.5
Skulk.kCameraRollTiltModifier = 0.05
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time *
Skulk.kCameraRollSpeedModifier))
end
local gEnableTilt = true
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
self.pitchy=input.pitch
self.yawx=input.yaw
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
if wallAngle>math.pi/6 AND wallAngle<math.pi*5/6 then
if wallAngle<math.pi/3 OR wallAngle>math.pi*2/3 then
if self.goalCameraRoll=0 OR self.goalCameraRoll=math.pi
//nochange
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-yawx
input.yaw=pitchy
end
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-yawx
input.yaw=pitchy
end
end
if wallAngle<-math.pi/6 AND wallAngle>-math.pi*5/6 then
if wallAngle>-math.pi/3 OR wallAngle<-math.pi*2/3 then
if self.goalCameraRoll=0 OR self.goalCameraRoll=math.pi
//nochange
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=yawx
input.yaw=-pitchy
end
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=yawx
input.yaw=-pitchy
end
end
if math.abs(wallAngle)<math.pi*4/3 AND math.abs(wallAngle)>math.pi*2/3 then
if math.abs(wallAngle)>math.pi*5/6 OR math.abs(wallAngle)<math.pi*5/6 then
if math.abs(self.goalCameraRoll)=math.pi/2
//nochange
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-pitchy
input.yaw=-yawx
end
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-pitchy
input.yaw=-yawx
end
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
return cameraCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 0.5
Skulk.kCameraRollTiltModifier = 0.05
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time *Skulk.kCameraRollSpeedModifier))
end
local gEnableTilt = true
function Skulk:OverrideInput(input)
self.pitchy = input.pitch
self.yawx = input.yaw
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
if (wallAngle > math.pi/6) and (wallAngle < math.pi*5/6) then
if wallAngle<math.pi/3 or wallAngle>math.pi*2/3 then
if (self.goalCameraRoll==0) or self.goalCameraRoll==math.pi then
//nochange
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-yawx
input.yaw=pitchy
end
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-yawx
input.yaw=pitchy
end
end
if wallAngle<-math.pi/6 and wallAngle>-math.pi*5/6 then
if wallAngle>-math.pi/3 or wallAngle<-math.pi*2/3 then
if self.goalCameraRoll==0 or self.goalCameraRoll==math.pi then
//nochange
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=yawx
input.yaw=-pitchy
end
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=yawx
input.yaw=-pitchy
end
end
if math.abs(wallAngle)<math.pi*4/3 and math.abs(wallAngle)>math.pi*2/3 then
if math.abs(wallAngle)>math.pi*5/6 or math.abs(wallAngle)<math.pi*5/6 then
if math.abs(self.goalCameraRoll) == math.pi/2 then
//nochange
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-pitchy
input.yaw=-yawx
end
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-pitchy
input.yaw=-yawx
end
end
end
// Tilt the camera based on the wall the Skulk is attached to.
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords)
if self.wallWalkingNormalCurrent and gEnableTilt then
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallWalkingNormalCoords = BuildCoords(self.wallWalkingNormalCurrent, cameraCoords.zAxis)
local wallWalkingRoll = Angles()
wallWalkingRoll:BuildFromCoords(wallWalkingNormalCoords)
if math.abs(wallWalkingRoll.roll) > 0 then //avoid problems when on ceiling
wallWalkingRoll.roll = math.abs(wallWalkingRoll.roll)
end
wallWalkingRoll = wallWalkingRoll.roll
self.goalCameraRoll = (wallWalkingRoll * Skulk.kCameraRollTiltModifier)
if self.currentCameraRoll then
viewModelTiltAngles.roll = viewModelTiltAngles.roll + self.currentCameraRoll
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
return cameraCoords
end
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// ======= Copyright © 2003-2011, Unknown Worlds Entertainment, Inc. All rights reserved. =======
//
// lua\Skulk_Client.lua
//
// Created by: Brian Cronin (brianc@unknownworlds.com)
//
// ========= For more information, visit us at http://www.unknownworlds.com =====================
Skulk.kCameraRollSpeedModifier = 0.5
Skulk.kCameraRollTiltModifier = 0.05
function Skulk:UpdateMisc(input)
Alien.UpdateMisc(self, input)
if self.currentCameraRoll == nil then
self.currentCameraRoll = 0
end
if self.goalCameraRoll == nil then
self.goalCameraRoll = 0
end
self.currentCameraRoll = LerpGeneric(self.currentCameraRoll, self.goalCameraRoll, math.min(1, input.time *Skulk.kCameraRollSpeedModifier))
end
local gEnableTilt = true
function Skulk:PlayerCameraCoordsAdjustment(cameraCoords, input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
if self.wallWalkingNormalCurrent and gEnableTilt then
if (wallAngle > math.pi/6) and (wallAngle < math.pi*5/6) then
if wallAngle<math.pi/3 or wallAngle>math.pi*2/3 then
if (self.goalCameraRoll==0) or self.goalCameraRoll==math.pi then
//nochange
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-self.yawx
input.yaw=self.pitchy
end
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-self.yawx
input.yaw=self.pitchy
end
end
if wallAngle<-math.pi/6 and wallAngle>-math.pi*5/6 then
if wallAngle>-math.pi/3 or wallAngle<-math.pi*2/3 then
if self.goalCameraRoll==0 or self.goalCameraRoll==math.pi then
//nochange
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=self.yawx
input.yaw=-self.pitchy
end
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=self.yawx
input.yaw=-self.pitchy
end
end
if math.abs(wallAngle)<math.pi*4/3 and math.abs(wallAngle)>math.pi*2/3 then
if math.abs(wallAngle)>math.pi*5/6 or math.abs(wallAngle)<math.pi*5/6 then
if math.abs(self.goalCameraRoll) == math.pi/2 then
//nochange
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-self.pitchy
input.yaw=-self.yawx
end
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-self.pitchy
input.yaw=-self.yawx
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
return cameraCoords
end
// Tilt the camera based on the wall the Skulk is attached to.
function OnCommandSkulkViewTilt(enableTilt)
gEnableTilt = enableTilt ~= "false"
end
Event.Hook("Console_skulk_view_tilt", OnCommandSkulkViewTilt)<!--c2--></div><!--ec2-->
and adding the code below on a random place in Skulk.lua
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Skulk:PlayerCameraCoordsAdjustment(cameraCoords, input)
local coords = self:GetViewCoords()
local viewModelTiltAngles = Angles()
viewModelTiltAngles:BuildFromCoords(cameraCoords)
local wallAngle = math.acos(self.wallWalkingNormalGoal.y)
if self.wallWalkingNormalCurrent and gEnableTilt then
if (wallAngle > math.pi/6) and (wallAngle < math.pi*5/6) then
if wallAngle<math.pi/3 or wallAngle>math.pi*2/3 then
if (self.goalCameraRoll==0) or self.goalCameraRoll==math.pi then
//nochange
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-self.yawx
input.yaw=self.pitchy
end
else
self.goalCameraRoll=math.pi/2
input.move.y=-input.move.x
input.pitch=-self.yawx
input.yaw=self.pitchy
end
end
if wallAngle<-math.pi/6 and wallAngle>-math.pi*5/6 then
if wallAngle>-math.pi/3 or wallAngle<-math.pi*2/3 then
if self.goalCameraRoll==0 or self.goalCameraRoll==math.pi then
//nochange
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=self.yawx
input.yaw=-self.pitchy
end
else
self.goalCameraRoll=-math.pi/2
input.move.y=input.move.x
input.pitch=self.yawx
input.yaw=-self.pitchy
end
end
if math.abs(wallAngle)<math.pi*4/3 and math.abs(wallAngle)>math.pi*2/3 then
if math.abs(wallAngle)>math.pi*5/6 or math.abs(wallAngle)<math.pi*5/6 then
if math.abs(self.goalCameraRoll) == math.pi/2 then
//nochange
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-self.pitchy
input.yaw=-self.yawx
end
else
self.goalCameraRoll=math.pi
input.move.x=-input.move.x
input.pitch=-self.pitchy
input.yaw=-self.yawx
end
local viewModelTiltCoords = viewModelTiltAngles:GetCoords()
viewModelTiltCoords.origin = cameraCoords.origin
return viewModelTiltCoords
end
return cameraCoords
end<!--c2--></div><!--ec2-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function CameraHolderMixin:SetBaseViewAngles(viewAngles)
self.baseYaw = viewAngles.yaw
// Adjusting the base pitch and roll is not desirable.
// It ends up putting the player into a state where their camera goes upside
// down and rolls around at weird angles relative to their mouse input.
// I can't imagine a case where this would be wanted.
self.basePitch = 0
self.baseRoll = 0
end<!--c2--></div><!--ec2-->
Take a look at ControllerMixin.lua though, and perhaps ModleMixin.lua too, the later I don't have time to check through right now.
Particularly these two functions look interesting.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function ControllerMixin:UpdateControllerFromEntity()<!--c2--></div><!--ec2-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function ControllerMixin:PerformMovement(offset, maxTraces, velocity)<!--c2--></div><!--ec2-->
I got that error today. I had been editing the fade file and had entered a syntax error in the fade file, that caused this break. I'd check your skulk.lua file for invalid statements.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Player:_CheckInputInversion(input)
// Invert mouse if specified in options.
local invertMouse = Client.GetOptionBoolean(kInvertedMouseOptionsKey, false)
if invertMouse then
input.pitch = -input.pitch
end
end
function Player:OverrideInput(input)
self:_CheckInputInversion(input)
local maxPitch = Math.Radians(89.9)
input.pitch = Math.Clamp(input.pitch, -maxPitch, maxPitch)
if self.timeClosedMenu and (Shared.GetTime() < self.timeClosedMenu + .25) then
// Don't allow weapon firing
local removePrimaryAttackMask = bit.bxor(0xFFFFFFFF, Move.PrimaryAttack)
input.commands = bit.band(input.commands, removePrimaryAttackMask)
end
if self.frozen then
// Don't allow secondary attack while frozen to prevent skulks from jumping around.
local removeSecondaryAttackMask = bit.bxor(0xFFFFFFFF, Move.SecondaryAttack)
input.commands = bit.band(input.commands, removeSecondaryAttackMask)
end
self:OverrideSayingsMenu(input)
return input
end<!--c2--></div><!--ec2-->
This got me thinking, can we write an input override function that works along the lines of <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Fade:OverrideInput(input)
if self:GetIsWallWalking() then
for rotation of camera
rotate controls
end
end<!--c2--></div><!--ec2-->
What do you think, could it work? My head needs a break so I'm not going to try anything with it for a few hours at least :)
<a href="http://www.unknownworlds.com/ns2/forums/index.php?showtopic=115926&pid=1897075&st=60&#entry1897075" target="_blank">http://www.unknownworlds.com/ns2/forums/in...p;#entry1897075</a>
Instead of modifying OverrideInput can also override :
Player:UpdateViewAngles(input)
It's the function that set the camera angle from the input and
Player:ComputeForwardVelocity(input)
That compute the velocity from the inputs.
would love spinning while leaping skulks :P
would love spinning while leaping skulks :P<!--QuoteEnd--></div><!--QuoteEEnd-->
We're using the UWE code, it doesn't work properly. When you enable it, the controls aren't altered for the fact your view is altered, and thus causes issue. You can add a slight view tilt without issue, but full lean and turn is hard to figure out :)
<!--quoteo(post=1897632:date=Jan 27 2012, 07:25 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 27 2012, 07:25 PM) <a href="index.php?act=findpost&pid=1897632"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->But I'm already so committed to this thread!
coords.yAxis = wallNormal
coords.zAxis = f(input.yaw, input.pitch)
coords.xAxis = perpendicular to yAxis and zAxis
?
<a href="http://www.unknownworlds.com/ns2/forums/index.php?showtopic=115601" target="_blank">Very well...</a><!--QuoteEnd--></div><!--QuoteEEnd-->
What about this:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->wallNormal = self.wallWalkingNormalCurrent
coords.yAxis = wallNormal
coords.zAxis.x = math.sin(input.yaw)
coords.zAxis.y = math.sin(input.pitch)
// coords.zAxis.z = ?
// x^2 + y^2 + z^2 = 1
// z^2 = 1 - (x^2 + y^2)
// z = +-sqrt[1 - (x^2 + y^2))]
coords.zAxis.z = math.sqrt(1 - ((coords.zAxis.x)^2 + (coords.zAxis.y)^2)) // positive or negative? depends on cosine of the angle(s) I guess. How?
coords.xAxis = math.crossProduct(coords.yAxis,coords.zAxis) // which order? we want zAxis forward, yAxis up, xAxis right<!--c2--></div><!--ec2-->
<img src="http://i.imgur.com/7hd5v.png" border="0" class="linked-image" />
hrrmm... that might not work quite right. x y and z axes have to be orthogonal don't they...
what about:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->wallNormal = self.wallWalkingNormalCurrent
coords.yAxis = wallNormal
coords.zAxis = [0,0,0] // ?
coords.zAxis.x = math.sin(input.yaw)
coords.zAxis.y = ? // we have one parameter (x), we know length is 1, and we know a perpendicular vector (coords.yAxis)
coords.zAxis.z = ? // once we have above, we should be able to determine this as well?
coords.xAxis = math.crossProduct(coords.yAxis,coords.zAxis) // which order? we want zAxis forward, yAxis up, xAxis right
coords = coords:getRotation(coords.xAxis, input.pitch)<!--c2--></div><!--ec2-->
We want to keep the z-axis the same, and rotate the x and y axis around that. But how do we do it?
Here is how. I can't remember all the lua words for the different vectors, but it should be clear what I mean:
New x-axis: <b>[wallwalkingnormal]x[camera z-axis]</b>
The camera z-axis and wallwalkingnormal will span a plane, the normal to that vector will be orthogonal to the z-axis (and wallwalkingnormal ofcourse). Now that we have two orthogonal vectors, we just take the cross between them to get the new y-axis:
New y-axis: <b>[camera z-axis]x[new x-axis]</b>
So let's see if it works (cba normalizing right now, they should point in the right direction still) by starting simple:
vertical wall to your left, normal got coordinates [-1,0,0] and you aim parallel to it so z-axis=[0,0,1], x-axis=[1,0,0] and y-axis=[0,1,0]. We want the view to rotate 90 degree clockwise, so that our new x-axis=[0,1,0] and y-axis=[-1,0,0]. We get:
[-1,0,0]x[0,0,1]=[0,1,0] which is wanted x-axis.
[0,0,1]x[0,1,0]=[-1,0,0] which is wanted y-axis.
Trying something more complex: same wall, but aiming diagonally up away from it, so z-axis=1/sqrt(3)*[-1,1,1], x-axis=1/sqrt(2)*[1,0,1] and y-axis=1/sqrt(6)*[1,2,-1]. Yea, I normalized after all... Had to calculate the y-axis by taking the cross product of z and x. Rotating again 90 degree clockwise we want our new x-axis to lie in the wallwalking plane (y-z plane) with the y-component positive, or we would have rotated the wrong direction. Since z-axis points up away from the wall and x-axis point up, the y-axis need to be negative in all components, or would point into the wall.
[-1,0,0]x(1/sqrt(3))[-1,1,1]=1/sqrt(3)*[0,1,-1] which is wanted.
1/3([-1,1,1]x[0,1,-1]=1/3*[-2,-1,-1] which is wanted.
Now, I may have made some mistake somewhere, but the general idea should work. Also, calculating the vectors when you rotate around more than one axis isn't easy to do in your head...
I think the default parametrization is z-axis = (cos(yaw), tan(pitch), sin(yaw)) maybe it would work.
Found it.
<a href="http://en.wikipedia.org/wiki/Sphere#Equations_in_R3" target="_blank">http://en.wikipedia.org/wiki/Sphere#Equations_in_R3</a>
<a href="http://en.wikipedia.org/wiki/Spherical_coordinates" target="_blank">http://en.wikipedia.org/wiki/Spherical_coordinates</a>
<img src="http://i.imgur.com/gNvSc.png" border="0" class="linked-image" />
r = 1
x0, y0, z0 = 0, 0, 0
θ = -input.pitch
φ = input.yaw
Just that... this gives the... y-axis? Not 100% sure.
Ah, nope, it gives the z-axis:
When θ = 0, φ = 0
x = 0
y = 0
z = 1
Yes, this is ideal.
One question popped into my head last night, which may have been already answered by Fluid Core, but I'm not sure :P We've been doing the rotation for the camera, but don't we need to multiply that by a translation on the plane, from a horizontal to a vertical? What we covered initally is the camera transform, but not planar transformation.
As I said, Fluid seems to have mentioned this, but I can't be sure I follow the maths so well :P
<!--quoteo(post=1897657:date=Jan 27 2012, 03:19 PM:name=Yuuki)--><div class='quotetop'>QUOTE (Yuuki @ Jan 27 2012, 03:19 PM) <a href="index.php?act=findpost&pid=1897657"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Sounds good, there is only one thing missing, how do you get camera z-axis from input ?<!--QuoteEnd--></div><!--QuoteEEnd-->
Maybe do the code in
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Fade:PlayerCameraCoordsAdjustment(cameraCoords)<!--c2--></div><!--ec2-->
Or create a new function in Player that enables us to inherit input and cameracoords?
ns2_skulktest
<img src="http://img.photobucket.com/albums/v260/Soulrefuge/skulktestmap.png" border="0" class="linked-image" />
Download here:
<a href="http://www.filehosting.org/file/details/305766/ns2_skulktest.rar" target="_blank">http://www.filehosting.org/file/details/30...2_skulktest.rar</a>
I think the default parametrization is z-axis = (cos(yaw), tan(pitch), sin(yaw)) maybe it would work.<!--QuoteEnd--></div><!--QuoteEEnd-->
Good point. Can you call multiple values in one function? Such as calling a function with both input and cameracoords? They should also be defined somewhere in the code so that we could call it in a function, similar to how for example self.wallWalkingNormalCurrent is used.
<!--quoteo(post=1897658:date=Jan 27 2012, 03:35 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 27 2012, 03:35 PM) <a href="index.php?act=findpost&pid=1897658"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->tan(pitch)? couldn't that lead to really large values of y?<!--QuoteEnd--></div><!--QuoteEEnd-->
Pitch of pi/2 (or -pi/2) will give values approching + or - infinite. Don't how pitch is expressed exactely.
<!--quoteo(post=1897668:date=Jan 27 2012, 04:30 PM:name=Soul_Rider)--><div class='quotetop'>QUOTE (Soul_Rider @ Jan 27 2012, 04:30 PM) <a href="index.php?act=findpost&pid=1897668"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->One question popped into my head last night, which may have been already answered by Fluid Core, but I'm not sure :P We've been doing the rotation for the camera, but don't we need to multiply that by a translation on the plane, from a horizontal to a vertical? What we covered initally is the camera transform, but not planar transformation.<!--QuoteEnd--></div><!--QuoteEEnd-->
Not completely sure what you mean. If you relate the inputs to the camera coords then they will behave as if in the new plane. The problem is getting the camera working and being able to have inputs working alongside it. Hopefully that camera orientation should work for all situations, might get strange situations if you can stand on a wall and aim straight at or away from it. On the ground that is solved by only being able to pitch 89.5 degrees up or down. Hopefully that will translate automatically with the new camera coordinates.
Inspired by <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->viewModelTiltAngles:GetCoords()<!--c2--></div><!--ec2-->, could it work to do the same way for getting the camera coords? So that
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local cameraCoords = cameraCoords:GetCoords()<!--c2--></div><!--ec2-->
I have to take a break now though, best of luck while I'm gone!
<a href="http://en.wikipedia.org/wiki/Sphere#Equations_in_R3" target="_blank">http://en.wikipedia.org/wiki/Sphere#Equations_in_R3</a>
<a href="http://en.wikipedia.org/wiki/Spherical_coordinates" target="_blank">http://en.wikipedia.org/wiki/Spherical_coordinates</a>
<img src="http://i.imgur.com/gNvSc.png" border="0" class="linked-image" />
r = 1
x0, y0, z0 = 0, 0, 0
θ = -input.pitch
φ = input.yaw
Just that... this gives the... y-axis? Not 100% sure.
Ah, nope, it gives the z-axis:
When θ = 0, φ = 0
x = 0
y = 0
z = 1
Yes, this is ideal.<!--QuoteEnd--></div><!--QuoteEEnd-->
I've been quick-editing my post while tabbing into a game, so you might not have seen this yet. But now we've got the starting z-axis, and we can take the approach that Fluid Core described earlier.
local coords = angles:GetCoords()
coords.zAxis.x = math.cos(-input.pitch)*math.sin(input.yaw) // could be cos(input.pitch)
coords.zAxis.y = math.sin(-input.pitch)*math.sin(input.yaw) // could be sin(input.pitch)
coords.zAxis.z = math.cos(input.yaw)
local wallWalkingNormal = self.wallWalkingNormalCurrent
coords.xAxis = math.crossProduct(wallWalkingNormal,coords.zAxis) // could be (coords.zAxis,wallWalkingNormal)
coords.yAxis = math.crossProduct(coords.zAxis,coords.xAxis) // could be (coords.xAxis,coords.zAxis)
angles:BuildFromCoords(coords)
self:SetViewAngles(angles)<!--c2--></div><!--ec2-->