cambridge/tetris/components/piece.lua

197 lines
5.0 KiB
Lua
Raw Permalink Normal View History

2019-05-22 22:57:34 -05:00
local Object = require 'libs.classic'
local Piece = Object:extend()
2022-07-04 23:05:40 -05:00
local drawBlock = require 'tetris.components.draw_block'
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin, colour, big)
2019-05-22 22:57:34 -05:00
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.colour = colour
2019-05-22 22:57:34 -05:00
self.ghost = false
self.locked = false
self.big = big
2019-05-22 22:57:34 -05:00
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, self.colour, self.big
2019-05-22 22:57:34 -05:00
)
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, self.colour, self.big
2019-05-22 22:57:34 -05:00
)
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, instant)
2019-05-22 22:57:34 -05:00
local moved = false
for x = 1, squares do
if grid:canPlacePiece(self:withOffset(step)) then
moved = true
self:setOffset(step)
if instant then
self:dropToBottom(grid)
end
2019-05-22 22:57:34 -05:00
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
2020-11-03 22:04:47 -06:00
self:dropSquares(math.huge, grid)
2019-05-22 22:57:34 -05:00
self.gravity = 0
if self.position.y > piece_y then
if self.ghost == false then playSE("bottom") end
-- self.lock_delay = 0
2019-05-22 22:57:34 -05:00
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, classic_lock)
gravity = gravity / (self.big and 2 or 1)
2019-05-22 22:57:34 -05:00
local new_gravity = self.gravity + gravity
if self:isDropBlocked(grid) then
if classic_lock then
self.gravity = new_gravity
else
self.gravity = 0
self.lock_delay = self.lock_delay + 1
end
elseif not (
self:isMoveBlocked(grid, { x=0, y=-1 }) and gravity < 0
) then
local dropped_squares = math.floor(math.abs(new_gravity))
if gravity >= 0 then
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
else
local new_frac_gravity = new_gravity + dropped_squares
self.gravity = new_frac_gravity
self:moveInGrid({ x=0, y=-1 }, dropped_squares, grid)
if self:isMoveBlocked(grid, { x=0, y=-1 }) then
playSE("bottom")
end
2019-05-22 22:57:34 -05:00
end
else
self.gravity = 0
2019-05-22 22:57:34 -05:00
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
local offsets = self:getBlockOffsets()
local gravity_offset = 0
2020-12-17 17:00:07 -06:00
if config.gamesettings.smooth_movement == 1 and
grid ~= nil and not self:isDropBlocked(grid) then
gravity_offset = self.gravity * 16
end
2019-05-22 22:57:34 -05:00
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
2022-07-04 23:05:40 -05:00
local scale = self.big and 2 or 1
if grid ~= nil then
drawBlock(
brightness, brightness, brightness, opacity,
blocks[self.skin][self.colour],
2022-07-04 23:05:40 -05:00
64 + (x*16+partial_das)*scale, 16 + (y*16+gravity_offset)*scale,
48, 48+(grid.width+1)*16,
0, (grid.height+1)*16,
self.big
)
else
2022-07-04 23:05:40 -05:00
drawBlock(
brightness, brightness, brightness, opacity,
blocks[self.skin][self.colour],
2022-07-04 23:05:40 -05:00
64 + (x*16+partial_das)*scale, 16 + (y*16+gravity_offset)*scale,
false, false,
false, false,
self.big
)
end
2019-05-22 22:57:34 -05:00
end
return false
end
return Piece