精華區beta PttNewhand 關於我們 聯絡資訊
在BBS上玩打磚塊! ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ e▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ 說明: 這是一份 BBS-Lua 程式,請按 L 開始 使用左右鍵移動,其他鍵停止 目前有三個關卡,之後的關卡為隨機關卡 到達一定分數可以增加球數 若您中途想中斷程式執行,按下 Ctrl-C 即可 === -- 版本變更: -- 0.01 初步雛型 -- 0.02 修正板子移動的錯誤及使用 Frozenmouse 的方法堆動作 -- 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.color) 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 - math.cos(ball.angle)/math.abs(math.cos(ball.angle))][ball.ny] >2 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 = 3, 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 === -- ※ 發信站: 批踢踢兔(ptt2.cc) ◆ From: 91.3.238.213
phyton:自己玩都過不了一關也是很無奈的事....推 01/20 23:25
Kinten:我剛發現 球穿過橫槓了 or2推 01/20 23:32
phyton:穿過打擊的橫槓嗎?可能是顯示delay的緣故:P (攤手無解)推 01/20 23:44
GabrielII:轉錄至看板 GabrielII 01/20 23:46 phyton:轉錄至某隱形看板 01/21 00:06 peter1988:轉錄至看板 FLOWER 01/21 00:11 peter1988:轉錄至看板 FlowEreat 01/21 00:12
egh:感覺三種等級速度差不多?推 01/21 00:19
kira925:我也發生了....推 01/21 01:57
nakts0123:邊邊可以留個縫讓球(?)上去 可能會比較好過 orz推 01/21 06:40
phyton:要改嗎? 要改很容易XD 只是現在螢幕有點擠就是推 01/21 06:44
-- 把註解寫一寫了,大家可以自己改 :) 我對於"好玩的配置"實在沒有概念啊 orz prc:轉錄至看板 Teletubbies 01/21 12:43
ForSinSoKing:酷推 01/21 15:55
endlessdream:推XD 好難推 01/21 17:08
intotherain:底板會亂飄怎麼辦~"~推 01/21 19:49
blueshadow27:目前只玩到第四關 @@"推 01/22 13:17
phyton:樓上真強者 @_@b推 01/22 17:10
aitaik:轉錄至看板 aitai 01/22 23:21
blueshadow27:借轉推 01/23 00:18
blueshadow27:轉錄至看板 blueshadow27 01/23 00:19
shilala:好玩!!推 01/23 01:24
shilala:轉錄至看板 Prendre 01/23 01:24
Koint:借轉~~推 01/23 01:37
Koint:轉錄至看板 UVERworld 01/23 01:38
fuzuki:第6關 29950推 01/23 08:49
fuzuki:這真是殺時間的好物推 01/23 08:50
shilala:也是第6關 33650 我恨黃色磚!!推 01/23 11:36
federdream:轉錄至看板 fishstory 01/23 13:15 coolhunter:轉錄至某隱形看板 01/23 17:28 WiseWang:轉錄至看板 WiseWang 01/23 20:13 chris:轉錄至某隱形看板 01/24 02:09 keepsleeping:轉錄至看板 waturtle 01/24 21:46 ke1:轉錄至看板 Amour_ 01/25 14:22
milochen:速度變慢後,球跟棒子都變慢了,(我是按上停住棒子的)推 01/25 23:51
phyton:因為全部都連在一起啊XD 可能列入改版的考量:P推 01/26 00:55
westlife138:轉錄至看板 Eat09 01/26 01:41 westlife138:轉錄至看板 Eat09 01/26 01:52 prc:轉錄至看板 MathTurtle 01/27 12:13 sophiaky:轉錄至某隱形看板 01/27 13:38 Ckusdotiet:轉錄至某隱形看板 01/28 18:51 stinkytofu:轉錄至看板 AlenMiTofu 01/30 00:05 piaip:轉錄至看板 Test 02/05 11:38 ReverbHorn:轉錄至某隱形看板 02/11 18:34 m6ru80:轉錄至看板 SexNews 02/12 23:39 AlanCloud:轉錄至某隱形看板 03/12 23:41 weicha:轉錄至某隱形看板 04/05 20:47 pigtail:轉錄至看板 bonga 04/11 00:05
puzpuzpi:借轉!推 05/11 12:53
puzpuzpi:轉錄至某隱形看板 05/11 12:53 turtleknight:轉錄至看板 marshell 05/30 17:27 herman602:轉錄至某隱形看板 06/22 22:15 kula0000:轉錄至某隱形看板 08/13 01:43