• Simulated Physics
    22 replies, posted
I asked in the newbie questions forum, but since this apparently is not simple I'll ask here. Right now I'm using [b][url=wiki.garrysmod.com/?title=PhysObj.ComputeShadowControl]PhysObj.ComputeShadowControl [img]http://wiki.garrysmod.com/favicon.ico[/img][/url][/b] inside of the [b][url=wiki.garrysmod.com/?title=ENT.PhysicsSimulate]ENT.PhysicsSimulate [img]http://wiki.garrysmod.com/favicon.ico[/img][/url][/b] hook. Here's what I'm trying to do: My SENT is like a vehicle of sorts, but it cruises at a set distance above the ground, except when it goes off of ledges, in which case you can glide (fly). Right now I'm working on the cruising aspect. The SENT has several variables that alter how the movement works. [list] [*][b]Speed[/b] This is the constant speed that the entity tries to achieve unless told otherwise. [*][b]Acceleration[/b] This is in units per second. It does not effect the enitity's speed after it has reached its desired speed. [*][b]Turn[/b] This is how fast the entity turns when the player presses their strafe keys. It is in degrees per second. [*][b]Handling[/b] This is where things get tricky. I'll try and explain this as best I can. Handling determines how quickly the current move vector changes to the one that the player is trying to move in based on current speed. The turn variable and the handling variable do not effect one another, but they do combine to represent the control the player has over the vehicle. In other words, Turn + Handling = Control. [b]Here are some examples of how this would work:[/b] [list][*]High turn + low handling = Spinning around when turning while sliding in your current move vector. [*]Low turn + high handling = Very gradual turning. [*]High turn + high handling = Moving and turning exactly where you intend to. [*]Low turn + low handling = No control at all.[/list] Most of the time, the mix will be somewhere in between. I'm just using extremes so you get the picture. [*][b]Glide[/b] This one is dependant on the input of the forward/back keys. Forward means aim down, back means aim up. The number here determines how high and far we can glide, the degrees of pitch change per second, the maximum upward pitch before no longer travelling forward and up, our speed and acceleration in air, and the amount of time it takes before descent. All of this is also in direct relation to the previous values presented. [/list] Now that you understand the issue (I hope), it's time for the math, which is what I suck at. Here's what I have so far: [lua] function ENT:PhysicsSimulate( phys, delta ) phys:Wake() local ply = self.Rider -- Our player controlling the SENT local turn, speed if self.Rider then turn, speed = --This is what I need to find... else return SIM_NOTHING end local accel = 5 --Our acceleration local maxspeed = 25 --Our speed local curvec = speed or self:GetVelocity() --Our current speed if curvec:Length() >= maxspeed then accel = 1 end local newpos = (curvec*delta) + speed * (0.5 * accel * (delta^2)) --Our next position to move to local dist = (self:GetPos() - newpos):Length() local sta = self:GetVelocity():Length()/dist --seconds to arrive self.ShadowParams.secondstoarrive = sta // How long it takes to move to pos and rotate accordingly - only if it _could_ move as fast as it want - damping and max speed/angular will make this invalid (Cannot be 0! Will give errors if you do) self.ShadowParams.pos = newpos // Where you want to move to self.ShadowParams.angle = turn // Angle you want to move to self.ShadowParams.maxangular = 1 // What should be the maximal angular force applied self.ShadowParams.maxangulardamp = 3 // At which force/speed should it start damping the rotation self.ShadowParams.maxspeed = 4 // Maximal linear force applied self.ShadowParams.maxspeeddamp = 5 // Maximal linear force/speed before damping self.ShadowParams.dampfactor = 0.8 // The percentage it should damp the linear/angular force if it reaches it's max amount self.ShadowParams.teleportdistance = 0 // If it's further away than this it'll teleport (Set to 0 to not teleport) self.ShadowParams.deltatime = deltatime // The deltatime it should use - just use the PhysicsSimulate one phys:ComputeShadowControl(self.ShadowParams) end [/lua] In short, none of this works yet. I haven't a clue as to how to make all of the ShadowParams work cohesively. Anyone know how I can achieve this kind of movement I've described?
This sounds like a Jet Moto type of device. I wanted to make this work within e2.
[QUOTE=evan_madore;20035454]This sounds like a Jet Moto type of device. I wanted to make this work within e2.[/QUOTE] It's for a gamemode I'm making. I can't really release any more information until I have this done though.
So you want to figure out what angle the 'ship' is to move to? How will the player be controlling the direction? Pointing the mouse? Keyboard? (using the mouse would be the most simple way imo) More details :D
[QUOTE=MGinshe;20036315]So you want to figure out what angle the 'ship' is to move to? How will the player be controlling the direction? Pointing the mouse? Keyboard? (using the mouse would be the most simple way imo) More details :D[/QUOTE] Read it. I said it's controlled by the WASD keys (i.e. Strafe and forward/back).
[QUOTE=grea$emonkey;20036335]Read it. I said it's controlled by the WASD keys (i.e. Strafe and forward/back).[/QUOTE] Damnit, should have read that a little better. And let me get this a little clearer about the turning control. One of the values is how fast you turn, one of them is how accurately that turn is (so holding left strafe with a low Handling would end up in you turning too far)
[QUOTE=MGinshe;20036397]Damnit, should have read that a little better. And let me get this a little clearer about the turning control. One of the values is how fast you turn, one of them is how accurately that turn is (so holding left strafe with a low Handling would end up in you turning too far)[/QUOTE] Think of it like this. A car is speeding down a highway and does a sharp turn. If handling is low on this car, it spins out of control until its speed is low enough to get back into control. If the handling is high, the car will basically turn and move exactly where it was meant to.
So maybe something like: [lua] function Turning() if( TurnValueBlah ) then // something unique, so as not to conflict. make sure turnvalueblah is actually existant if( ply:KeyDown( side ) ) then TurnValueBlah = TurnValueBlah + ((TurnValueBlah+TurningSpeed)/Handeling) // So the longer we hold the key down, the faster we turn if( TurnValueBlah > MaxTurnSpeed ) then TurnValueBlah = MaxTurnSpeed end elseif( ply:KeyDown( otherside ) ) then TurnValueBlah = TurnValueBlah - ((TurnValueBlah+TurningSpeed)/Handeling) // So the longer we hold the key down, the faster we turn if( TurnValueBlah < MinTurnSpeed ) then TurnValueBlah = MinTurnSpeed end elseif( !ply:KeyDown( side ) and !ply:KeyDown( otherside ) ) then if( TurnValueBlah > 1 ) then // we have turned in one direction TurnValueBlah = TurnValueBlah - ((TurnValueBlah+TurningSpeed)/Handeling) elseif( TurningSpeed < -1 ) then TurnValueBlah = TurnValueBlah + ((TurnValueBlah+TurningSpeed)/Handeling) end end end TurnAngleBlah = Angle( TurnAngleBlah.p, TurnAngleBlah.y, TurnAngleBlah.r ) // you would add TurnValBlah to the pitch, yaw, or roll (i forget which order they go in, and which one controll rotation on the axis you want) return TurnAngleBlah end [/lua] And yes, im tired too. You kinda get the point from the pseudo code. It might work, but as i said, im tired.. So thats my excuse.
I'm about to fall asleep. If I don't reply soon after you post code, it means I'll be back in 8 or 10 hours. :smile: [editline]02:58AM[/editline] [QUOTE=MGinshe;20036437]-snip-[/QUOTE] What?
Gah, stupid laptop fucked all the tabbing up :/ [editline]07:16PM[/editline] I suppose that means you went off. At least now i have time to make something decent :D [editline]09:05PM[/editline] ~130 views and im the only post?
It sounds very much like you should just look into how wings work (and a glider is essentially just a wing), check the wing-stool or some of the wings made in e2 (although I'm not sure if people ever released those). Most of this can be faked pretty easily, but getting the right feel requires that you do look into how wings work, shouldn't be terribly complicated.
Here's a basic code that half worked. The effect I was going for was the ability to hover above any surface (caused me a lot of pain). [lua]function ENT:PhysicsSimulate( phys, deltatime ) if self.OnTrack and self.Pilot and self.InFlight and self.OnTrack then local track = nil for _,v in ipairs(ents.FindInSphere(self.Entity:GetPos(),200)) do if v:GetClass() == "env_track" then track = v end end local tracktr = util.TraceLine({start = self.Entity:GetPos(),endpos = self.Entity:GetPos() - self.Entity:GetUp() * 300,filter=self.Entity}) if !track or track.Entity != track then return end phys:Wake() if self.Pilot:KeyDown(IN_FORWARD) then self.Accel = math.Approach(self.Accel,1000,2.5) elseif self.Pilot:KeyDown(IN_BACK) then self.Accel = math.Approach(self.Accel,-1000,-2.5) else if self.Accel > 0 then self.Accel = math.Approach(self.Accel,0,-4.5) else self.Accel = math.Approach(self.Accel,0,4.5) end end local pr={} pr.secondstoarrive = 0.5; pr.pos = tracktr.HitPos + tracktr.HitNormal * 100 + self.Entity:GetForward()*self.Accel pr.maxangular = 20000; pr.maxangulardamp = 50; pr.maxspeed = 1000000; pr.maxspeeddamp = 500000; pr.dampfactor = 1; pr.teleportdistance = 5000; local fwd = self.Entity:GetForward() local hit = tracktr.HitNormal /* if self.LastNormal != hit:Angle() and CurTime() - self.NormalWait > 1 then self.LastNormal = hit:Angle() self.Angle = hit:Angle() self.NormalWait = CurTime() elseif CurTime() - self.NormalWait < 1 then self.Angle = hit:Angle() end */ if self.Pilot:KeyDown(IN_MOVERIGHT) then self.AngInc = self.AngInc + 1 pr.pos = pr.pos + self.Entity:GetRight() * 150 elseif self.Pilot:KeyDown(IN_MOVELEFT) then self.AngInc = self.AngInc - 1 pr.pos = pr.pos - self.Entity:GetRight() * 150 end self.Angle = hit:Angle() self.Angle.y = self.Entity:GetAngles().y self.Angle.pitch = self.Angle.pitch - 270 // self.Angle = self.Angle + self.Entity:GetRight() * self.AngInc pr.angle = self.Angle pr.deltatime = deltatime phys:ComputeShadowControl(pr) end end [/lua]
[QUOTE=MGinshe;20036437]So maybe something like: And yes, im tired too. You kinda get the point from the pseudo code. It might work, but as i said, im tired.. So thats my excuse.[/QUOTE] I'll have to try that. [QUOTE=Syranide;20039317]It sounds very much like you should just look into how wings work (and a glider is essentially just a wing), check the wing-stool or some of the wings made in e2 (although I'm not sure if people ever released those). Most of this can be faked pretty easily, but getting the right feel requires that you do look into how wings work, shouldn't be terribly complicated.[/QUOTE] Well, gliding for this is really more like a limited form of flying. [QUOTE=Entoros;20039949]Here's a basic code that half worked. The effect I was going for was the ability to hover above any surface (caused me a lot of pain).[/QUOTE] The main issue I'm having is making it move forward, and combining turning/handling. I can see a lot of stuff you're not utilizing in there. You could be smoothly changing the angles with shadowcontrol, and you shouldn't need a trace for this.
Here's my new code: [lua] function ENT:CalcSpeed() local dSpeed = self.DesiredSpeed --This is our top speed local cSpeed = self:GetVelocity():Length() --This is our current speed local Accel = self.Acceleration --This is the time it takes to get there local newSpeed = cSpeed if (cSpeed < dSpeed) then newSpeed = cSpeed + ( cSpeed * (Accel/dSpeed) ) else newSpeed = dSpeed end if !self.Damaged and self.Cruising then end return newSpeed end function ENT:CalcMove() if !self.Rider then return false end local ply = self.Rider local doDismount = ( ply:KeyDown( IN_BACK ) and ply:KeyDown( IN_JUMP ) and true ) if doDismount then self:Dismount() end local turnDir = ( ply:KeyDown( IN_MOVELEFT ) and -1 ) or ( ply:KeyDown( IN_MOVERIGHT ) and 1 ) or 0 -- Left, right, or straight? local glideDir = ( ply:KeyDown( IN_BACK ) and 1 ) or ( ply:KeyDown( IN_FORWARD ) and -1 ) or 0 -- Up, down, or level? local traceGroundNorm = util.QuickTrace( self.Entity:GetPos(), self.Entity:GetPos() + vector_up * -self.Hover, { self, ply } ) -- Trace the ground if traceGroundNorm.Hit then self.Cruising = true else self.Gliding = true end local normAng = traceGroundNorm.HitNormal:Angle() or Angle(0,0,0) -- The angle of the normalized vector of the ground // Values to clamp our rotations by local pitchLimit = 15 + ( (self.Gliding and 60) or 0 ) -- If we are _, our _ limit will be _ local yawLimit = 45 + ( (self.Cruising and 45) or 0 ) -- If we are _, our _ limit will be _ local rollLimit = 35 + ( (self.Gliding and 55) or 0 ) -- If we are _, our _ limit will be _ local glideDeg = math.Clamp( ( self.TurnPower * glideDir ), -pitchLimit, pitchLimit ) -- Our pitch (up/down) local turnDeg = math.Clamp( ( self.TurnPower * turnDir ), -yawLimit, yawLimit ) -- Our yaw (left/right) local tiltDeg = math.Clamp( ( self.TurnPower * turnDir ), -rollLimit, rollLimit ) -- Our roll (left/right) //local curAngles = self.Entity:GetAngles() local turnAng = self.Entity:GetAngles() if turnDir == 0 then turnAng = self.Entity:GetAng // Modify our angles turnAng:RotateAroundAxis( self.Entity:GetAngles():Forward(), glideDeg ) -- This should modify our pitch to what we want. turnAng:RotateAroundAxis( self.Entity:GetAngles():Up(), turnDeg ) -- This should modify our yaw to what we want. turnAng:RotateAroundAxis( self.Entity:GetAngles():Right(), tiltDeg ) -- This should modify our roll to what we want. turnAng = turnAng + normAng local desiredVec = turnAng:Forward() * self:CalcSpeed() local currentVec = self.Entity:GetVelocity() // Our newVec is what will come out as the final move vector; handlingVec is a vector added/subtracted by our current and desired vectors local newVec, handlingVec = Vector(), Vector(1, 1, 1) * self.Handling local currentVec, desiredVec = self.Entity:GetVelocity(), self.Entity:GetAngles():Forward() // Here is the part that's supposed to make the machine slide when trying to turn currentVec = currentVec - (handlingVec * turnDir) desiredVec = desiredVec + (handlingVec * turnDir) newVec = desiredVec newVec.z = ( ( !self.Gliding and !self.Charging ) and traceGroundNorm.HitNormal * 5 ) or newVec.z return newVec, turnAng end function ENT:PhysicsSimulate(phys, delta) phys:Wake() local moveVec, moveAng -- Define our values if self.Rider then moveVec, moveAng = self:CalcMove() -- Set our values if we have a rider else return SIM_NOTHING -- Otherwise we don't do anything end local speed = self:CalcSpeed() moveVec = moveVec * speed local newPos = (moveVec * delta) //+ self:GetVelocity():Length() * (0.5 * self.Acceleration * (delta^2)) --Our next position to move to --print(tostring(newPos)) --self.ShadowParams.secondstoarrive = 1 // How long it takes to move to pos and rotate accordingly - only if it _could_ move as fast as it want - damping and max speed/angular will make this invalid (Cannot be 0! Will give errors if you do) self.ShadowParams.pos = newPos // Where you want to move to self.ShadowParams.angle = moveAng // Angle you want to move to self.ShadowParams.maxangular = 1000 // What should be the maximal angular force applied self.ShadowParams.maxangulardamp = 1000 // At which force/speed should it start damping the rotation self.ShadowParams.maxspeed = 1000 // Maximal linear force applied self.ShadowParams.maxspeeddamp = 1000*2 // Maximal linear force/speed before damping self.ShadowParams.dampfactor = 0.8 // The percentage it should damp the linear/angular force if it reaches it's max amount self.ShadowParams.teleportdistance = 0 // If it's further away than this it'll teleport (Set to 0 to not teleport) self.ShadowParams.deltatime = deltatime // The deltatime it should use - just use the PhysicsSimulate one phys:ComputeShadowControl(self.ShadowParams) end [/lua] I tried doing a total rewrite. It doesn't work, but it's getting closer. Problems: -It always moves to Vector(0,0,0). -When turning, it sets the angles in comparison to one another. In other words, it changes pitch, then changes yaw in comparison to that, and then changes roll in comparison to that. -Since it isn't going anywhere, I can't tell whether handling works, but I'm pretty sure it doesn't.
Don't mean to be nit picky, but the var on line 29 could be thrown into the if on 31, instead of making a var (even if it is local)
[QUOTE=MGinshe;20054605]Don't mean to be nit picky, but the var on line 29 could be thrown into the if on 31, instead of making a var (even if it is local)[/QUOTE] Right. Forgot. Did a lot of copy-pasta. That still does not solve my problem.
I understand that I am not contributing anything to help your problem, grea$emonkey, but your OP has a typo in it. What it is now: [QUOTE] [LIST] [*]High turn + low handling = Spinning around when turning while sliding in your current move vector. [*]Low turn + high handling = Very gradual turning. [*]High turn + high handling = Moving and turning exactly where you intend to. [*]Low turn + high handling = No control at all. [/LIST][/QUOTE] What it [I]Should[/I] be: [QUOTE] [LIST] [*]High turn + low handling = Spinning around when turning while sliding in your current move vector. [*]Low turn + [B][I]LOW[/I][/B] handling = Very gradual turning. [*]High turn + high handling = Moving and turning exactly where you intend to. [*]Low turn + high handling = No control at all. [/LIST][/QUOTE] I am sorry for being so anal about this. I just got confused and thought I should try to fix the problem.
[QUOTE=XavierStudios;20081474]I understand that I am not contributing anything to help your problem, grea$emonkey, but your OP has a typo in it. What it is now: What it [I]Should[/I] be: I am sorry for being so anal about this. I just got confused and thought I should try to fix the problem.[/QUOTE] Actually, Low turn + low handling would be almost the same as low turn + high handling, except the first one would slide around more. There [i]is[/i] a difference. Turning and handling are two separate things, but they act on one another to create a general concept of [i]control[/i]. But you're right, the last one was a typo, not the second one.
[QUOTE=grea$emonkey;20082398]Actually, Low turn + low handling would be almost the same as low turn + high handling, except the first one would slide around more. There [I]is[/I] a difference. Turning and handling are two separate things, but they act on one another to create a general concept of [I]control[/I].[/QUOTE] My bad, it's just you had low turn + high handling twice which confused me. You win this round. Well played.
Anyways, it has started to work. I recoded it, but it is a little funky. Very hard to describe what it's doing wrong. [editline]02:22PM[/editline] [QUOTE=XavierStudios;20082475]My bad, it's just you had low turn + high handling twice which confused me. You win this round. Well played.[/QUOTE] Thanks.
Upload the vid :) Easier to see the problem if we can well.. see it..
[QUOTE=MGinshe;20097602]Upload the vid :) Easier to see the problem if we can well.. see it..[/QUOTE] Well that's just it, sometimes it works and sometimes it won't. I think most of the problems have to do with angles. If you don't fully understand angles, I found these flight dynamics pictures very useful: Pitch: Aiming up/down [img_thumb]http://upload.wikimedia.org/wikipedia/commons/4/48/Aptch.gif[/img_thumb] Yaw: Turning left/right [img_thumb]http://upload.wikimedia.org/wikipedia/commons/c/c5/Ayaw.gif[/img_thumb] Roll: Tilting from side-to-side (i.e. Do a barrel [i]roll[/i]) [img_thumb]http://upload.wikimedia.org/wikipedia/commons/c/cc/Aileron_roll.gif[/img_thumb] Here is what needs to be fixed: [list] This SENT uses the normal of the ground below it to determine a lot of things. This does not appear to be working. [list][*]It is supposed to hover at a vector only a little bit above the ground using the normal. It seems to hover at the Z height of Vector(0,0,0) when I'm trying to use a vector that's 5 units about current ground height. [*]I need this thing to stay roughly upright based on the angle of the ground below it. That means I need to use the ground normal as a reference point for pitch and roll.[/list] [/list] [list] Movement is acting funky. [list][*]For some reason it moves in the forward direction my pitch is pointing in. Pitch shouldn't be doing anything until I get gliding done. Could be that as soon as it spawns, it's pitch (or maybe it's the roll) turns about 90 degrees. I think that is due to my angle:RotateAroundAxis() is set up wrong. [*]Turning yaw doesn't seem to point me where I want to go. I can't really explain this with words or a video. [*]Turning roll is not working how I want it to. Since roll effects yaw and not pitch, it makes the angles really weird. Basically, the roll can turn this thing upside down if I let it.[/list] [/list] [list] Some stuff that still needs to be scripted: [list][*]Acceleration. [*]Handling. [*]Gliding. [*]I'm probably forgetting something...[/list] [/list] I also want to change some collision stuff. The best way I can describe this is that I want it to kinda work like a player's collisions, but with more of a bounce. When this thing hits a wall, it kinda sticks to it. I want collisions to be sort of like that of a bounding box, except it doesn't get stuck in corners. It should be able to easily turn around when its against a wall.
[url=http://luabin.foszor.com/code/gamemodes/base/entities/entities/base_anim/init.lua#55]Evilness[/url] You should look into the [url=http://www.facepunch.com/showthread.php?t=484237]hoverboard[/url], it uses PhysicsSimulate
Sorry, you need to Log In to post a reply to this thread.