test
作者 phyton (有事請email) 看板 BBSLua
標題 [Lua ] 打磚塊 1.00
時間 Sun Jan 20 23:21:26 2008
───────────────────────────────────────
在BBS上玩打磚塊!
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
e▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
說明: 這是一份 BBS-Lua 程式,請按 L 開始
使用左右鍵移動,其他鍵停止
目前有三個關卡,之後的關卡為隨機關卡
到達一定分數可以增加球數
若您中途想中斷程式執行,按下 Ctrl-C 即可
===
===
-- 版本變更:
-- 0.01 初步雛型
-- 0.03 增加"球數"
-- 0.04 改用 Interface 0.118 的 bbs.kball() 增加效能/堆動作
-- 更正"隔角打磚"
-- 0.05 移動方式改成連續移動 感謝piaip,Frozenmouse的意見
-- 0.06 更正板子移動會把牆璧戳出一個洞的問題
-- 更正打到磚塊角落的問題
-- 0.07 再次更正打到磚塊角落的問題
-- 0.08 程式碼減肥,把用不到的螢幕處理刪掉,看起來好看些:P
-- 0.09 更正所有角落的問題
-- 0.10 增加打兩次才消得掉的磚塊
-- 0.11 增加打三次才能消掉的隱形磚塊
-- 0.12 增加關卡
-- 0.13 得分夠高加球數
-- 0.14 超過30秒沒打到磚塊板子回到起點
-- 0.15 增加速度選擇
-- 1.00 改版本號為正式版,增加程式註解
-- 預計修正:
-- 程式碼減肥
-- 改善遊戲界面!?
-- 增加變化!?
--#BBSLUA
-- Interface: 0.118
-- Title: 打磚塊
-- Notes: 打磚塊小遊戲,需支援中文雙色字。出現錯誤請至 BBSLua 板回報:)
-- Author: phyton @ PTT2
-- Version: 1.00
-- Date: 2008年1月20日
--
-- Code: http://chieh.hsu.googlepages.com/ball
-- CopyRight: 創用 CC 姓名標示-非商業性-相同方式分享 2.5 台灣 授權條款授權
-- 但是在 PTT2 的 BBSLua 板上非商業性的創作分享,則得免除姓名標
-- 示及相同方式分享的要求。
-- 測試用開無敵?
testMode = false
-- clone table, stolen from http://lua-users.org/wiki/RetiredLuaFaq
function clone(t) -- return a copy of the table t
local new = {} -- create a new table
local i, v = next(t, nil) -- i is an index of t, v = t[i]
while i do
if type(v)=="table" then v=clone(v) end
new[i] = v
i, v = next(t, i) -- get next index
end
return new
end
function toInt(x) -- 四捨五入至整數 注意沒有針對負數處理!
a,b=math.modf(x)
if b < 0.5 then
return a
else
return a+1
end
end
-- 螢幕處理
-- 製造一個空白螢幕
defaultColor=4 -- 預設前景顏色(0~7)
changeBufferIndex=0 -- 暫存數目(序號)
changeBuffer={} -- 變更位置暫存空間
oriValue={} -- 顏色資訊暫存空間
MaxY,MaxX=bbs.getmaxyx() -- 螢幕大小
blockMaxX=math.modf((MaxX-1)/2)
blockMaxY=MaxY-1
screenMaxX=blockMaxX*2
screenMaxY=blockMaxY*2
screen = {} -- 預設黑螢幕
for screenx = 1,screenMaxX do
screen[screenx] = {}
for screeny= 1,2*screenMaxY do
screen[screenx][screeny]=0
end
end
blockStat={} -- 預備中文網格 預設黑螢幕
for blockX=1, blockMaxX do
blockStat[blockX]={}
for blockY=1, blockMaxY do
blockStat[blockX][blockY]=0
end
end
basicCube="▄" -- 中文網格基本單元
lCube=string.sub(basicCube, 1, 1)
rCube=string.sub(basicCube, 2, 2)
aBlock={} -- 中文字庫
for l = 0,7 do
for m=0,7 do
for n=0,7 do
for o=0,7 do
aBlock[o+n*8+m*64+l*64*8]=bbs.ANSI_COLOR(30+n,40+l) ..
lCube .. bbs.ANSI_COLOR(30+o,40+m) .. rCube .. bbs.ANSI_RESET
end
end
end
end
numTable = {} -- 數字表 減少計算
for l = 0,7 do -- 這些是為了這個對映
numTable[l]={} -- ┌─┬─┐
for m=0,7 do -- │3│2│
numTable[l][m]={} -- ├─┼─┤ 中文格值 = Ci * 8^i
for n=0,7 do -- │1│0│ C: 小格顏色值
numTable[l][m][n]={} -- └─┴─┘
for o=0,7 do
numTable[l][m][n][o]=o+n*8+m*64+l*64*8
end
end
end
end
-- 中文格動作
function blockCal(X,Y) -- 查詢格子狀態
blockStat[X][Y]=numTable[
screen[X*2-1][Y*2-1]][
screen[X*2 ][Y*2-1]][
screen[X*2-1][Y*2 ]][
screen[X*2 ][Y*2 ]]
end
-- 螢幕動作
function screenRefresh() -- 重畫螢幕(輸出螢幕)
for X=1, blockMaxX do
for Y=1, blockMaxY do
bbs.move(Y, X*2-1)
bbs.outs(aBlock[blockStat[X][Y]])
end
end
end
function changeRefresh() -- 僅更新螢幕新繪部份
if changeBufferIndex > 0 then
for i =1, changeBufferIndex do
local x=changeBuffer[i][1]
local y=changeBuffer[i][2]
local X=toInt(x/2)
local Y=toInt(y/2)
blockCal(X,Y)
bbs.move(Y, X*2-1)
bbs.outs(aBlock[blockStat[X][Y]])
end
bbs.move(MaxY-1,MaxX-1)
end
end
function changeClear() -- 清除變更部份(塗黑路徑)
if changeBufferIndex > 0 then
for i =1, changeBufferIndex do
x=changeBuffer[i][1]
y=changeBuffer[i][2]
X=toInt(x/2)
Y=toInt(y/2)
screen[x][y]=0
blockCal(X,Y)
bbs.move(Y, X*2-1)
bbs.outs(aBlock[blockStat[X][Y]])
end
changeBuffer={}
changeBufferIndex=0
bbs.move(MaxY-1,MaxX-1)
end
end
-- 繪圖指令
function addChangeBuffer(x,y,v) -- 加入暫存
changeBufferIndex=changeBufferIndex+1
changeBuffer[changeBufferIndex]={x,y}
oriValue[changeBufferIndex]=v
end
function drawPoint(x,y,c) -- 畫一個點(x,y,顏色)
if (x<1) or (x>screenMaxX) or (y<1) or (y>screenMaxY) then return end
local color=defaultColor
if c then color=c end
if screen[x][y] ~= color then addChangeBuffer(x,y,screen[x][y]) end
screen[x][y]=color
blockCal(toInt(x/2),toInt(y/2))
end
-- 打磚塊
field={ -- "場子"的大小
width = 62, -- 寬度
height = 44, -- 高度
posX=0, -- 在整個營幕的位置
posY=0,
map = {}, -- 紀錄每個位置的屬性
wallColor = 6,
init = function ()
field.posX=toInt((screenMaxX-14-field.width)/2)+15
field.posY=toInt((screenMaxY-field.height)/2)
for i = 1, field.width do
field.map[i]={}
for j = 1, field.height do
if i==1 or j==1 or i==field.width or j==field.height then
field.map[i][j]=9
else
field.map[i][j]=0
end
end
end
for i = 1, field.width do
for j = 1,field.height do
if field.map[i][j] > 1 then
drawPoint(field.posX + i, field.posY + j,field.wallColor)
end
end
end
if testMode == false then
for i = 1, field.width do
field.map[i][field.height] = 1
drawPoint(field.posX + i, field.posY + field.height,0)
end
end
changeBufferIndex = 0
screenRefresh()
end,
}
ball={ -- 基本上用角度來計算球走的下一步
oriX = toInt(field.width/2), oriY = field.height -6,
x = toInt(field.width/2), y = field.height -6,
angle = 0 - math.pi/7,
step = 1,
color = 2,
next_x = 0, next_y = 0,
nx =0, ny = 0,
move = function()
drawPoint(field.posX + toInt(ball.x), field.posY + toInt(ball.y),
ball.c\
olor)
if math.abs(math.sin(ball.angle)) < 0.1 or
math.abs(math.cos(ball.angle)) < 0.1 then
ball.angle = 2*math.pi*math.random()
end
ball.next_x = ball.x + math.cos(ball.angle) * ball.step
ball.next_y = ball.y + math.sin(ball.angle) * ball.step
ball.nx = toInt(ball.next_x); ball.ny = toInt(ball.next_y)
if field.map[ball.nx][ball.ny] == 0 then -- 沒事繼續走
ball.x = ball.next_x; ball.y = ball.next_y
elseif field.map[ball.nx][ball.ny] == 1 then -- 打到洞
game.loseBall()
elseif field.map[ball.nx][ball.ny] == 2 then -- 打到板子
ball.angle = plate.hit(ball.nx,ball.ny)
else -- 打到硬硬的東西
local hitLeftRight = field.map[ball.nx][ball.ny -
math.sin(ball.angle)/math.abs(math.sin(ball.angle))] >2
local hitUpDown = field.map[ball.nx -
local x0,y0 = bricks.mapping(ball.nx,ball.ny)
if hitLeftRight and hitUpDown then
-- 如果打進角落的話,檢查旁邊有沒有磚塊
local side_x = ball.nx -
math.cos(ball.angle)/math.abs(math.cos(ball.angle))
local side_y = ball.ny -
math.sin(ball.angle)/math.abs(math.sin(ball.angle))
local x1,y1 = bricks.mapping(side_x, side_y)
if field.map[side_x][ball.ny] == 3 then
bricks.units[x1][y0]:hit()
end
if field.map[ball.nx][side_y] == 3 then
bricks.units[x0][y1]:hit()
end
ball.angle = math.pi + ball.angle
elseif not (hitLeftRight or hitUpDown) then
-- 打到角角的話原路回去
ball.angle = math.pi + ball.angle
if field.map[ball.nx][ball.ny] == 3 then
bricks.units[x0][y0]:hit()
end
else
-- 打到邊邊的話反射
if hitLeftRight and not hitUpDown then
ball.angle = math.pi - ball.angle
elseif hitUpDown and not hitLeftRight then
ball.angle = 0 - ball.angle
end
if field.map[ball.nx][ball.ny] == 3 then
bricks.units[x0][y0]:hit()
end
end
end
end,
}
plate={ -- 這是操縱的打擊板
width = 11,
height = 1, -- 高度通常不大於1
oriX = toInt((field.width - 10)/2), oriY= field.height - 5,
x = toInt((field.width - 10)/2), y= field.height - 5,
color = 7,
step = 1,
minAngle = math.pi/((20 + 1)*2),
move = function(LR)
if LR == "LEFT" and plate.x - plate.step > 1 and
not (plate.x - plate.step == ball.x and plate.y == ball.y) then
for k= 1,plate.height do
field.map[plate.width+plate.x-1][k+plate.y-1]=0
end
plate.x = plate.x - plate.step
elseif LR == "RIGHT" and
plate.x + plate.step + plate.width <= field.width and
not (plate.x + plate.step == ball.x and plate.y == ball.y) then
for k= 1 , plate.height do
field.map[plate.x][k+plate.y-1]=0
end
plate.x = plate.x + plate.step
end
for i = 1,plate.width do
for j = 1, plate.height do
if j==1 or i ==1 or i==plate.width then
field.map[i+plate.x-1][j+plate.y-1] = 2
end
drawPoint(field.posX+i+plate.x-1,
field.posY+j+plate.y-1,plate.color)
end
end
end,
hit = function(x,y) -- 使球打到板子上造成球的不同角度
local position = x - plate.x +1
local frac = (math.pi - plate.minAngle*2) *
(position / (plate.width + 1))
if position < (plate.width/2 + plate.width/6) then
return math.pi + plate.minAngle * (position +1 ) *2
elseif position > (plate.width/2 + plate.width/6) then
return 0 - (plate.minAngle * (plate.width - position + 2)*2)
else
return 0 - ball.angle
end
end
}
aBrick={ -- 一塊磚塊的性質
x = 0,
y = 0,
width = 5,
height = 2,
color = 6, -- 顏色是亂寫的,在 init() 的時候會另外改變
life = 1, -- 本磚塊要打幾次才會消掉
hit = function (self) -- 被球打到的話會怎樣
if self.life == 1 then
for i = 1,self.width do
for j = 1, self.height do
field.map[i+self.x-1][j+self.y-1] = 0
drawPoint(field.posX+i+self.x-1,
field.posY+j+self.y-1,0)
end
end
changeRefresh()
changeBufferIndex = changeBufferIndex - self.width * self.height
game.addScore(100)
game.leftBricks = game.leftBricks -1
if game.leftBricks == 0 then game.nextStage() end
else
self.life = self.life -1
game.addScore(50)
if self.life == 1 then
self.color = math.random(0,1)*3+1
elseif self.life == 2 then
self.color = 3
end
for i = 1,self.width do
for j = 1, self.height do
drawPoint(field.posX + i + self.x-1,
field.posY + j + self.y-1, self.color)
end
end
changeRefresh()
changeBufferIndex = changeBufferIndex - self.width * self.height
end
game.lastHit = bbs.clock()
end,
init = function (self)
if self.life == 2 then
self.color = 3
elseif self.life == 3 then
self.color = 0
end
for i = 1,self.width do
for j = 1, self.height do
field.map[i+self.x-1][j+self.y-1] = 3
drawPoint(field.posX + i + self.x-1,
field.posY + j + self.y-1, self.color)
end
end
changeBufferIndex = 0
end,
}
bricks = { -- 所有磚塊的集合
x=2, -- 左上角的位置,注意牆也佔了一格
y=6,
units = {}, -- 磚塊存在這裡
sizeX = 12, -- 行數
sizeY = 4, -- 列數
hardBricks =10, -- 打兩次才會消的磚塊數
invisibleBricks =5, -- 打三次才會消的隱形磚
-- 以上兩個是隨機關卡的性質
init = function(stage)
if stage == 1 then -- 第一關
for i = 1, bricks.sizeX do
bricks.units[i]={}
for j = 1,bricks.sizeY do
bricks.units[i][j]=clone(aBrick)
bricks.units[i][j].x=bricks.x+(i-1)* aBrick.width
bricks.units[i][j].y=bricks.y+(j-1)* aBrick.height
bricks.units[i][j].color=2.5+1.5*math.pow(-1,i+j)
bricks.units[i][j]:init()
game.leftBricks = game.leftBricks+1
end
end
elseif stage == 2 then -- 第二關
for i = 1, bricks.sizeX do
bricks.units[i]={}
for j = 1,bricks.sizeY do
bricks.units[i][j]=clone(aBrick)
bricks.units[i][j].x=bricks.x+(i-1)* aBrick.width
bricks.units[i][j].y=bricks.y+(j-1)* aBrick.height
if j == bricks.sizeY then
bricks.units[i][j].life = 2
else
bricks.units[i][j].color=2.5+1.5*math.pow(-1,i+j)
end
bricks.units[i][j]:init()
game.leftBricks = game.leftBricks+1
end
end
elseif stage == 3 then -- 第三關
for i = 1, bricks.sizeX do
bricks.units[i]={}
for j = 1,bricks.sizeY do
bricks.units[i][j]=clone(aBrick)
bricks.units[i][j].x=bricks.x+(i-1)* aBrick.width
bricks.units[i][j].y=bricks.y+(j-1)* aBrick.height
if i == 1 or i == bricks.sizeX then
bricks.units[i][j].life = 3
elseif i-1 == j or i + j == bricks.sizeX then
bricks.units[i][j].life = 2
else
bricks.units[i][j].color=2.5+1.5*math.pow(-1,i+j)
end
bricks.units[i][j]:init()
game.leftBricks = game.leftBricks+1
end
end
else -- 很多關
for i = 1, bricks.sizeX do
bricks.units[i]={}
for j = 1,bricks.sizeY do
bricks.units[i][j]=clone(aBrick)
bricks.units[i][j].x=bricks.x+(i-1)* aBrick.width
bricks.units[i][j].y=bricks.y+(j-1)* aBrick.height
bricks.units[i][j].color=2.5+1.5*math.pow(-1,i+j)
bricks.units[i][j]:init()
game.leftBricks = game.leftBricks+1
end
end
for i = 1, bricks.hardBricks do
math.randomseed(bbs.clock()+i)
local p = math.random(1,bricks.sizeX)
local q = math.random(1,bricks.sizeY)
bricks.units[p][q].life = 2
bricks.units[p][q]:init()
end
for i = 1, bricks.invisibleBricks do
math.randomseed(bbs.clock()+i)
local p = math.random(1,bricks.sizeX)
local q = math.random(1,bricks.sizeY)
bricks.units[p][q].life = 3
bricks.units[p][q]:init()
end
end
bricks.hardBricks =bricks.hardBricks +1
bricks.invisibleBricks= bricks.invisibleBricks +1
end,
mapping = function(x,y)
local x0 = math.modf((x - bricks.x)/ aBrick.width) +1
local y0 = math.modf((y - bricks.y)/ aBrick.height) +1
return x0,y0
end,
}
game = { -- 關於遊戲及遊戲的動作
score = 0,
leftBricks =0,
FIN = 0, -- =1 則結束遊戲
balls = 300,
stage = 1, -- 目前關卡
lastAddBall = 0, -- 用來計算加球的條件
lastHit= 0, -- 紀錄上次打到磚塊的時間
speed=0.02, -- frame refresh period
bearablePeriod = 30, -- 多久打不到磚塊則重設位置
addScore = function (points)
game.score = game.score + points
if game.score == 2500 or (game.score - game.lastAddBall) >= 5000 then
game.balls = game.balls + 1
game.lastAddBall = game.score
end
end,
loseBall =function()
if game.balls == 0 then
game.over()
else
changeClear()
game.balls = game.balls -1
game.reset()
end
end,
nextStage = function()
changeClear()
game.stage = game.stage + 1
bricks.init(game.stage)
game.reset()
end,
checkTime = function() -- 超過時限回到原點避免無限迴圈
if bbs.clock() - game.lastHit > game.bearablePeriod then
changeClear()
game.reset()
end
end,
reset = function()
keyTemp = ""
ball.x , ball.y = ball.oriX, ball.oriY
plate.x, plate.y = plate.oriX, plate.oriY
plate.move()
ball.move()
changeRefresh()
screenRefresh()
game.state()
bbs.move(9,1)
bbs.outs("=請按空白鍵開始=")
repeat until bbs.getch() == " "
game.lastHit = bbs.clock()
screenRefresh()
end,
over = function()
game.state()
bbs.move(9,1)
bbs.outs("==遊戲結束==")
bbs.sleep(1)
game.FIN = 1
end,
state = function()
bbs.move(1,1)
bbs.outs("打磚塊 " .. toc.version .. " 版")
bbs.move(2,1)
bbs.outs("分數: " ..tostring(game.score))
bbs.move(4,1)
bbs.outs("尚有: " .. tostring(game.balls) .. " 球")
bbs.move(3,1)
bbs.outs("關卡: " .. tostring(game.stage))
bbs.move(6,1)
bbs.outs("左右鍵 移動")
bbs.move(7,1)
bbs.outs("其他鍵 停止")
bbs.move(9,1)
bbs.outs("按 Q/q 離開")
bbs.move(MaxY,MaxX)
end,
chooseSpeed = function()
bbs.clear()
bbs.outs([[
這是 BBS-Lua 打磚塊小游戲,
請選擇遊戲速度:
(1) 慢
(2) 中等 (預設)
(3) 快
]])
bbs.move(MaxY,MaxX)
local key = bbs.getch()
if key == "1" then
game.speed = 0.03
bearablePeriod = 60
elseif key == "2" then
game.speed = 0.02
bearablePeriod = 30
elseif key == "3" then
game.speed = 0.01
bearablePeriod = 20
end
bbs.clear()
end
}
-- main
game.chooseSpeed()
field.init()
bricks.init(game.stage)
screenRefresh()
game.balls = game.balls - 1
keyList ={}
keyTemp = ""
game.reset()
repeat
changeClear()
for i=1, #keyList do
local key = keyList[i]
if key == "q" or key == "Q" then game.FIN=1 end
if key == "RIGHT" or key == "LEFT" then
keyTemp = key
else
keyTemp =""
end
end
plate.move(keyTemp)
ball.move()
changeRefresh()
game.state()
game.checkTime()
keyList= {bbs.kball(game.speed)}
until game.FIN == 1
--#BBSLUA
===
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.229.27.27
推
06/26 09:54, , 1F
06/26 09:54, 1F
→
06/26 13:48, , 2F
06/26 13:48, 2F