Gorge Powerslide Mod
Soul_Rider
Mod Bean Join Date: 2004-06-19 Member: 29388Members, Constellation, Squad Five Blue
<div class="IPBDescription">Videos and Code</div><a href="http://www.duplexgaming.co.uk/downloads/mods/74/gorge_powerslide/" target="_blank">Download Here</a>
Version 3 of the Powerslide :)
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/WUfoVHSL9WY"></param><embed src="http://www.youtube.com/v/WUfoVHSL9WY" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
--------------Original Post---------------------------
As you are aware the current bellyslide fires you in a straight line and turning your view with the mouse does not make you turn.
I want to add the ability for the Gorge to 'PowerSlide' around corners. I have an idea of the kind of code that needs to be written, but I haven't really delved into the mathematics for many years, so I am asking for help in what I need to do. I will use this as my re-introduction to advanced maths :)
So here is what I want the code to do in principle:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if self:GetIsSliding() then
local currentDirection = GetNormalizedVector(self:GetVelocity())
local viewDirection = GetNormalizedVector(self:GetViewCoords())
if viewDirection ~= currentDirection then
if difference between viewDirection and currentDirection > 5 degrees then
local newDirection = (Difference between viewDirection and currentDirection) \ 2
local slidePush = newDirection * (kStartSlideForce \ 2)
velocity.x = velocity.x + slidePush.x
velocity.y = velocity.y + slidePush.y
velocity.z = velocity.z + slidePush.z
end
end
end<!--c2--></div><!--ec2-->
The aim of this is to take the difference between the direction you are facing, and the direction you are going, divide the angle. and start propelling you along the divided angle with a minor slide kick, to power you around the corner slowly. Values will definitely need adjusting, but this is what I want to do in principle, any help with the implementation?
Version 3 of the Powerslide :)
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/WUfoVHSL9WY"></param><embed src="http://www.youtube.com/v/WUfoVHSL9WY" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
--------------Original Post---------------------------
As you are aware the current bellyslide fires you in a straight line and turning your view with the mouse does not make you turn.
I want to add the ability for the Gorge to 'PowerSlide' around corners. I have an idea of the kind of code that needs to be written, but I haven't really delved into the mathematics for many years, so I am asking for help in what I need to do. I will use this as my re-introduction to advanced maths :)
So here is what I want the code to do in principle:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if self:GetIsSliding() then
local currentDirection = GetNormalizedVector(self:GetVelocity())
local viewDirection = GetNormalizedVector(self:GetViewCoords())
if viewDirection ~= currentDirection then
if difference between viewDirection and currentDirection > 5 degrees then
local newDirection = (Difference between viewDirection and currentDirection) \ 2
local slidePush = newDirection * (kStartSlideForce \ 2)
velocity.x = velocity.x + slidePush.x
velocity.y = velocity.y + slidePush.y
velocity.z = velocity.z + slidePush.z
end
end
end<!--c2--></div><!--ec2-->
The aim of this is to take the difference between the direction you are facing, and the direction you are going, divide the angle. and start propelling you along the divided angle with a minor slide kick, to power you around the corner slowly. Values will definitely need adjusting, but this is what I want to do in principle, any help with the implementation?
Comments
Coordinate systems have three axis (normalized vectors) and an origin. What you want to do is something like this :
local viewDirection = self:GetViewCoords().zAxis
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if viewDirection ~= currentDirection then<!--c2--></div><!--ec2-->
To measure if two normalized vectors are aligned you can use the dot product, which give you just one number (a scalar). This number is equal to one if the two vectors are perfectly aligned, zero if they are perpendicular and -1 if they are in opposite direction. So you want to do something like :
if viewDirection:DotProduct(currentDirection) < 0.9 then
I don't exactly understand what you want to do, but doing the difference between the vectors seems a bit weird, don't you simply want to get the average of the two vectors ?
newDirection = (currentDirection + viewDirection) / 2
You can also add vectors directly :
velocity = velocity + slidePush
So here is the 1st pass:
Gorge Powerslide:
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/MYlwD2Vu1GY"></param><embed src="http://www.youtube.com/v/MYlwD2Vu1GY" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Current issues are when belly sliding to receive a boost all you need to do is turn your view angle, and while max speed is clamped you can theoretically keep sliding forever.
This issue is mitigated in NS2 by the fact you can only slide on infestation, but in my TDM mod you can slide anywhere. I will add a timer into the code to make it more powerslide like, so that the update of the direction is only performed every .5 sec.
Other than that, any other ideas on how to improve the skill involved in manoeuvring a sliding gorge around corners?
I will also try and add the 'pushoff' animation to play when I fire a turning kick as well, to give a reason for the turn, although probably not as often as the turn is called in the code, a .5 sec animation update time might be a bit too much :)
Recorded at 15fps so excuse the poor driving and crashing :P
All you need to do is open up gorge.lua and go to the function:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->local function UpdateGorgeSliding(self, input)
PROFILE("UpdateGorgeSliding")<!--c2--></div><!--ec2-->
Then near the end of the function find the lines:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// Have Gorge lean into turns depending on input. He leans more at higher rates of speed.
if self:GetIsSliding() then
local desiredBellyYaw = 2 * (-input.move.x / kSlidingMoveInputScalar) * (self:GetVelocity():GetLength() / self:GetMaxSpeed())
self.bellyYaw = Slerp(self.bellyYaw, desiredBellyYaw, input.time * kGorgeLeanSpeed)<!--c2--></div><!--ec2-->
In the open if clause place the following code:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//PPPP-Powerslide
local currentDirection = GetNormalizedVector(self:GetVelocity())
local viewDirection = self:GetViewCoords().zAxis
if viewDirection:DotProduct(currentDirection) < 0.9 then
local newDirection = (viewDirection + currentDirection) / 4
local slidePush = newDirection * (kStartSlideForce / 4)
local velocity = self:GetVelocity()
velocity = velocity + slidePush
self:SetVelocity(velocity)
end<!--c2--></div><!--ec2-->
So the finished function looks like this:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->local function UpdateGorgeSliding(self, input)
PROFILE("UpdateGorgeSliding")
local slidingDesired = GetIsSlidingDesired(self, input)
if slidingDesired and not self.sliding then
self.sliding = true
self.startedSliding = true
if Server then
self.slideLoopSound:Start()
end
end
if not slidingDesired and self.sliding then
self.sliding = false
if Server then
self.slideLoopSound:Stop()
end
end
// Have Gorge lean into turns depending on input. He leans more at higher rates of speed.
if self:GetIsSliding() then
local desiredBellyYaw = 2 * (-input.move.x / kSlidingMoveInputScalar) * (self:GetVelocity():GetLength() / self:GetMaxSpeed())
self.bellyYaw = Slerp(self.bellyYaw, desiredBellyYaw, input.time * kGorgeLeanSpeed)
//PPPP-Powerslide
local currentDirection = GetNormalizedVector(self:GetVelocity())
local viewDirection = self:GetViewCoords().zAxis
if viewDirection:DotProduct(currentDirection) < 0.9 then
local newDirection = (viewDirection + currentDirection) / 4
local slidePush = newDirection * (kStartSlideForce / 4)
local velocity = self:GetVelocity()
velocity = velocity + slidePush
self:SetVelocity(velocity)
end
end
end<!--c2--></div><!--ec2-->
Maybe adding a bit of friction, so If you do nothing you loose speed.
Maybe adding a bit of friction, so If you do nothing you loose speed.<!--QuoteEnd--></div><!--QuoteEEnd-->
Currently if you do nothing, that is stay facing in a direction after turning, the gorge will slow down as per normal bellyslide slow down. Maybe I have to increase the angle of turn before it provides a kick, as at the moment a little left/right movement of the mouse keeps you sliding forward, but then it's still kind of skill based movement.
Also in NS2, gorge can only slide on infestation. In my mod, as a TDM super long belly slides are only going to take you towards or away from a battle, I mean, you can't fight or heal anyone while sliding, so it's a decent enough compromise.
I've released version 1 alpha of my TDM with this in it too.
Would be interesting to do some sort of Mario Kart drifting style thing, maybe using the control key along with the bellysliding key, to get a speed boost coming out of turns, with the right timing. There's visuals in Mario Kart to show when to hit the button, but since you bellyslide in first person you wouldn't see any FX on the gorge model, so would need some indication through sound or on the HUD. Just tossing out ideas, not sure how feasible they are, and might be too ridiculous for the actual game, but would be fun to try out.
Also, I'd be interested to see how this looks from first person view, as well, since that will be how you experience the bellyslide as a player.
--Cory
Fast and the Furious, Gorge Drift
It would be funny to use in it's current state on a gorge racetrack for sure :)
Needs a lot more work to be a sensible mod to fit within NS2 gameplay, but I can always try and make more than 1 version :)
I need some mappers to make TDM maps, and now GorgeRace maps :)
Fast and the Furious, Gorge Drift<!--QuoteEnd--></div><!--QuoteEEnd-->
You mean the Fat and the Furious: Gorge Drift.
Should become a game mode. At least in some ready rooms :D
<!--coloro:gray--><span style="color:gray"><!--/coloro-->I mean, <b>if it didn't already</b>, then I would probably use surface normals to determine the acceleration (decline) or deceleration (incline), but that might be too difficult, so while sliding you could take the difference in position between two frames, take the perpendicular (the "normal"), add it to gravity (to get the resultant force) and apply a force (acceleration) in that direction. Or this image can simplify it for you:
<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Freebodydiagram3_pn.svg/500px-Freebodydiagram3_pn.svg.png" border="0" class="linked-image" />
I'd just ignore friction and apply that later, though. Because for instance, you might be trying to move up the incline, so you'd be working against both friction and the weight force.
So, simply put, for two positions, original position [x1,y1,z1], new position [x2,y2,z2]
acceleration
= force / mass
= m.g.sin(theta) / m
= g.sin(theta)
= g.(y2-y1)/|[x2-x1,y2-y1,z2-z1]|
= (acceleration due to gravity)*(difference in elevation)/(magnitude of vector between two points)
the acceleration would apply in the direction normalised([x2-x1,y2-y1,z2-z1]) i.e. (vector between two points, normalised as a unit vector)
<!--colorc--></span><!--/colorc-->
I think it would also be interesting if you had very little friction outside of infestation, but zero friction on infestation. So on a horizontal plane outside of infestation, you would very slowly decelerate, but on infestation you would just skate along.
Also what about, like, a "kick"? For example, pressing jump and a movement key while holding shift would add a force in that direction. So when turning a straight corner, you'd want to strafe-kick, to push you around the corner rather than sliding out of control - this could be where you gain the speed bonus that Cory was talking about too.
Also, in terms of third-person visuals, I think there should be a bit of tilting with turns, and pitching with incline/declines. The first-person visuals may benefit from tilting with turns, too.
With my code currently, if you use the powerslide around the corner, and then continue facing in the same direction, the powerslide runs out of energy exactly like normal. The only trouble is currently, as the powerslide slows down, rather than having to release the slide and start a new one, you can just turn the mouse by a few degrees to get the slide going again. This is what i want to remove, the ability to re-powerslide, once the powerslide has finished.
The powerslide should end the belly slide like it does, but should not be affected by moving the mouse again.
I will update some videos to show what I mean.
----EDIT-----
Standard straight line belly slide:
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/yX1WEzjSwRE"></param><embed src="http://www.youtube.com/v/yX1WEzjSwRE" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
Powerslide around corner, then user doesn't adjust view after powersliding around corner:
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/2Pwt7S6ISEQ"></param><embed src="http://www.youtube.com/v/2Pwt7S6ISEQ" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
The problem is, as the slide is slowing down, moving the mouse provides the kick again. I want this after kick disabled until the shift key is released then pressed again:
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/AA1Qvqm2lUo"></param><embed src="http://www.youtube.com/v/AA1Qvqm2lUo" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
This of course is actually a key requirement of gorge racing, but probably not of NS2 gameplay.
I want the player to have to release the shift key and press again to get the straight line boost again as they come around the corner, which can be done now, but I need to stop the current implementation from being used as infinite belly slide.
Also, I'd be interested to see how this looks from first person view, as well, since that will be how you experience the bellyslide as a player.
--Cory<!--QuoteEnd--></div><!--QuoteEEnd-->
The <u><b>tongue animation</b></u> could be used as indication to hit the right button.
Please more Gorge powerslide and<u><b> NO SLOW on damage</b></u>.
How do I stop the ability to powerslide continuously?
Make it use energy? Make the powerslide ability only work for a certain period of time and need a cooldown?
The level of control provided etc is really good, I just need to find a simple but effective way of restricting the usage of powerslide.
@Harimau, there is already something like it in the game; when you try to move the collision cylinder and it hits something the velocity is partially redirected along the wall surface. It's like a mildly inelastic collision. But there is also speed clamping and such that prevent you to gain speed often.
Making it an ability, means I can add a secondary fire, so for a straight line shot of speed at the end of the powerslide, that kills the powerslide and forces an ordinary belly slide to finish.
It's a lot of code, but I think it is the most sensible way of handling it. Makes the code more robust and less prone to code changes too if it's all kept separate.
What do you think?
How do I stop the ability to powerslide continuously?
Make it use energy? Make the powerslide ability only work for a certain period of time and need a cooldown?
The level of control provided etc is really good, I just need to find a simple but effective way of restricting the usage of powerslide.<!--QuoteEnd--></div><!--QuoteEEnd-->
I made the suggestion of using shift+space+direction for the kick (and the kick would be directional).
Do you want to restrict sliding in general, or just powerslide (what gives you a speed advantage)? I would just make powerslide more conditional I think.
Also, latest videos?
<!--quoteo(post=1903943:date=Feb 17 2012, 08:23 AM:name=Yuuki)--><div class='quotetop'>QUOTE (Yuuki @ Feb 17 2012, 08:23 AM) <a href="index.php?act=findpost&pid=1903943"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->@Harimau, there is already something like it in the game; when you try to move the collision cylinder and it hits something the velocity is partially redirected along the wall surface. It's like a mildly inelastic collision. But there is also speed clamping and such that prevent you to gain speed often.<!--QuoteEnd--></div><!--QuoteEEnd-->
So with no friction, would you gain speed as you continued to slide down a slope?
The implementation of the slide in game hasn't changed at, just been experimenting with different ways of coding it. I think I will probably go with making it an ability, much simpler to manage and tidier in the long run.
<!--quoteo(post=1904028:date=Feb 17 2012, 03:53 AM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Feb 17 2012, 03:53 AM) <a href="index.php?act=findpost&pid=1904028"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->So with no friction, would you gain speed as you continued to slide down a slope?<!--QuoteEnd--></div><!--QuoteEEnd-->
Until you hit the Max Speed clamp limit yes.
is the limit high? and is it possible to change the limit so you can keep gaining speed?
"im visualizing a ski ramp and jumping as a gorge"
It doesn't appears to be working for build 199. :(
As for it not working :P
It is used in my PG mod, and works with Build 199. I am using the original code posted here. Of course, when I say works, I mean it does what it does in the original video, whether that really counts as working or not...
The code worked in 199, but the file didn't, as UWE had made some changes. The code as entered still works. But now, I've taken it even further...
<a href="http://www.duplexgaming.co.uk/downloads/mods/74/gorge_powerslide/" target="_blank">Gorge PowerSlide Version 3</a>
Press space while sliding to PowerSlide around the corner. Powerslide ability drains energy. When you release the space bar, or run out of energy, you continue going in the direction you are travelling, not the one you are facing! To get a kick in the right direction, you need to release and reapply the belly slide key.
The skill comes in knowing the right point to get the slide kick right, and getting used to the powerslide itself.
It takes a bit of practice, but it is great fun.
I tried to make videos, but I kept crashing...
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/sv2JEcDPi_I"></param><embed src="http://www.youtube.com/v/sv2JEcDPi_I" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/GdReG2_aRXI"></param><embed src="http://www.youtube.com/v/GdReG2_aRXI" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/9dXMmznx_Ik"></param><embed src="http://www.youtube.com/v/9dXMmznx_Ik" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
On the third attempt I got through the door, but immediately released the shift key and forgot to press it again :P
While sliding back, I turned the mouse, but forgot to use powerslide :P This is purely a result of 15fps and not a difficulty with the controls :)
Note: Every time you see the tongue flick out, that is me pressing the slide key again. There are no mile long continuous slides with this version. Also note the energy drain when I am using powerslide.
<center><object width="450" height="356"><param name="movie" value="http://www.youtube.com/v/WUfoVHSL9WY"></param><embed src="http://www.youtube.com/v/WUfoVHSL9WY" type="application/x-shockwave-flash" width="450" height="356"></embed></object></center>
There is still the issue that if your slide has almost come to a stop, and you turn and start to powerslide, it will kick and speed you up. This cannot be abused like before, due to the energy drain.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->local function UpdateGorgeSliding(self, input)
PROFILE("UpdateGorgeSliding")
local slidingDesired = GetIsSlidingDesired(self, input)
if slidingDesired and not self.sliding and self:GetGameEffectMask(kGameEffect.OnInfestation) then
self.sliding = true
self.startedSliding = true
if Server then
self.slideLoopSound:Start()
end
end
if not slidingDesired and self.sliding then
self.sliding = false
if Server then
self.slideLoopSound:Stop()
end
end
// Have Gorge lean into turns depending on input. He leans more at higher rates of speed.
if self:GetIsSliding() then
local desiredBellyYaw = 2 * (-input.move.x / kSlidingMoveInputScalar) * (self:GetVelocity():GetLength() / self:GetMaxSpeed())
self.bellyYaw = Slerp(self.bellyYaw, desiredBellyYaw, input.time * kGorgeLeanSpeed)
if bit.band(input.commands, Move.Jump) ~= 0 then
local currentDirection = GetNormalizedVector(self:GetVelocity())
local viewDirection = self:GetViewCoords().zAxis
if viewDirection:DotProduct(currentDirection) < 0.9 then
if self:GetEnergy() > 6 then
local newDirection = (viewDirection + currentDirection) / 4
local slidePush = newDirection * (kStartSlideForce / 4)
local velocity = self:GetVelocity()
velocity = velocity + slidePush
self:SetVelocity(velocity)
self:DeductAbilityEnergy(2)
end
end
end
end
end<!--c2--></div><!--ec2-->
When turning/slide sideways in a turn make the head camera angle tilt that direction (like riding a motorcycle)
Humans do it when running turn turns or any animal, would be a neat feature