Let's discuss skulk movement
Yuuki
Join Date: 2010-11-20 Member: 75079Members
<div class="IPBDescription">in a civilized manner</div>Topics: speed, air control, wall walking, jump, wall jumping, leap.
There is some interesting changes in the last patch, the wall jumping has been changed a bit, and there is also a system that store energy when you land, like a spring and give it back as speed (you can see you sink in a bit in the ground when landing), didn't looked in details yet. For some reason they do not work so well yet.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> // if we have impactVelocity, we shift the models origin in the direction of the deltaVee
// We shift the model (hack; should use animation instead) to reflect the storing of the energy
// in the legs ... its a real short-duration effect, about 1/5 of a second. The timing is the
// same for all energies, but the size of the effect is bigger for bigger energy
local bounceSinkIn = self:CalcBounceSinkIn()
if bounceSinkIn then
modelCoords.origin = modelCoords.origin + bounceSinkIn * 0.5
end<!--c2--></div><!--ec2-->
The way the wall walking works is also interesting. Anyway here is some tweaks I've done, the numbers are a bit extreme but it's fun to jump around the map :
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/jcYFkBYjOo8"></param><embed src="http://www.youtube.com/v/jcYFkBYjOo8" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Code linked if someone want to test (probably a bit buggy, I've change lots of things).
<a href="http://www.mediafire.com/?ii53zq54evzuqto" target="_blank">http://www.mediafire.com/?ii53zq54evzuqto</a>
There is some interesting changes in the last patch, the wall jumping has been changed a bit, and there is also a system that store energy when you land, like a spring and give it back as speed (you can see you sink in a bit in the ground when landing), didn't looked in details yet. For some reason they do not work so well yet.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> // if we have impactVelocity, we shift the models origin in the direction of the deltaVee
// We shift the model (hack; should use animation instead) to reflect the storing of the energy
// in the legs ... its a real short-duration effect, about 1/5 of a second. The timing is the
// same for all energies, but the size of the effect is bigger for bigger energy
local bounceSinkIn = self:CalcBounceSinkIn()
if bounceSinkIn then
modelCoords.origin = modelCoords.origin + bounceSinkIn * 0.5
end<!--c2--></div><!--ec2-->
The way the wall walking works is also interesting. Anyway here is some tweaks I've done, the numbers are a bit extreme but it's fun to jump around the map :
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/jcYFkBYjOo8"></param><embed src="http://www.youtube.com/v/jcYFkBYjOo8" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Code linked if someone want to test (probably a bit buggy, I've change lots of things).
<a href="http://www.mediafire.com/?ii53zq54evzuqto" target="_blank">http://www.mediafire.com/?ii53zq54evzuqto</a>
Comments
Hope you did well in the gather ;)
<i> Slightly off-topic, but have you got any new ideas on a working mod for a rotating view? I would surely love to get one working to try, especially as a client mod so that it would be optional. </i>
Looking at the code, so much goes into just making wallwalking work :/
<strike><!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//
// how much of an effect the bounce has just now (0-1). Used to calculate the "sink in" and the bonus jump effect
//
function Skulk:CalcBounceEffectFraction()
local result = 0
local t = Shared.GetTime() - self.timeOfImpact
if t <= Skulk.kStoredDeltaVeeDuration then
result = math.sin(math.pi * t / Skulk.kStoredDeltaVeeDuration)
end
return result
end<!--c2--></div><!--ec2-->
See this line: (1)
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->result = math.sin(math.pi * t / Skulk.kStoredDeltaVeeDuration)<!--c2--></div><!--ec2-->
Should it be: (2)
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->result = math.sin(math.pi / 2 * t / Skulk.kStoredDeltaVeeDuration)<!--c2--></div><!--ec2-->
Or: (3)
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->result = math.cos(math.pi / 2 * t / Skulk.kStoredDeltaVeeDuration)<!--c2--></div><!--ec2-->
(1) means that when
t = 0, result = 0;
t = (Skulk.kStoredDeltaVeeDuration/2), result = 1;
t = Skulk.kStoredDeltaVeeDuration, result = 0
(2) means that when
t = 0, result = 0;
t = Skulk.kStoredDeltaVeeDuration, result = 1
(3) means that when
t = 0, result = 1;
t = Skulk.kStoredDeltaVeeDuration, result = 0</strike>
EDIT: Never mind. I think the goal is that you 'sink in' for half the duration, and then jump at this point to get the maximum speed bonus. Too soon? Less speed bonus. Too late? Less speed bonus.
The final velocity (that might have been reduced by collision) is called "velocity" and the velocity you expected (without collision) is "requestedVelocity", then the game call :
self:StoreImpactVelocity(requestedVelocity, velocity)
In this function the game makes the difference between the two velocities and store it (under some conditions) in self.impactVelocity, and also store the time you hit the wall :
self.impactVelocity = impactVelocity
self.timeOfImpact = Shared.GetTime()
Then if you jump the game use the length of this vector to compute a "velocity bonus" that also depend on this sin shaped curve :
<a href="http://www.wolframalpha.com/input/?i=plot+sin%28pi+t+%2F+0.55%29+between+0+and+0.55" target="_blank">http://www.wolframalpha.com/input/?i=plot+...ween+0+and+0.55</a>
So there is an optimal time (0.55/2 ?) after timeOfImpact, which correspond to the maximum of sink in of your model, if you jump at the moment you get a maximal speed bonus. Exactly what you said Harimau.
The bonus direction is given by where you're looking (viewCoords) and the movement keys :
// we add the bonus in the direction the move is going
local bonusVec = viewCoords:TransformVector( input.move )
I think then idea is pretty good, it makes a lot of sense. But the effect on speed is very subtle in the current implementation, I mainly noticed the sink in of the model. Maybe I should try it a bit more.
<!--quoteo--><div class='quotetop'>QUOTE </div><div class='quotemain'><!--quotec-->Looking at the code, so much goes into just making wallwalking work :/<!--QuoteEnd--></div><!--QuoteEEnd-->
Yeah, the basic ideas are simple but then there is a lot of tricks to make sure it works well on complex geometry, smoothing, sticking, etc.
<!--quoteo--><div class='quotetop'>QUOTE </div><div class='quotemain'><!--quotec-->Slightly off-topic, but have you got any new ideas on a working mod for a rotating view? I would surely love to get one working to try, especially as a client mod so that it would be optional.<!--QuoteEnd--></div><!--QuoteEEnd-->
I don't have new ideas but looking a bit more into skulk code might help, for example there is a piece of code in PreUpdateMove that rotate the skulk model to fit the wall normal. We should also have a look at Player:ComputeForwardVelocity (the function that generate movement from inputs) and maybe override it.
Currently, Skulks have to face parallel to the surface to achieve maximum forward speed. Unfortunately, this makes it difficult for Skulks to keep their eyes on their enemies.
Skulks can slow down to a crawl if they try to move forward while facing into the wall. On the other hand, if you move away from the wall, you falling off the surface. Consequently, the best method to wall walk is to face away from the wall, and strafe like a crab, which looks very silly.
Since Skulks can easily detach from walls voluntarily with crouch and wall jump, it would be wise to increase the "stickiness" of wall-walking Skulks, to the point they cannot fall off walls with WSAD keys.
I can't compete with the tech-wiz programmer talk of Yuuki and Harimu (sorry if I got you're names spelled wrong but I've had a few KIRIN's), but I have just 2 questions regarding the progress on skulk wall walking;
What has happened to the 'tilt' function?
I really like realism, and I believe that is what UWE has always strived to achieve. If we, as players, are to achieve true skill in this game, then a certain degree of tilt to player view needs to be applied!!
How come I (as skulk) pounce/leap through a marine??
It doesn't make sense.. If I were some rabid space alien dog thing and I jumped on a guys back so I could tear his head from his shoulders I would NOT PASS THROUGH him, ffs!
Maybe only remove a part of it, or in a non-linear way, so you can look down a bit more without detaching.
It doesn't tilt anymore ? I didn't pay attention, It should though, I don't think it was changed recently.
> How come I (as skulk) pounce/leap through a marine??
You can leap though marines ?
It doesn't tilt anymore ? I didn't pay attention, It should though, I don't think it was changed recently.
> How come I (as skulk) pounce/leap through a marine??
You can leap though marines ?<!--QuoteEnd--></div><!--QuoteEEnd-->
No tilting! Not like what it was in earlier builds. I am aware that there may have been some resistance to this, but many REFUSE to get into the spirit of the (new) game in FEAR of losing skills attributed in NS1. Such feebleness NEEDS to be overlooked by UWE in order to make NS2 the success it is due.
Often, in combat with marine as skulk I am discovering that either/and I, marine are quite ethereal and upon moving through the target I am unable to continue/register attack from being to far from target.. I mean, WTH is the rifle-butt for if not to get a skulk off ya??!?!?!?!!?
As it stands, rifle-butt is an awful attribute to the game and stands to wreck the entire balance of marine/kharaa ratio!
(as is the whole I can stand on your head and jump THROUGH your body 'physics')
Often, in combat with marine as skulk I am discovering that either/and I, marine are quite ethereal and upon moving through the target I am unable to continue/register attack from being to far from target.. I mean, WTH is the rifle-butt for if not to get a skulk off ya??!?!?!?!!?
As it stands, rifle-butt is an awful attribute to the game and stands to wreck the entire balance of marine/kharaa ratio!
(as is the whole I can stand on your head and jump THROUGH your body 'physics')<!--QuoteEnd--></div><!--QuoteEEnd-->
Don't get me wrong, I'm sure you raise a valid point. I just can't understand any of it.
There is a cool way of displaying vectors in game, so I tried to display the part of the desired speed that has been removed by the speed clamper, just to get an idea :
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->
local startPoint = Vector(self:GetOrigin())
local extents = self:GetExtents()
startPoint.y = startPoint.y + extents.y
local endPoint = startPoint + velocity-desiredVelocity
DebugLine(startPoint, endPoint, 0.8, 0, 1, 0, 1)
if (velocity-desiredVelocity):GetLength() > 0.7 then
DebugLine(startPoint, endPoint, 2.8, 1, 0, 0, 1)
end<!--c2--></div><!--ec2-->
Here it draws a green vector (0, 1, 0) from the origin of the skulk to the origin plus the difference between the clamped velocity (velocity) and desired velocity (desiredVelocity). So what we see is the speed that has be removed. It also draws the same in red for 2.8 seconds if the velocity difference if big enough.
So here I try to wall jump against a crate in summit, but there is a big vector that is removed when I do so (the long red line along the crate). I find a bit odd to add a speed bonus in a function and to remove most of it in the next one :)
(forgot to turn off the music while recording..)
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/avkfavthU_4"></param><embed src="http://www.youtube.com/v/avkfavthU_4" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
You can also see that a lot of speed is clamped when you go down the ramp, so you can't use it to gain speed (I'm not sure if it's a good think or not).
I think the speed clamper could also hide a few bugs, for example if you mess up with the numbers and add a force that is hundred times too big you might not notice it because if will be clamped out. Here is an example, if you walk on a wall looking up a huge speed is generated for some reason (the big red line) :
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/DHSRY6Zby9U"></param><embed src="http://www.youtube.com/v/DHSRY6Zby9U" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
This would make the trace of the vectors display the path of your movement, and their height the speed and the removed one. Kind of like in this TRON clip, only the height being your speed...
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/-3ODe9mqoDE"></param><embed src="http://www.youtube.com/v/-3ODe9mqoDE" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Drawing the speed makes really cool curves :
<img src="http://i.imgur.com/s902j.jpg" border="0" class="linked-image" />
@Fluid_Core:
I have no idea where you would actually put this (ask Yuuki), but:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local startPoint = Vector(self:GetOrigin())
local extents = self:GetExtents()
local lineScale = 1 // scale the size of the lines
startPoint.y = startPoint.y + extents.y // no idea what this step does, other than that it translates startPoint in the y-direction
local endPoint = startPoint // initialising x, y and z coordinates
endPoint.y = startPoint.y + lineScale*desiredVelocity:GetLength() // translate endPoint in y-direction
DebugLine(startPoint, endPoint, 10, 1, 0, 0, 1) // draw red line for desiredVelocity
endPoint.y = startPoint.y + lineScale*velocity:GetLength() // translate endPoint in y-direction
DebugLine(startPoint, endPoint, 10, 0, 1, 0, 1) // draw green line for velocity<!--c2--></div><!--ec2-->
What this will do (or at least what I predict it will do) is:
- draw vertical red lines whose length is proportional to the length of the desired velocity, with the bottom of the line at the origin.
- draw vertical green lines whose length is proportional to the length of your velocity (i.e. your speed), with the bottom of the line at the origin.
- lines will expire after 10 seconds.
Since I'm not sure how the system will deal with overlapping lines, I'm drawing the desired velocity first (since it will always be larger or equal to your velocity).
If the lines are too long or too short, change the scale.
(I'm assuming y is the vertical axis in this engine.)
@Yuuki:
DebugLine(startPoint, endPoint, a, b, c, d, e)
I understand that "b", "c", "d" dictate the colour (r, g, b), but what do "a" and "e" do? "e" appears to be 1 in both cases, but what significance does "a" being 0.8 then 2.8 have?
EDIT: Oh, I know what "a" is, it's the time that you want the line to remain. Will change the code above. Still not sure what "e" does.
Since e is 1 in both cases, couldn't it be a normalization of some sort?
Yuuki; not only does it look amasing, but it is easier to visualize the speed when it is nt pointing in the movement direction, and thus overlap.
The y axis is up. Should your speed go in the same direction as that it gets harder to visualise again.
// rgba are normalized values (0-1)
function DebugLine(startPoint, endPoint, lifetime, r, g, b, a)
<a href="http://dl.dropbox.com/u/53107776/ns2docs/190/src/natural+selection+2/ns2/lua/Utility.lua/index.html#line-289" target="_blank">http://dl.dropbox.com/u/53107776/ns2docs/1...x.html#line-289</a>
About the speed clamp, you can remove it easily, then you have to adjust the values (friction, forces) and fix a few bugs but it works (cf. first post).
Since e is 1 in both cases, couldn't it be a normalization of some sort?
Yuuki; not only does it look amasing, but it is easier to visualize the speed when it is nt pointing in the movement direction, and thus overlap.
The y axis is up. Should your speed go in the same direction as that it gets harder to visualise again.<!--QuoteEnd--></div><!--QuoteEEnd-->
Do you think you could test it and record a video?
Or Yuuki?
But yeah, clearly it wouldn't work very well when you're moving vertically (wallwalking, jumping vertically, falling vertically), but perhaps you could add a dependency.
like for example
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if (0.5 * velocity:GetLength()) > velocity.y:GetLength() // essentially if vertical velocity accounts for less than half of the total velocity
// draw vertical lines
endPoint.y = startPoint.y + lineScale*desiredVelocity:GetLength() // translate endPoint in y-direction
DebugLine(startPoint, endPoint, 10, 1, 0, 0, 1) // draw red line for desiredVelocity
endPoint.y = startPoint.y + lineScale*velocity:GetLength() // translate endPoint in y-direction
DebugLine(startPoint, endPoint, 10, 0, 1, 0, 1) // draw green line for velocity
else
// draw horizontal lines
endPoint.x = startPoint.x + lineScale*desiredVelocity:GetLength() // translate endPoint in x-direction
DebugLine(startPoint, endPoint, 10, 1, 0, 0, 1) // draw red line for desiredVelocity
endPoint.x = startPoint.x + lineScale*velocity:GetLength() // translate endPoint in x-direction
DebugLine(startPoint, endPoint, 10, 0, 1, 0, 1) // draw green line for velocity
end<!--c2--></div><!--ec2-->
It must be noted that the horizontal line will draw parallel with the x-axis in the absolute frame of reference, i.e. not always useful.
I mean, you could instead try doing it actually perpendicular to the model's movement:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->endPoint = startPoint + lineScale*vector:GetLength()*GetNormalizedVector([some perpendicular vector I'm too lazy to work out right now])<!--c2--></div><!--ec2-->
[Velocity]x[1,1,1]
I initially intended to write a sum of the crossproduct of the velocity and the x, y and z axis, but that should give the same result if I'm not misstaken. This should give the dispalyed vector as [vy-vz,vx-vz,vx-vy] and with a total speed of v we can look at a few scenarios:
Running straight along z: v=[0,0,1] give [-1,1,0] i.e. pointing diagonal up on your right.
Jumping up along y: v=[0,1,0] give [1,0,-1] i.e if you face in z, pointing diagonal behind on your left.
Falling down again: v=[0,-1,0] give [-1,0,1] i.e. diagonal forward on your right.
Running along z and jump: v=[0,1,1] give [0,-1,-1] i.e pointing diagonal up back.
I didn't bother to normalize anything...
Here I put velocity on the current orientation of the skulk (self.wallWalkingNormalCurrent) and the input
on the perpendicular direction, I'm not sure it's really useful...
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->
if math.random() < 0.5 then
local startPoint = Vector(self:GetOrigin())
local extents = self:GetExtents()
startPoint.y = startPoint.y + extents.y
local endPoint = startPoint + self.wallWalkingNormalCurrent*velocity:GetLength()/10
DebugLine(startPoint, endPoint, 5, 0, 1, 0, 1)
endPoint = startPoint + self.wallWalkingNormalCurrent:GetPerpendicular()*input.move:GetLength()
DebugLine(startPoint, endPoint, 5, 1, 0, 0, 1)
end<!--c2--></div><!--ec2-->
Also if you type "skulk_speed" in the console there is some kind of speed-o-meter that is displayed,
pretty cool.
<img src="http://i.imgur.com/BtBas.jpg" border="0" class="linked-image" />
Ideally you should have the red (that's the wanted speed, right?) be stacked over the green, with the difference added to the top of the speed.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function Skulk:ClampSpeed(input, velocity)
local desiredVelocity = Vector(velocity)
if self:GetIsWallWalking() then
// Clamp XYZ speed
local moveSpeed = velocity:GetLength()
local maxSpeed = self:GetMaxSpeed()
if (moveSpeed > maxSpeed) then
velocity:Scale( maxSpeed / moveSpeed )
end
else
// Otherwise clamp XZ
velocity = Alien.ClampSpeed(self, input, velocity)
end
if math.random() < 0.7 then
local startPoint = Vector(self:GetOrigin())
local extents = self:GetExtents()
startPoint.y = startPoint.y + extents.y
local endPoint = startPoint + self.wallWalkingNormalCurrent*velocity:GetLength()/10
DebugLine(startPoint, endPoint, 5, 0, 1, 0, 1)
startPoint = startPoint + self.wallWalkingNormalCurrent*velocity:GetLength()/10
endPoint = startPoint + self.wallWalkingNormalCurrent*(desiredVelocity-velocity):GetLength()/10
DebugLine(startPoint, endPoint, 5, 1, 0, 0, 1)
end
return velocity
end<!--c2--></div><!--ec2-->
Looks pretty good (green is clamped velocity, red is the clamped part) :
<img src="http://i.imgur.com/0ftJJ.png" border="0" class="linked-image" />
It seems also that it doesn't clamp when you jump on a fence, it's probably not counted as wall walking.
Fence :
<img src="http://i.imgur.com/R0Kft.png" border="0" class="linked-image" />
Wall :
<img src="http://i.imgur.com/KNvKk.png" border="0" class="linked-image" />
It the normal of the surface you're currently walking on, so if you're on the ground it points upward, if you're on the ceiling downward, etc. It's also the vertical (yAxis) of the skulk model.
>The inability to bound forward without a hive 2 upgrade and adrenaline is mind boggling
You mean you want leap at one hive ? I would rather have a proper leap at hive 2.
>I'd also claim you need to add in camera shifts so people know what surface their own more easily
You mean to rotate the camera ? We tried to do that with FluidCore, but didn't succeeded yet :
<a href="http://unknownworlds.com/ns2/forums/index.php?showtopic=115601" target="_blank">http://unknownworlds.com/ns2/forums/index....howtopic=115601</a>
I will try to do a version where you can look away from the wall without falling.
And yes, I do mean rotate the camera. It gives you feed back on what wall you're currently on as well as gives the proper perspective for going around corners and bends. Without it when you go around a corner you'll just run right off the edge unless you perform an awkward strafe to wall and hope the wall lets you stick.
Until skulks can rely on wall walk working it would be hard to create any skill based movement revolving around their particular movement style.
It the normal of the surface you're currently walking on, so if you're on the ground it points upward, if you're on the ceiling downward, etc. It's also the vertical (yAxis) of the skulk model.<!--QuoteEnd--></div><!--QuoteEEnd-->
What happens while you're in the air?
<!--quoteo(post=1895738:date=Jan 19 2012, 07:26 PM:name=azimaith)--><div class='quotetop'>QUOTE (azimaith @ Jan 19 2012, 07:26 PM) <a href="index.php?act=findpost&pid=1895738"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I don't even care for leap. I just want to jump forward toward the center of my screen when moving forward, not silly hops.<!--QuoteEnd--></div><!--QuoteEEnd-->
Silly hops is the way that all jumps work in just about every FPS game ever. It would put people off if people lost that ability. However, I think you raise a good point, but this "directional jump" should be in addition to, not a replacement for, "silly hops".
<!--quoteo(post=1895738:date=Jan 19 2012, 07:26 PM:name=azimaith)--><div class='quotetop'>QUOTE (azimaith @ Jan 19 2012, 07:26 PM) <a href="index.php?act=findpost&pid=1895738"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->And yes, I do mean rotate the camera.<!--QuoteEnd--></div><!--QuoteEEnd-->
A lot of people get dizzy, disoriented or motion-sick with this feature.
A suggestion I've seen to get the same idea across is to actually rotate the skulk viewmodel, rather than the skulk view; or else some kind of gravity indicator.
<3