So I've been trying to code a Tetris on Roblox for a couple of days, and I'm stuck on this one bug that I can't seem to fix. In Tetris, you collide with other tetrominos (the Tetris blocks) and borders. I coded it so it will have collisions, and it somewhat works. It does work, but sometimes it doesn't detect some collisions, so you can sometimes cheat with this strange glitch. It usually starts happening when you rotate the tetrominos, and I've tried several solutions to try and fix it. This script is a local script in StarterPlayerScripts.
local player = game.Players.LocalPlayer
local tetrominos = game.ReplicatedStorage.Tetrominos
local tetrominoStorage = game.Workspace.Tetrominos
local borders = game.Workspace.Borders
local camera = game.Workspace.CurrentCamera
local UIS = game:GetService("UserInputService")
local debounce = false
local fallSpeed = 1
local previous
repeat wait() until player.Character
camera.CameraType = "Scriptable"
camera.CFrame = CFrame.new(0, 22, 35)
function IsColliding(tetromino)
local minos = tetromino:GetChildren()
local obstacles = borders:GetChildren()
for i, v in pairs(tetrominoStorage:GetChildren()) do
for _, mino in pairs(v:GetChildren()) do
if mino.Name == "Mino" then
table.insert(obstacles, mino)
end
end
end
for _, mino in pairs(minos) do
for _, obstacle in pairs(obstacles) do
if mino.Position == obstacle.Position then
return true
end
end
end
return false
end
function FixTetrominoPosition(tetromino)
for _, mino in pairs(tetromino:GetChildren()) do
for _, block in pairs(tetrominoStorage:GetDescendants()) do
if block.Name == "Mino" then
if mino.Position == block.Position then
repeat
tetromino:SetPrimaryPartCFrame(CFrame.new(0, 2, 0) * tetromino.PrimaryPart.CFrame)
until not IsColliding(tetromino)
end
end
end
for _, border in pairs(borders:GetChildren()) do
if mino.Position == border.Position then
local borderType = string.sub(border.Name, 7, #border.Name)
if borderType == "Left" then
repeat
tetromino:SetPrimaryPartCFrame(CFrame.new(2, 0, 0) * tetromino.PrimaryPart.CFrame)
until not IsColliding(tetromino)
elseif borderType == "Right" then
repeat
tetromino:SetPrimaryPartCFrame(CFrame.new(-2, 0, 0) * tetromino.PrimaryPart.CFrame)
until not IsColliding(tetromino)
elseif borderType == "Bottom" then
repeat
tetromino:SetPrimaryPartCFrame(CFrame.new(0, 2, 0) * tetromino.PrimaryPart.CFrame)
until not IsColliding(tetromino)
end
end
end
end
end
function ClearFullRows()
local rows = {}
local hasFullRows = false
for i = 1, 20 do
local minos = {}
for _, mino in pairs(tetrominoStorage:GetDescendants()) do
if mino.Name == "Mino" then
if mino.Position.Y == i * 2 + 1 then
table.insert(minos, mino)
end
end
end
table.insert(rows, minos)
end
for i, v in pairs(rows) do
if #v == 10 then
hasFullRows = true
for int, mino in pairs(v) do
mino:Destroy()
end
local row = rows[i + 1]
if row then
for int, rowsAbove in pairs(rows) do
if int >= i + 1 then
for _, mino in pairs(rowsAbove) do
mino.CFrame = CFrame.new(0, -2, 0) * mino.CFrame
end
end
end
end
end
end
end
function UpdatePreview(tetromino)
if previous then
previous:Destroy()
end
local preview = tetromino:Clone()
preview.Parent = game.Workspace
preview.Name = "Preview"
for i, v in pairs(preview:GetChildren()) do
if v.Name == "Mino" then
v.SelectionBox.Color3 = Color3.new(1, 1, 1)
v.Material = "ForceField"
v.Transparency = 0.5
end
end
previous = preview
repeat
preview:SetPrimaryPartCFrame(CFrame.new(0, -2, 0) * preview.PrimaryPart.CFrame)
until IsColliding(preview)
preview:SetPrimaryPartCFrame(CFrame.new(0, 2, 0) * preview.PrimaryPart.CFrame)
end
function CreateTetromino()
local tetromino = tetrominos:GetChildren()[math.random(1, #tetrominos:GetChildren())]:Clone()
tetromino.Parent = game.Workspace
return tetromino
end
local tetromino = CreateTetromino()
UpdatePreview(tetromino)
UIS.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.A or input.KeyCode == Enum.KeyCode.Left then
tetromino:SetPrimaryPartCFrame(CFrame.new(-2, 0, 0) * tetromino.PrimaryPart.CFrame)
if IsColliding(tetromino) then
FixTetrominoPosition(tetromino)
end
elseif input.KeyCode == Enum.KeyCode.D or input.KeyCode == Enum.KeyCode.Right then
tetromino:SetPrimaryPartCFrame(CFrame.new(2, 0, 0) * tetromino.PrimaryPart.CFrame)
if IsColliding(tetromino) then
FixTetrominoPosition(tetromino)
end
end
if input.KeyCode == Enum.KeyCode.W or input.KeyCode == Enum.KeyCode.Up then
tetromino:SetPrimaryPartCFrame(tetromino.PrimaryPart.CFrame * CFrame.Angles(0, 0, math.rad(-90)))
if IsColliding(tetromino) then
for _, mino in pairs(tetromino:GetChildren()) do
for _, block in pairs(tetrominoStorage:GetDescendants()) do
if block.Name == "Mino" then
if mino.Position == block.Position then
tetromino:SetPrimaryPartCFrame(tetromino.PrimaryPart.CFrame * CFrame.Angles(0, 0, math.rad(90)))
end
end
end
end
FixTetrominoPosition(tetromino)
end
end
if input.KeyCode == Enum.KeyCode.S or input.KeyCode == Enum.KeyCode.Down then
tetromino:SetPrimaryPartCFrame(CFrame.new(0, -2, 0) * tetromino.PrimaryPart.CFrame)
if IsColliding(tetromino) then
FixTetrominoPosition(tetromino)
tetromino.Parent = tetrominoStorage
tetromino = CreateTetromino()
ClearFullRows()
end
end
if input.KeyCode == Enum.KeyCode.Space or input.KeyCode == Enum.KeyCode.KeypadEnter then
repeat
tetromino:SetPrimaryPartCFrame(CFrame.new(0, -2, 0) * tetromino.PrimaryPart.CFrame)
until IsColliding(tetromino)
tetromino:SetPrimaryPartCFrame(CFrame.new(0, 2, 0) * tetromino.PrimaryPart.CFrame)
tetromino.Parent = tetrominoStorage
tetromino = CreateTetromino()
ClearFullRows()
end
UpdatePreview(tetromino)
debounce = false
wait(0.5)
if not debounce then
debounce = true
end
end)
spawn(function()
while wait(1 / fallSpeed) do
local canFall = true
for _, input in pairs(UIS:GetKeysPressed()) do
if input.KeyCode == Enum.KeyCode.S or input.KeyCode == Enum.KeyCode.Down then
canFall = false
end
end
if canFall then
tetromino:SetPrimaryPartCFrame(CFrame.new(0, -2, 0) * tetromino.PrimaryPart.CFrame)
end
fallSpeed = fallSpeed + (1 / 120)
if IsColliding(tetromino) then
FixTetrominoPosition(tetromino)
tetromino.Parent = tetrominoStorage
tetromino = CreateTetromino()
ClearFullRows()
end
UpdatePreview(tetromino)
end
end)
