Right now, I’m trying to make a platform that you can jump through and then land on.
Sounds simple, but it really isn’t.
The two main issues I have currently is that it’ll make them colliding while I’m jumping through it making my character stuck in the platform, and that if I try to jump through another platform above the current it just won’t let me pass through at all.
The class I’m using is:
--// Dependencies
local PhysicsService = game:GetService("PhysicsService");
local RunService = game:GetService("RunService")
--// Constants
local PLATFORM_PART_NAME = "Platform";
local PLATFORM_COLLISION_GROUP_NAME = "PLATFORM_COLLISION_GROUP";
local PLAYER_COLLISION_GROUP_NAME = "%s_COLLISION_GROUP";
local MAX_RAY_DISTANCE = 10000;
local MAX_FALLING_WAIT_TIME = 1;
--// Variables
local Platforms = {};
--// Class
local JumpCollisions = {};
JumpCollisions.__index = JumpCollisions;
--// Functions
local function CollisionGroupExists(Name)
for _, CollisionGroup in ipairs(PhysicsService:GetCollisionGroups()) do
if (CollisionGroup.name == Name) then
return true;
end
end
end
local function CreateIfNotCreated(Name)
if (not CollisionGroupExists(Name)) then
PhysicsService:CreateCollisionGroup(Name);
end
end
local function BasePartIter(Parent)
return coroutine.wrap(function()
for _, BasePart in ipairs(Parent:GetDescendants()) do
if (BasePart:IsA("BasePart")) then
coroutine.yield(BasePart, BasePart.Name);
end
end
end)
end
CreateIfNotCreated(PLATFORM_COLLISION_GROUP_NAME);
for BasePart, Name in BasePartIter(workspace) do
if (Name == PLATFORM_PART_NAME) then
table.insert(Platforms, BasePart)
PhysicsService:SetPartCollisionGroup(BasePart, PLATFORM_COLLISION_GROUP_NAME);
end
end
function JumpCollisions.Init(Player)
local self = setmetatable({
PlayerKey = string.format(PLAYER_COLLISION_GROUP_NAME, Player.Name);
PlatformKey = PLATFORM_COLLISION_GROUP_NAME;
Root = Instance.new("ObjectValue");
}, JumpCollisions);
CreateIfNotCreated(self.PlayerKey);
local function SetCharacterParts(Character)
if (not Player:HasAppearanceLoaded()) then
Character = Player.CharacterAppearanceLoaded:Wait()
end
self.Root.Value = Character.HumanoidRootPart;
for BasePart in BasePartIter(Character) do
PhysicsService:SetPartCollisionGroup(BasePart, self.PlayerKey);
end
end
if (Player.Character) then
SetCharacterParts(Player.Character);
end
Player.CharacterAppearanceLoaded:Connect(SetCharacterParts);
PhysicsService:CollisionGroupSetCollidable(self.PlayerKey, self.PlatformKey, true);
return self;
end
function JumpCollisions:Start()
local function StartRaycasting(Root)
Root.Parent.Humanoid.StateChanged:Connect(function(_, New)
local IsJumping = New == Enum.HumanoidStateType.Jumping;
local IsFalling = New == Enum.HumanoidStateType.Freefall;
local DownHit = self:Raycast("Up", true);
if (IsJumping) then
print("Made non-collidable");
self:SetCollidable(false)
elseif (IsFalling) then
if (not self:WaitUntilNotInPlatform()) then
return;
end
print("Made collidable");
self:SetCollidable(true);
elseif (DownHit and PhysicsService:CollisionGroupContainsPart(self.PlatformKey, DownHit)) then
print("Underneath is a Platform");
self:SetCollidable(true);
else
self:SetCollidable(false);
end
print(string.rep("-", 50));
end)
end
if (self.Root.Value) then
StartRaycasting(self.Root.Value);
end
self.Root.Changed:Connect(StartRaycasting);
end
function JumpCollisions:Raycast(Direction, Negative)
if (self.Root.Value) then
local FullDirection = self.Root.Value.CFrame[Direction .. "Vector"] * MAX_RAY_DISTANCE;
if (Negative) then
FullDirection = -FullDirection;
end
local DirectionalRay = Ray.new(self.Root.Value.Position, FullDirection);
return workspace:FindPartOnRay(DirectionalRay, self.Root.Value.Parent);
end
end
function JumpCollisions:IsInPlatform()
for _, Platform in ipairs(Platforms) do
local Connection = Platform.Touched:Connect(function() end);
for _, Colliding in ipairs(Platform:GetTouchingParts()) do
if (Colliding:IsDescendantOf(self.Root.Value.Parent)) then
Connection:Disconnect();
return true
end
end
Connection:Disconnect();
end
end
function JumpCollisions:WaitUntilNotInPlatform()
local TimeWaited = 0;
while (self:IsInPlatform()) do
TimeWaited = TimeWaited + RunService.Heartbeat:Wait();
if (TimeWaited >= MAX_FALLING_WAIT_TIME) then
return;
end
end
return true;
end
function JumpCollisions:SetCollidable(Collidable)
PhysicsService:CollisionGroupSetCollidable(self.PlayerKey, self.PlatformKey, Collidable);
end
return JumpCollisions;
The Start function mainly handles it, with Raycast as my primary raycasting function and WaitUntilNotInPlatform as my function to check that I’m not inside the Platform - probably the issue.
The code which inits this is:
--// Dependencies
local Players = game:GetService("Players");
local ServerStorage = game:GetService("ServerStorage");
--// Modules
local JumpCollisionsModule = require(ServerStorage.Modules.JumpCollisions);
--// Functions
local function PlayerAdded(Player)
local JumpCollisions = JumpCollisionsModule.Init(Player);
JumpCollisions:Start();
end
--// Connections
Players.PlayerAdded:Connect(PlayerAdded)
Possibly not the issue at hand though.
Just note that I have a DoubleJump client-sided class that handles double jumping, when I double jump I can move through the platform.
If any extra information is required then I’ll be happy to provide it.