• Custom Movement (again)
    17 replies, posted
Okay, basic idea here is controlling a player's movement by parenting them to an entity which uses custom physics. The problem is my last several attempts at custom physics failed miserably. I need to know how to do a few things: [list]Interpolated path of motion between 2 points. [img]http://img401.imageshack.us/img401/971/diagram1.png[/img] [/list] [list]Movement limited to one axis. [img]http://img169.imageshack.us/img169/4710/diagram2.png[/img] [/list] [list]Movement limited to an axis normal to a surface. [img]http://img169.imageshack.us/img169/7720/diagram3.png[/img] [/list] Can someone write me a quick example script so I can get it to work properly. I haven't a clue how to do any of these.
Well I would think you could..... Umm..... For the last one, you could force the client to move himself toward the wall at all times based on his eye trace, but that would be a really shitty way to do it. (ie. +backward if the client is looking inside a range of angles from the wall)
Parent the player to the entity, run a trace under the entity and set angles relative to it's hit normal, while running movement calculations? Ahg. The difficult thing I see here would be to run movement calculations for the player once on a surface greater than 45 degree's.
Ah! movement limited to 1 axis, you say? [url]http://dl.getdropbox.com/u/99862/HatCatcher.zip[/url] Remember that? While the camera/controls may have been funky, locking the player to a path worked fine.
[QUOTE=Levybreak;17569453]Ah! movement limited to 1 axis, you say? [url]http://dl.getdropbox.com/u/99862/HatCatcher.zip[/url] Remember that? While the camera/controls may have been funky, locking the player to a path worked fine.[/QUOTE] I remember that! :xd: That was fun to judge. So what about the other ones? [editline]03:26PM[/editline] Your code is interesting. Do you have a node path in the map, or are you creating nodes on the fly? I don't want to have to place nodes for every wall in my map or create more than I need to.
[QUOTE=grea$emonkey;17569518]I remember that! :xd: That was fun to judge. So what about the other ones? [editline]03:26PM[/editline] Your code is interesting. Do you have a node path in the map, or are you creating nodes on the fly? I don't want to have to place nodes for every wall in my map or create more than I need to.[/QUOTE] I have a node path in the map, but you can easily place them dynamically if you so desire. It just Lerp's the player's view and movement between the two points. (All the confusing movement code is primarily to TRY to get the camera to not fuck up. :S)
[QUOTE=Levybreak;17603253]I have a node path in the map, but you can easily place them dynamically if you so desire. It just Lerp's the player's view and movement between the two points. (All the confusing movement code is primarily to TRY to get the camera to not fuck up. :S)[/QUOTE] Could you post what restricts them to an axis?
[QUOTE=grea$emonkey;17603398]Could you post what restricts them to an axis?[/QUOTE] When you use Lerp for movement, it's just a constant loop of SetPos. The game automatically smooths the movement between the points.
I just want to see a pseudo-function so I have some idea.
[QUOTE=grea$emonkey;17616470]I just want to see a pseudo-function so I have some idea.[/QUOTE] [lua] local gravity = Vector(0,0,-160) function GM:SetupMove(ply, data) local fwdvec = ply:GetAngles():Forward() ply.VelocityMod = Vector(0,0,0) --[[if ply:KeyDown(IN_BACK) and (not ply.CanAddAngle or ply.CanAddAngle == true) then if not ply.ReverseTimerTick then ply.ReverseTimerTick = 0 end ply.CanAddAngle = true ply.ReverseNodeChanged = true ply.ReverseTimerTick = ply.ReverseTimerTick + 1 if ply.ReverseTimerTick >= 80 then ply.ReverseTimerTick = 0 ply.CanAddAngle = false end end]] data:SetForwardSpeed(0) if ply:KeyDown(IN_MOVERIGHT) then data:SetSideSpeed(0) if ply.LeftIsForward != true then if (ply.Reversed != true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end else if (ply.Reversed == true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end end elseif ply:KeyDown(IN_MOVELEFT) then data:SetSideSpeed(0) if ply.LeftIsForward == true then if (ply.Reversed != true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end else if (ply.Reversed == true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end end end if (ply:KeyPressed(IN_BACK)) then ply:ConCommand("+duck") end if (ply:KeyPressed(IN_FORWARD)) then ply:ConCommand("+jump") end if (ply:KeyReleased(IN_BACK)) then ply:ConCommand("-duck") end if (ply:KeyReleased(IN_FORWARD)) then ply:ConCommand("-jump") end if ply:KeyDown(IN_JUMP) and ((ply:GetGroundEntity():IsValid() == true or ply:GetGroundEntity():IsWorld() == true) or ply.StillJumping == true) then if not ply.JumpTimerTick then ply.JumpTimerTick = 0 end ply.StillJumping = true if ply.StillJumping == true then ply.JumpTimerTick = ply.JumpTimerTick + 1 end if ply.JumpTimerTick >= 60 then ply.StillJumping = false ply.JumpTimerTick = 0 return false end if ply.JumpTimerTick >= 1 then ply.VelocityMod = ply.VelocityMod + Vector(0,0,ply:GetJumpPower()+70) end end if ply:KeyDown(IN_DUCK) then ply.VelocityMod = (fwdvec*(ply.VelocityMod:Length()/2)) + ply.VelocityMod:Normalize() end data:SetVelocity(gravity+ply.VelocityMod) return true end [/lua] And as for think: [lua] function GM:PlayerThink(ply) if ply:IsValid() and ply:Alive() then if ply.viewer and ply.viewer:IsValid() then if ply.FlippedNodes and ply.FlippedNodes == true then ply.FlippedNodes = false ply.viewer.NextNode,ply.viewer.LastNode = ply.viewer.LastNode,ply.viewer.NextNode end if ply.viewer.NextNode and ply.NodeChanged and ply.NodeChanged == true then ply.NodeChanged = false if ply.Reversed and ply.Reversed == true then ply.viewer.LastNode = ply.viewer.CurrentNode ply.viewer.CurrentNode = ply.viewer.NextNode if GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) then ply.viewer.NextNode = GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) else ply.viewer.NextNode = self.ViewStart end else ply.viewer.LastNode = ply.viewer.CurrentNode ply.viewer.CurrentNode = ply.viewer.NextNode if ply.viewer.CurrentNode["target"] and ply.viewer.CurrentNode["target"] != "" then ply.viewer.NextNode = ents.FindByName(ply.viewer.CurrentNode["target"])[1] else ply.viewer.NextNode = self.ViewEnd end end elseif ply.viewer.LastNode and ply.viewer.LastNode:GetName() != ply.viewer.CurrentNode:GetName() and ply.ReverseNodeChanged and ply.ReverseNodeChanged == true then ply.viewer.NextNode,ply.viewer.CurrentNode = ply.viewer.CurrentNode,ply.viewer.NextNode ply.viewer.LastNode = GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) end end if ply.NextNode and ply:GetPos():Distance(ply.NextNode:GetPos()) <= 50 then --value subject to change. if ply.Reversed and ply.Reversed == true then ply.LastNode = ply.CurrentNode ply.CurrentNode = ply.NextNode if GetPathEntityByTarget(ply.CurrentNode:GetName()) then ply.NextNode = GetPathEntityByTarget(ply.CurrentNode:GetName()) else ply.NextNode = self.PlayerStart ply:Lock() if (not ply.Finished) or ply.Finished != true then ply.Finished = true self:ReturnedToStart(ply) end end else ply.LastNode = ply.CurrentNode ply.CurrentNode = ply.NextNode if ply.CurrentNode["target"] and ply.CurrentNode["target"] != "" then ply.NextNode = ents.FindByName(ply.CurrentNode["target"])[1] else ply.NextNode = self.PlayerEnd ply:Lock() if (not ply.Finished) or ply.Finished != true then ply.Finished = true self:FinnishedLevel(ply) end end end ply:SetPos(Vector(ply.CurrentNode:GetPos().x,ply.CurrentNode:GetPos().y,ply:GetPos().z+5)) ply.NodeChanged = true end if (ply.ReverseNodeChanged == true) then ply.ReverseNodeChanged = false ply.NextNode,ply.CurrentNode = ply.CurrentNode,ply.NextNode ply.LastNode = GetPathEntityByTarget(ply.CurrentNode:GetName()) if ply.Reversed then ply.Reversed = !ply.Reversed else ply.Reversed = true end end if ply.Reversed == true and ply.pitch then ply:SetEyeAngles(Angle(math.Clamp(math.NormalizeAngle(tonumber(ply.pitch) + 180)*-1,-60,50),(ply.NextNode:GetPos()-ply:GetPos()):Angle().y,0)) elseif ply.pitch then ply:SetEyeAngles(Angle(math.Clamp(tonumber(ply.pitch),-60,50),(ply.NextNode:GetPos()-ply:GetPos()):Angle().y,0)) else ply:SetEyeAngles(Angle(ply:EyeAngles().p,(ply.NextNode:GetPos()-ply:GetPos()):Angle().y,0)) end if ply.viewer and ply.viewer:IsValid() then if ply.FlippedNodes and ply.FlippedNodes == true then ply.FlippedNodes = false ply.viewer.NextNode,ply.viewer.LastNode = ply.viewer.LastNode,ply.viewer.NextNode end if ply.viewer.NextNode and ply.NodeChanged and ply.NodeChanged == true then ply.NodeChanged = false if ply.Reversed and ply.Reversed == true then ply.viewer.LastNode = ply.viewer.CurrentNode ply.viewer.CurrentNode = ply.viewer.NextNode if GetPathEntityByTar
[QUOTE=Levybreak;17619713][lua] local gravity = Vector(0,0,-160) function GM:SetupMove(ply, data) local fwdvec = ply:GetAngles():Forward() ply.VelocityMod = Vector(0,0,0) --[[if ply:KeyDown(IN_BACK) and (not ply.CanAddAngle or ply.CanAddAngle == true) then if not ply.ReverseTimerTick then ply.ReverseTimerTick = 0 end ply.CanAddAngle = true ply.ReverseNodeChanged = true ply.ReverseTimerTick = ply.ReverseTimerTick + 1 if ply.ReverseTimerTick >= 80 then ply.ReverseTimerTick = 0 ply.CanAddAngle = false end end]] data:SetForwardSpeed(0) if ply:KeyDown(IN_MOVERIGHT) then data:SetSideSpeed(0) if ply.LeftIsForward != true then if (ply.Reversed != true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end else if (ply.Reversed == true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end end elseif ply:KeyDown(IN_MOVELEFT) then data:SetSideSpeed(0) if ply.LeftIsForward == true then if (ply.Reversed != true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end else if (ply.Reversed == true or ply.ReverseNodeChanged == true) then if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*440) data:SetForwardSpeed(440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*220) data:SetForwardSpeed(220) end else ply.ReverseNodeChanged = true if (ply:KeyDown(IN_SPEED)) then ply.VelocityMod = ply.VelocityMod + (fwdvec*-440) data:SetForwardSpeed(-440) else ply.VelocityMod = ply.VelocityMod + (fwdvec*-220) data:SetForwardSpeed(-220) end end end end if (ply:KeyPressed(IN_BACK)) then ply:ConCommand("+duck") end if (ply:KeyPressed(IN_FORWARD)) then ply:ConCommand("+jump") end if (ply:KeyReleased(IN_BACK)) then ply:ConCommand("-duck") end if (ply:KeyReleased(IN_FORWARD)) then ply:ConCommand("-jump") end if ply:KeyDown(IN_JUMP) and ((ply:GetGroundEntity():IsValid() == true or ply:GetGroundEntity():IsWorld() == true) or ply.StillJumping == true) then if not ply.JumpTimerTick then ply.JumpTimerTick = 0 end ply.StillJumping = true if ply.StillJumping == true then ply.JumpTimerTick = ply.JumpTimerTick + 1 end if ply.JumpTimerTick >= 60 then ply.StillJumping = false ply.JumpTimerTick = 0 return false end if ply.JumpTimerTick >= 1 then ply.VelocityMod = ply.VelocityMod + Vector(0,0,ply:GetJumpPower()+70) end end if ply:KeyDown(IN_DUCK) then ply.VelocityMod = (fwdvec*(ply.VelocityMod:Length()/2)) + ply.VelocityMod:Normalize() end data:SetVelocity(gravity+ply.VelocityMod) return true end [/lua] And as for think: [lua] function GM:PlayerThink(ply) if ply:IsValid() and ply:Alive() then if ply.viewer and ply.viewer:IsValid() then if ply.FlippedNodes and ply.FlippedNodes == true then ply.FlippedNodes = false ply.viewer.NextNode,ply.viewer.LastNode = ply.viewer.LastNode,ply.viewer.NextNode end if ply.viewer.NextNode and ply.NodeChanged and ply.NodeChanged == true then ply.NodeChanged = false if ply.Reversed and ply.Reversed == true then ply.viewer.LastNode = ply.viewer.CurrentNode ply.viewer.CurrentNode = ply.viewer.NextNode if GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) then ply.viewer.NextNode = GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) else ply.viewer.NextNode = self.ViewStart end else ply.viewer.LastNode = ply.viewer.CurrentNode ply.viewer.CurrentNode = ply.viewer.NextNode if ply.viewer.CurrentNode["target"] and ply.viewer.CurrentNode["target"] != "" then ply.viewer.NextNode = ents.FindByName(ply.viewer.CurrentNode["target"])[1] else ply.viewer.NextNode = self.ViewEnd end end elseif ply.viewer.LastNode and ply.viewer.LastNode:GetName() != ply.viewer.CurrentNode:GetName() and ply.ReverseNodeChanged and ply.ReverseNodeChanged == true then ply.viewer.NextNode,ply.viewer.CurrentNode = ply.viewer.CurrentNode,ply.viewer.NextNode ply.viewer.LastNode = GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) end end if ply.NextNode and ply:GetPos():Distance(ply.NextNode:GetPos()) <= 50 then --value subject to change. if ply.Reversed and ply.Reversed == true then ply.LastNode = ply.CurrentNode ply.CurrentNode = ply.NextNode if GetPathEntityByTarget(ply.CurrentNode:GetName()) then ply.NextNode = GetPathEntityByTarget(ply.CurrentNode:GetName()) else ply.NextNode = self.PlayerStart ply:Lock() if (not ply.Finished) or ply.Finished != true then ply.Finished = true self:ReturnedToStart(ply) end end else ply.LastNode = ply.CurrentNode ply.CurrentNode = ply.NextNode if ply.CurrentNode["target"] and ply.CurrentNode["target"] != "" then ply.NextNode = ents.FindByName(ply.CurrentNode["target"])[1] else ply.NextNode = self.PlayerEnd ply:Lock() if (not ply.Finished) or ply.Finished != true then ply.Finished = true self:FinnishedLevel(ply) end end end ply:SetPos(Vector(ply.CurrentNode:GetPos().x,ply.CurrentNode:GetPos().y,ply:GetPos().z+5)) ply.NodeChanged = true end if (ply.ReverseNodeChanged == true) then ply.ReverseNodeChanged = false ply.NextNode,ply.CurrentNode = ply.CurrentNode,ply.NextNode ply.LastNode = GetPathEntityByTarget(ply.CurrentNode:GetName()) if ply.Reversed then ply.Reversed = !ply.Reversed else ply.Reversed = true end end if ply.Reversed == true and ply.pitch then ply:SetEyeAngles(Angle(math.Clamp(math.NormalizeAngle(tonumber(ply.pitch) + 180)*-1,-60,50),(ply.NextNode:GetPos()-ply:GetPos()):Angle().y,0)) elseif ply.pitch then ply:SetEyeAngles(Angle(math.Clamp(tonumber(ply.pitch),-60,50),(ply.NextNode:GetPos()-ply:GetPos()):Angle().y,0)) else ply:SetEyeAngles(Angle(ply:EyeAngles().p,(ply.NextNode:GetPos()-ply:GetPos()):Angle().y,0)) end if ply.viewer and ply.viewer:IsValid() then if ply.FlippedNodes and ply.FlippedNodes == true then ply.FlippedNodes = false ply.viewer.NextNode,ply.viewer.LastNode = ply.viewer.LastNode,ply.viewer.NextNode end if ply.viewer.NextNode and ply.NodeChanged and ply.NodeChanged == true then ply.NodeChanged = false if ply.Reversed and ply.Reversed == true then ply.viewer.LastNode = ply.viewer.CurrentNode ply.viewer.CurrentNode = ply.viewer.NextNode if GetPathEntityByTarget(ply.viewer.CurrentNode:GetName()) then ply.viewer.NextNode =
I'm positive you can find how the fellows at Noxious Net managed to make a side-scrolling gamemode like this one: [url=http://www.garrysmod.org/downloads/?a=view&id=76122][img]http://www.garrysmod.org/img/?t=dll&id=76122[/img][/url] I did a cursory search of the code and couldn't find anything meaningful, but who knows.
I don't want a side-scroller though. :v: I've been messing around with GM:Move() lately, with no luck at all.
Movement limited to one axis? MarioBoxes uses nodraw brushes I think. Just look at one of the maps.
[QUOTE=braxus;17776575]Movement limited to one axis? MarioBoxes uses nodraw brushes I think. Just look at one of the maps.[/QUOTE] Well, I need to be able to change the axis.
Not quite sure what you meen, but maybe you want to look into [url=http://en.wikipedia.org/wiki/Vector_projection]projection[/url]. [editline]06:42PM[/editline] [QUOTE=grea$emonkey;17568883] [list]Movement limited to one axis. [img]http://img169.imageshack.us/img169/4710/diagram2.png[/img] [/list][/QUOTE] But that's two axises:tinfoil:
I don't know...perhaps you can use variables and if it's the time you want them to go through or whatever a certain axis then set it to 1 and else make them collide with the brush or something...
Well, right now I've gotten almost everything working. I just need to make a way to stop the player from continuing to go up or to the side when a wall is about to end. Are traces a good way to do that? [editline]12:46PM[/editline] Or is there a less expensive way?
Sorry, you need to Log In to post a reply to this thread.