First bundled release.

This commit is contained in:
Joe Z
2019-05-22 23:57:34 -04:00
commit c973929e0c
120 changed files with 8709 additions and 0 deletions

204
tetris/components/grid.lua Normal file
View File

@@ -0,0 +1,204 @@
local Object = require 'libs.classic'
local Grid = Object:extend()
local empty = { skin = "", colour = "" }
function Grid:new()
self.grid = {}
self.grid_age = {}
for y = 1, 24 do
self.grid[y] = {}
self.grid_age[y] = {}
for x = 1, 10 do
self.grid[y][x] = empty
self.grid_age[y][x] = 0
end
end
end
function Grid:clear()
for y = 1, 24 do
for x = 1, 10 do
self.grid[y][x] = empty
self.grid_age[y][x] = 0
end
end
end
function Grid:isOccupied(x, y)
return self.grid[y+1][x+1] ~= empty
end
function Grid:isRowFull(row)
for index, square in pairs(self.grid[row]) do
if square == empty then return false end
end
return true
end
function Grid:canPlacePiece(piece)
local offsets = piece:getBlockOffsets()
for index, offset in pairs(offsets) do
local x = piece.position.x + offset.x
local y = piece.position.y + offset.y
if x >= 10 or x < 0 or y >= 24 or y < 0 or self.grid[y+1][x+1] ~= empty then
return false
end
end
return true
end
function Grid:canPlacePieceInVisibleGrid(piece)
local offsets = piece:getBlockOffsets()
for index, offset in pairs(offsets) do
local x = piece.position.x + offset.x
local y = piece.position.y + offset.y
if x >= 10 or x < 0 or y >= 24 or y < 4 or self.grid[y+1][x+1] ~= empty then
return false
end
end
return true
end
function Grid:getClearedRowCount()
local count = 0
for row = 1, 24 do
if self:isRowFull(row) then
count = count + 1
end
end
return count
end
function Grid:markClearedRows()
for row = 1, 24 do
if self:isRowFull(row) then
for x = 1, 10 do
self.grid[row][x] = {
skin = self.grid[row][x].skin,
colour = "X"
}
end
end
end
return true
end
function Grid:clearClearedRows()
for row = 1, 24 do
if self:isRowFull(row) then
for above_row = row, 2, -1 do
self.grid[above_row] = self.grid[above_row - 1]
self.grid_age[above_row] = self.grid_age[above_row - 1]
end
self.grid[1] = {empty, empty, empty, empty, empty, empty, empty, empty, empty, empty}
self.grid_age[1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
end
end
return true
end
function Grid:copyBottomRow()
for row = 1, 23 do
self.grid[row] = self.grid[row+1]
self.grid_age[row] = self.grid_age[row+1]
end
self.grid[24] = {empty, empty, empty, empty, empty, empty, empty, empty, empty, empty}
self.grid_age[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
for col = 1, 10 do
self.grid[24][col] = (self.grid[23][col] == empty) and empty or {
skin = self.grid[23][col].skin,
colour = "G"
}
end
return true
end
function Grid:applyPiece(piece)
offsets = piece:getBlockOffsets()
for index, offset in pairs(offsets) do
x = piece.position.x + offset.x
y = piece.position.y + offset.y
self.grid[y+1][x+1] = {
skin = piece.skin,
colour = piece.shape
}
end
end
function Grid:update()
for y = 1, 24 do
for x = 1, 10 do
if self.grid[y][x] ~= empty then
self.grid_age[y][x] = self.grid_age[y][x] + 1
end
end
end
end
function Grid:draw()
for y = 1, 24 do
for x = 1, 10 do
if self.grid[y][x] ~= empty then
if self.grid_age[y][x] < 1 then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16)
else
love.graphics.setColor(0.5, 0.5, 0.5, 1)
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
end
love.graphics.setColor(0.8, 0.8, 0.8, 1)
love.graphics.setLineWidth(1)
if y > 1 and self.grid[y-1][x] == empty then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < 24 and self.grid[y+1][x] == empty then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
end
if x < 10 and self.grid[y][x+1] == empty then
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
end
end
end
end
end
function Grid:drawInvisible(opacity_function, garbage_opacity_function)
for y = 1, 24 do
for x = 1, 10 do
if self.grid[y][x] ~= empty then
if self.grid[y][x].colour == "X" then
opacity = 1
elseif garbage_opacity_function and self.grid[y][x].colour == "G" then
opacity = garbage_opacity_function(self.grid_age[y][x])
else
opacity = opacity_function(self.grid_age[y][x])
end
love.graphics.setColor(0.5, 0.5, 0.5, opacity)
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
if opacity > 0 and self.grid[y][x].colour ~= "X" then
love.graphics.setColor(0.64, 0.64, 0.64)
love.graphics.setLineWidth(1)
if y > 1 and self.grid[y-1][x] == empty then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < 24 and self.grid[y+1][x] == empty then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
end
if x < 10 and self.grid[y][x+1] == empty then
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
end
end
end
end
end
end
return Grid

153
tetris/components/piece.lua Normal file
View File

@@ -0,0 +1,153 @@
local Object = require 'libs.classic'
local Piece = Object:extend()
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin)
self.shape = shape
self.rotation = rotation
self.position = position
self.block_offsets = block_offsets
self.gravity = gravity
self.lock_delay = lock_delay
self.skin = skin
self.ghost = false
self.locked = false
end
-- Functions that return a new piece to test in rotation systems.
function Piece:withOffset(offset)
return Piece(
self.shape, self.rotation,
{x = self.position.x + offset.x, y = self.position.y + offset.y},
self.block_offsets, self.gravity, self.lock_delay, self.skin
)
end
function Piece:withRelativeRotation(rot)
local new_rot = self.rotation + rot
while new_rot < 0 do new_rot = new_rot + 4 end
while new_rot >= 4 do new_rot = new_rot - 4 end
return Piece(
self.shape, new_rot, self.position,
self.block_offsets, self.gravity, self.lock_delay, self.skin
)
end
-- Functions that return predicates relative to a grid.
function Piece:getBlockOffsets()
return self.block_offsets[self.shape][self.rotation + 1]
end
function Piece:occupiesSquare(x, y)
local offsets = self:getBlockOffsets()
for index, offset in pairs(offsets) do
local new_offset = {x = self.position.x + offset.x, y = self.position.y + offset.y}
if new_offset.x == x and new_offset.y == y then
return true
end
end
return false
end
function Piece:isMoveBlocked(grid, offset)
local moved_piece = self:withOffset(offset)
return not grid:canPlacePiece(moved_piece)
end
function Piece:isDropBlocked(grid)
return self:isMoveBlocked(grid, { x=0, y=1 })
end
-- Procedures to actually do stuff to pieces.
function Piece:setOffset(offset)
self.position.x = self.position.x + offset.x
self.position.y = self.position.y + offset.y
return self
end
function Piece:setRelativeRotation(rot)
new_rot = self.rotation + rot
while new_rot < 0 do new_rot = new_rot + 4 end
while new_rot >= 4 do new_rot = new_rot - 4 end
self.rotation = new_rot
return self
end
function Piece:moveInGrid(step, squares, grid)
local moved = false
for x = 1, squares do
if grid:canPlacePiece(self:withOffset(step)) then
moved = true
self:setOffset(step)
else
break
end
end
if moved and step.y == 0 then playSE("move") end
return self
end
function Piece:dropSquares(dropped_squares, grid)
self:moveInGrid({ x = 0, y = 1 }, dropped_squares, grid)
end
function Piece:dropToBottom(grid)
local piece_y = self.position.y
self:dropSquares(20, grid)
self.gravity = 0
if self.position.y > piece_y then
-- if it got dropped any, also reset lock delay
if self.ghost == false then playSE("bottom") end
self.lock_delay = 0
end
return self
end
function Piece:lockIfBottomed(grid)
if self:isDropBlocked(grid) then
self.locked = true
end
return self
end
function Piece:addGravity(gravity, grid)
local new_gravity = self.gravity + gravity
if self:isDropBlocked(grid) then
self.gravity = math.min(1, new_gravity)
self.lock_delay = self.lock_delay + 1
else
local dropped_squares = math.floor(new_gravity)
local new_frac_gravity = new_gravity - dropped_squares
self.gravity = new_frac_gravity
self:dropSquares(dropped_squares, grid)
if self:isDropBlocked(grid) then
playSE("bottom")
end
end
return self
end
-- Procedures for drawing.
function Piece:draw(opacity, brightness, grid, partial_das)
if opacity == nil then opacity = 1 end
if brightness == nil then brightness = 1 end
love.graphics.setColor(brightness, brightness, brightness, opacity)
local offsets = self:getBlockOffsets()
local gravity_offset = 0
if grid ~= nil and not self:isDropBlocked(grid) then
gravity_offset = self.gravity * 16
end
if partial_das == nil then partial_das = 0 end
for index, offset in pairs(offsets) do
local x = self.position.x + offset.x
local y = self.position.y + offset.y
love.graphics.draw(blocks[self.skin][self.shape], 64+x*16+partial_das, 16+y*16+gravity_offset)
end
return false
end
return Piece