From 9cfa745b01ecaa94ec6ab94ea0fc14529e998c9b Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 31 Mar 2023 12:03:47 -0700 Subject: [PATCH 1/4] Support multiple player sizes dynamically --- .../customclient/Characters/NicerHumanoid.lua | 3 +- src/Simulation/CollisionModule.lua | 31 +++++++++---------- src/Simulation/init.lua | 16 +++++----- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/example/customclient/Characters/NicerHumanoid.lua b/example/customclient/Characters/NicerHumanoid.lua index ff63121..6bcbc5c 100644 --- a/example/customclient/Characters/NicerHumanoid.lua +++ b/example/customclient/Characters/NicerHumanoid.lua @@ -31,5 +31,4 @@ function module:GetCharacterModel(userId) end -return module - +return module \ No newline at end of file diff --git a/src/Simulation/CollisionModule.lua b/src/Simulation/CollisionModule.lua index 8e245c5..3d79e3e 100644 --- a/src/Simulation/CollisionModule.lua +++ b/src/Simulation/CollisionModule.lua @@ -255,7 +255,8 @@ function module:FetchHullsForPoint(point) return hullRecords end -function module:FetchHullsForBox(min, max) +function module:FetchHullsForBox(min, max, playerSize) + local fetchExpansionSize = playerSize or module.expansionSize local minx = min.x local miny = min.y local minz = min.z @@ -347,13 +348,10 @@ function module:FetchHullsForBox(min, max) --Inflate missing hulls for key,record in pairs(hullRecords) do - if (record.hull == nil) then - record.hull = self:GenerateConvexHullAccurate(record.instance, module.expansionSize, self:GenerateSnappedCFrame(record.instance)) - if (record.hull == nil) then - hullRecords[key] = nil - end - end + record.hull = {} + end + record.hull[fetchExpansionSize] = self:GenerateConvexHullAccurate(record.instance, fetchExpansionSize, self:GenerateSnappedCFrame(record.instance)) end @@ -512,10 +510,10 @@ function module:SimpleRayTest(a, b, hull) return tfirst, tlast end -function module:CheckBrushPoint(data, hullRecord) +function module:CheckBrushPoint(data, hullRecord, playerSize) local startsOut = false - for _, p in pairs(hullRecord.hull) do + for _, p in pairs(hullRecord.hull[playerSize]) do local startDistance = data.startPos:Dot(p.n) - p.ed if startDistance > 0 then @@ -534,14 +532,14 @@ function module:CheckBrushPoint(data, hullRecord) end --Checks a brush, but doesn't handle it well if the start point is inside a brush -function module:CheckBrush(data, hullRecord) +function module:CheckBrush(data, hullRecord, playerSize) local startFraction = -1.0 local endFraction = 1.0 local startsOut = false local endsOut = false local lastPlane = nil - for _, p in pairs(hullRecord.hull) do + for _, p in pairs(hullRecord.hull[playerSize]) do local startDistance = data.startPos:Dot(p.n) - p.ed local endDistance = data.endPos:Dot(p.n) - p.ed @@ -608,7 +606,7 @@ function module:CheckBrush(data, hullRecord) end --Checks a brush, but is smart enough to ignore the brush entirely if the start point is inside but the ray is "exiting" or "exited" -function module:CheckBrushNoStuck(data, hullRecord) +function module:CheckBrushNoStuck(data, hullRecord, playerSize) local startFraction = -1.0 local endFraction = 1.0 local startsOut = false @@ -618,7 +616,7 @@ function module:CheckBrushNoStuck(data, hullRecord) local nearestStart = -math.huge local nearestEnd = -math.huge - for _, p in pairs(hullRecord.hull) do + for _, p in pairs(hullRecord.hull[playerSize]) do local startDistance = data.startPos:Dot(p.n) - p.ed local endDistance = data.endPos:Dot(p.n) - p.ed @@ -711,7 +709,8 @@ function module:PlaneLineIntersect(normal, distance, V1, V2) return (V1 + u * (V2 - V1)) end -function module:Sweep(startPos, endPos) +function module:Sweep(startPos, endPos, playerSize) + playerSize = playerSize or module.expansionSize local data = {} data.startPos = startPos data.endPos = endPos @@ -734,7 +733,7 @@ function module:Sweep(startPos, endPos) if (self.profile == true) then debug.profilebegin("Fetch") end - local hullRecords = self:FetchHullsForBox(startPos, endPos) + local hullRecords = self:FetchHullsForBox(startPos, endPos, playerSize) if (self.profile==true) then debug.profileend() end @@ -745,7 +744,7 @@ function module:Sweep(startPos, endPos) for _, hullRecord in pairs(hullRecords) do data.checks += 1 - if (hullRecord.hull ~= nil) then + if (hullRecord.hull[playerSize] ~= nil) then self:CheckBrushNoStuck(data, hullRecord) if data.allSolid == true then data.fraction = 0 diff --git a/src/Simulation/init.lua b/src/Simulation/init.lua index ef49a59..3ee2526 100644 --- a/src/Simulation/init.lua +++ b/src/Simulation/init.lua @@ -37,7 +37,7 @@ function Simulation.new(userId) self.state.jumpThrust = 0 self.state.pushing = 0 --External flag comes from server (ungh >_<') self.state.moveState = 0 --Walking! - + self.state.playerSize = Vector3.new(3, 5, 3) self.characterData = CharacterData.new() @@ -240,14 +240,14 @@ function Simulation:DoStepUp(pos, vel, deltaTime) local stepVec = Vector3.new(0, self.constants.stepSize, 0) --first move upwards as high as we can go - local headHit = CollisionModule:Sweep(pos, pos + stepVec) + local headHit = CollisionModule:Sweep(pos, pos + stepVec, self.state.playerSize) --Project forwards local stepUpNewPos, stepUpNewVel, _stepHitSomething = self:ProjectVelocity(headHit.endPos, flatVel, deltaTime) --Trace back down local traceDownPos = stepUpNewPos - local hitResult = CollisionModule:Sweep(traceDownPos, traceDownPos - Vector3.new(0, self.constants.aggressiveStep, 0)) + local hitResult = CollisionModule:Sweep(traceDownPos, traceDownPos - Vector3.new(0, self.constants.aggressiveStep, 0), self.state.playerSize) stepUpNewPos = hitResult.endPos @@ -276,7 +276,7 @@ end --Magic to stick to the ground instead of falling on every stair function Simulation:DoStepDown(pos) local stepVec = Vector3.new(0, self.constants.stepSize, 0) - local hitResult = CollisionModule:Sweep(pos, pos - stepVec) + local hitResult = CollisionModule:Sweep(pos, pos - stepVec, self.state.playerSize) if hitResult.startSolid == false @@ -308,7 +308,7 @@ function Simulation:DecayStepUp(deltaTime) end function Simulation:DoGroundCheck(pos) - local results = CollisionModule:Sweep(pos + Vector3.new(0, 0.1, 0), pos + Vector3.new(0, -0.1, 0)) + local results = CollisionModule:Sweep(pos + Vector3.new(0, 0.1, 0), pos + Vector3.new(0, -0.1, 0), self.state.playerSize) if results.allSolid == true or results.startSolid == true then --We're stuck, pretend we're in the air @@ -345,7 +345,7 @@ function Simulation:ProjectVelocity(startPos, startVel, deltaTime) end --We only operate on a scaled down version of velocity - local result = CollisionModule:Sweep(movePos, movePos + (moveVel * timeLeft)) + local result = CollisionModule:Sweep(movePos, movePos + (moveVel * timeLeft), self.state.playerSize) --Update our position if result.fraction > 0 then @@ -393,7 +393,7 @@ function Simulation:CheckGroundSlopes(startPos) local moveDir = Vector3.new(0,-1,0) --We only operate on a scaled down version of velocity - local result = CollisionModule:Sweep(movePos, movePos + moveDir) + local result = CollisionModule:Sweep(movePos, movePos + moveDir, self.state.playerSize) --Update our position if result.fraction > 0 then @@ -414,7 +414,7 @@ function Simulation:CheckGroundSlopes(startPos) end --Try and move it - local result = CollisionModule:Sweep(movePos, movePos + moveDir) + local result = CollisionModule:Sweep(movePos, movePos + moveDir, self.state.playerSize) if (result.fraction == 0) then return true --stuck end From 4eef61cfd7dd8dbe4ce957df5af586fe0f1b8ad3 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 31 Mar 2023 12:25:40 -0700 Subject: [PATCH 2/4] Added `playerSize` field to more check methods --- src/Simulation/CollisionModule.lua | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Simulation/CollisionModule.lua b/src/Simulation/CollisionModule.lua index 3d79e3e..c3c665f 100644 --- a/src/Simulation/CollisionModule.lua +++ b/src/Simulation/CollisionModule.lua @@ -745,7 +745,7 @@ function module:Sweep(startPos, endPos, playerSize) data.checks += 1 if (hullRecord.hull[playerSize] ~= nil) then - self:CheckBrushNoStuck(data, hullRecord) + self:CheckBrushNoStuck(data, hullRecord, playerSize) if data.allSolid == true then data.fraction = 0 break @@ -763,14 +763,15 @@ function module:Sweep(startPos, endPos, playerSize) if data.fraction >= SKIN_THICKNESS or data.allSolid == false then for _, hullRecord in pairs(self.dynamicRecords) do data.checks += 1 - - self:CheckBrushNoStuck(data, hullRecord) - if data.allSolid == true then - data.fraction = 0 - break - end - if data.fraction < SKIN_THICKNESS then - break + if (hullRecord.hull[playerSize] ~= nil) then + self:CheckBrushNoStuck(data, hullRecord, playerSize) + if data.allSolid == true then + data.fraction = 0 + break + end + if data.fraction < SKIN_THICKNESS then + break + end end end end @@ -786,7 +787,8 @@ function module:Sweep(startPos, endPos, playerSize) return data end -function module:BoxTest(pos) +function module:BoxTest(pos, playerSize) + playerSize = playerSize or module.expansionSize local data = {} data.startPos = pos data.endPos = pos @@ -805,7 +807,7 @@ function module:BoxTest(pos) for _, hullRecord in pairs(hullRecords) do data.checks += 1 - self:CheckBrushPoint(data, hullRecord) + self:CheckBrushPoint(data, hullRecord, playerSize) if data.allSolid == true then data.fraction = 0 break From a038c9e524fa262c3d92c4733231ae1f3ab3c97d Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 31 Mar 2023 12:33:35 -0700 Subject: [PATCH 3/4] Added crouch support to example move type --- .../Characters/utils/MoveTypeWalking.luau | 126 ++++++++++-------- 1 file changed, 73 insertions(+), 53 deletions(-) diff --git a/example/customclient/Characters/utils/MoveTypeWalking.luau b/example/customclient/Characters/utils/MoveTypeWalking.luau index c0ab621..3063bc1 100644 --- a/example/customclient/Characters/utils/MoveTypeWalking.luau +++ b/example/customclient/Characters/utils/MoveTypeWalking.luau @@ -1,6 +1,7 @@ local module = {} local path = game.ReplicatedStorage.Shared.Chickynoid local MathUtils = require(path.Simulation.MathUtils) +local CollisionModule = require(path.Simulation.CollisionModule) local Enums = require(path.Enums) function module:Setup(simulation) @@ -12,19 +13,20 @@ function module:ModifySimulation(simulation) simulation:SetMoveState("Walking") simulation.state.up = Vector3.yAxis + simulation.state.crouching = false end -function module:ActiveThink(cmd) +function module:ActiveThink(simulation, cmd) --Check ground local onGround = nil - onGround = self:DoGroundCheck(self.state.pos) + onGround = self:DoGroundCheck(simulation.state.pos) --If the player is on too steep a slope, its not ground if (onGround ~= nil and onGround.normal.Y < self.constants.maxGroundSlope) then --See if we can move downwards? - if (self.state.vel.y < 0.1) then - local stuck = self:CheckGroundSlopes(self.state.pos) + if (simulation.state.vel.y < 0.1) then + local stuck = self:CheckGroundSlopes(simulation.state.pos) if (stuck == false) then --we moved, that means the player is on a slope and can free fall @@ -51,18 +53,36 @@ function module:ActiveThink(cmd) local wishDir = nil if cmd.x ~= 0 or cmd.z ~= 0 then wishDir = Vector3.new(cmd.x, 0, cmd.z).Unit - self.state.pushDir = Vector2.new(cmd.x, cmd.z) + simulation.state.pushDir = Vector2.new(cmd.x, cmd.z) else - self.state.pushDir = Vector2.new(0, 0) + simulation.state.pushDir = Vector2.new(0, 0) end --Create flat velocity to operate our input command on --In theory this should be relative to the ground plane instead... - local flatVel = MathUtils:FlatVec(self.state.vel) + local flatVel = MathUtils:FlatVec(simulation.state.vel) --Does the player have an input? if wishDir ~= nil then if onGround then + -- check crouching state + if cmd.y < 0 then + simulation.state.crouching = true + simulation.state.playerSize = Vector3.new(2, 2, 2) --could probably change this to a constant + elseif simulation.state.crouching then + + local headHit = CollisionModule:Sweep( --// check to see if player isn't currently under something + simulation.state.pos, + simulation.state.pos + Vector3.new(0, 3, 0), + Vector3.new(2, 5, 2) --could probably change this to a constant + ) + if not headHit.hullRecord then --// only stand up once cleared + simulation.state.crouching = false + simulation.state.playerSize = Vector3.new(2, 5, 2) --also could be a constant + simulation.state.pos = simulation.state.pos + Vector3.new(0, 3, 0) --/// pop player back up? + end + end + --Moving along the ground under player input flatVel = MathUtils:GroundAccelerate( @@ -74,7 +94,7 @@ function module:ActiveThink(cmd) ) --Good time to trigger our walk anim - if self.state.pushing > 0 then + if simulation.state.pushing > 0 then self.characterData:PlayAnimation(Enums.Anims.Push, Enums.AnimChannel.Channel0, false) else self.characterData:PlayAnimation(Enums.Anims.Walk, Enums.AnimChannel.Channel0, false) @@ -96,22 +116,22 @@ function module:ActiveThink(cmd) end --Turn out flatvel back into our vel - self.state.vel = Vector3.new(flatVel.x, self.state.vel.y, flatVel.z) + simulation.state.vel = Vector3.new(flatVel.x, simulation.state.vel.y, flatVel.z) --Do jumping? - if self.state.jump > 0 then - self.state.jump -= cmd.deltaTime - if self.state.jump < 0 then - self.state.jump = 0 + if simulation.state.jump > 0 then + simulation.state.jump -= cmd.deltaTime + if simulation.state.jump < 0 then + simulation.state.jump = 0 end end if onGround ~= nil then --jump! - if cmd.y > 0 and self.state.jump <= 0 then - self.state.vel = Vector3.new(self.state.vel.x, self.constants.jumpPunch, self.state.vel.z) - self.state.jump = 0.2 --jumping has a cooldown (think jumping up a staircase) - self.state.jumpThrust = self.constants.jumpThrustPower + if cmd.y > 0 and simulation.state.jump <= 0 then + simulation.state.vel = Vector3.new(simulation.state.vel.x, self.constants.jumpPunch, simulation.state.vel.z) + simulation.state.jump = 0.2 --jumping has a cooldown (think jumping up a staircase) + simulation.state.jumpThrust = self.constants.jumpThrustPower self.characterData:PlayAnimation(Enums.Anims.Jump, Enums.AnimChannel.Channel0, true, 0.2) end @@ -123,8 +143,8 @@ function module:ActiveThink(cmd) local vec3 = instance:GetAttribute("launch") if vec3 then local dir = instance.CFrame:VectorToWorldSpace(vec3) - self.state.vel = dir - self.state.jump = 0.2 + simulation.state.vel = dir + simulation.state.jump = 0.2 self.characterData:PlayAnimation(Enums.Anims.Jump, Enums.AnimChannel.Channel0, true, 0.2) end end @@ -133,42 +153,42 @@ function module:ActiveThink(cmd) --In air? if onGround == nil then - self.state.inAir += cmd.deltaTime - if self.state.inAir > 10 then - self.state.inAir = 10 --Capped just to keep the state var reasonable + simulation.state.inAir += cmd.deltaTime + if simulation.state.inAir > 10 then + simulation.state.inAir = 10 --Capped just to keep the state var reasonable end --Jump thrust if cmd.y > 0 then - if self.state.jumpThrust > 0 then - self.state.vel += Vector3.new(0, self.state.jumpThrust * cmd.deltaTime, 0) - self.state.jumpThrust = MathUtils:Friction( - self.state.jumpThrust, + if simulation.state.jumpThrust > 0 then + simulation.state.vel += Vector3.new(0, simulation.state.jumpThrust * cmd.deltaTime, 0) + simulation.state.jumpThrust = MathUtils:Friction( + simulation.state.jumpThrust, self.constants.jumpThrustDecay, cmd.deltaTime ) end - if self.state.jumpThrust < 0.001 then - self.state.jumpThrust = 0 + if simulation.state.jumpThrust < 0.001 then + simulation.state.jumpThrust = 0 end else - self.state.jumpThrust = 0 + simulation.state.jumpThrust = 0 end --gravity - self.state.vel += Vector3.new(0, self.constants.gravity * cmd.deltaTime, 0) + simulation.state.vel += Vector3.new(0, self.constants.gravity * cmd.deltaTime, 0) --Switch to falling if we've been off the ground for a bit - if self.state.vel.y <= 0.01 and self.state.inAir > 0.5 then + if simulation.state.vel.y <= 0.01 and simulation.state.inAir > 0.5 then self.characterData:PlayAnimation(Enums.Anims.Fall, Enums.AnimChannel.Channel0, false) end else - self.state.inAir = 0 + simulation.state.inAir = 0 end --Sweep the player through the world, once flat along the ground, and once "step up'd" local stepUpResult = nil - local walkNewPos, walkNewVel, hitSomething = self:ProjectVelocity(self.state.pos, self.state.vel, cmd.deltaTime) + local walkNewPos, walkNewVel, hitSomething = self:ProjectVelocity(simulation.state.pos, simulation.state.vel, cmd.deltaTime) --Did we crashland if onGround == nil and hitSomething == true then @@ -182,27 +202,27 @@ function module:ActiveThink(cmd) end -- Do we attempt a stepup? (not jumping!) - if onGround ~= nil and hitSomething == true and self.state.jump == 0 then - stepUpResult = self:DoStepUp(self.state.pos, self.state.vel, cmd.deltaTime) + if onGround ~= nil and hitSomething == true and simulation.state.jump == 0 then + stepUpResult = self:DoStepUp(simulation.state.pos, simulation.state.vel, cmd.deltaTime) end --Choose which one to use, either the original move or the stepup if stepUpResult ~= nil then - self.state.stepUp += stepUpResult.stepUp - self.state.pos = stepUpResult.pos - self.state.vel = stepUpResult.vel + simulation.state.stepUp += stepUpResult.stepUp + simulation.state.pos = stepUpResult.pos + simulation.state.vel = stepUpResult.vel else - self.state.pos = walkNewPos - self.state.vel = walkNewVel + simulation.state.pos = walkNewPos + simulation.state.vel = walkNewVel end --Do stepDown if true then - if startedOnGround ~= nil and self.state.jump == 0 and self.state.vel.y <= 0 then - local stepDownResult = self:DoStepDown(self.state.pos) + if startedOnGround ~= nil and simulation.state.jump == 0 and simulation.state.vel.y <= 0 then + local stepDownResult = self:DoStepDown(simulation.state.pos) if stepDownResult ~= nil then - self.state.stepUp += stepDownResult.stepDown - self.state.pos = stepDownResult.pos + simulation.state.stepUp += stepDownResult.stepDown + simulation.state.pos = stepDownResult.pos end end end @@ -211,21 +231,21 @@ function module:ActiveThink(cmd) if (self.constants.aimlock == 1) then if (cmd.fa) then - local vec = cmd.fa - self.state.pos + local vec = cmd.fa - simulation.state.pos - self.state.targetAngle = MathUtils:PlayerVecToAngle(vec) - self.state.angle = MathUtils:LerpAngle( - self.state.angle, - self.state.targetAngle, + simulation.state.targetAngle = MathUtils:PlayerVecToAngle(vec) + simulation.state.angle = MathUtils:LerpAngle( + simulation.state.angle, + simulation.state.targetAngle, self.constants.turnSpeedFrac * cmd.deltaTime ) end else if wishDir ~= nil then - self.state.targetAngle = MathUtils:PlayerVecToAngle(wishDir) - self.state.angle = MathUtils:LerpAngle( - self.state.angle, - self.state.targetAngle, + simulation.state.targetAngle = MathUtils:PlayerVecToAngle(wishDir) + simulation.state.angle = MathUtils:LerpAngle( + simulation.state.angle, + simulation.state.targetAngle, self.constants.turnSpeedFrac * cmd.deltaTime ) end From c1a4f632178bbaf73f0d7d23471fc5b4f2eedd24 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 11 Apr 2023 07:54:25 -0700 Subject: [PATCH 4/4] Necessary generations only --- src/Simulation/CollisionModule.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Simulation/CollisionModule.lua b/src/Simulation/CollisionModule.lua index c3c665f..d322191 100644 --- a/src/Simulation/CollisionModule.lua +++ b/src/Simulation/CollisionModule.lua @@ -351,7 +351,10 @@ function module:FetchHullsForBox(min, max, playerSize) if (record.hull == nil) then record.hull = {} end - record.hull[fetchExpansionSize] = self:GenerateConvexHullAccurate(record.instance, fetchExpansionSize, self:GenerateSnappedCFrame(record.instance)) + + if (record.hull[fetchExpansionSize]) == nil then + record.hull[fetchExpansionSize] = self:GenerateConvexHullAccurate(record.instance, fetchExpansionSize, self:GenerateSnappedCFrame(record.instance)) + end end