I am workin on a non physics based character controller.
As the title says, I am using raycasts to detect collusion. It works fine when there are only a couple of characters .The problem Im having is when there are a lot of characters colliding wirh each other. The characters pushing each other creates a “vibration”, that builds up over time and eventually ends up pushing the charactes into walls. I dont really have a clue of what to do. How can I fix this? Thanks in advance
code ( cm for character motor)
local cm = {}
cm.__index = cm
--variable
cm.targetPos = Vector3.zero
cm.input = Vector3.zero
cm.velocity = Vector3.zero
cm.falling = false
--setting
cm.walkSpeed = 20
cm.gravity = 2
--internal_variables
cm._minMove = 0.01
cm._rayMultiplier = 1.5
cm._hitboxRadius = 1
cm._hitboxHeightHalf = 1
cm._hitboxSideRays = {}
function cm:update(dt)
local currentPos = self.hitbox.Position
local diff = self.targetPos - currentPos
local diffXZ = diff * Vector3.new(1, 0, 1)
local diffXZMag = diffXZ.Magnitude
local velocity = Vector3.zero
local prevVelocity = self.velocity
--calc walk
if diffXZMag > self._minMove then
if diffXZMag > self.walkSpeed * dt then
velocity = diffXZ.Unit * self.walkSpeed * dt
else
velocity = diffXZ
end
end
--gravity
if self.falling then
velocity += Vector3.yAxis * ( prevVelocity.Y - (self.gravity * dt) )
end
--check ground collusion
local groundCastResult = workspace:Raycast(
currentPos + velocity,
Vector3.yAxis * -1 * self._rayMultiplier * self._hitboxHeightHalf,
self._rayPara
)
if groundCastResult then
local dist = groundCastResult.Distance
local diff = dist - self._hitboxHeightHalf
if diff > self._minMove then
self.falling = true
elseif diff < self._minMove then
self.falling = false
velocity -= Vector3.yAxis * diff
else
self.falling = false
end
else
self.falling = true
end
--check side collusion
local sidePush = Vector3.zero
for i, vec in ipairs(self._hitboxSideRays) do
local result = workspace:Raycast(currentPos + velocity, vec * self._hitboxRadius * self._rayMultiplier, self._rayPara)
if result then
local dist = result.Distance - self._hitboxRadius
if dist < 0 then
sidePush += vec * dist
end
end
end
velocity += sidePush
--apply min move
local and = Vector3.yAxis
if math.abs(velocity.X) > self._minMove then
and += Vector3.xAxis
end
if math.abs(velocity.Z) > self._minMove then
and += Vector3.zAxis
end
velocity = velocity * and
self.velocity = velocity
self.model:TranslateBy(velocity)
end
function cm.new(m)
local new = {
model = m,
hitbox = m.PrimaryPart,
_hitboxHeightHalf = m.PrimaryPart.Size.Y / 2,
_hitboxRadius = math.max(m.PrimaryPart.Size.X/2, m.PrimaryPart.Size.Z/2),
targetPoint = m.PrimaryPart.Position
}
setmetatable(new ,cm)
new._hitboxSideRays = {
Vector3.new(1, 0, 0),
Vector3.new(-1, 0, 0),
Vector3.new(0, 0, 1),
Vector3.new(0, 0, -1)
}
local rayPara = RaycastParams.new()
rayPara.IgnoreWater = true
rayPara.FilterDescendantsInstances = {m}
new._rayPara = rayPara
return new
end
return cm
video