Love2D游戏引擎制作贪吃蛇游戏
預(yù)覽游戲
love2d游戲引擎重要函數(shù)
詳情:
-
love.load:當(dāng)游戲開(kāi)始時(shí)被調(diào)用且僅調(diào)用一次
-
love.draw:回調(diào)函數(shù),每幀更新一次游戲畫(huà)面
-
love.update:回調(diào)函數(shù),每幀更新一次游戲狀態(tài)
-
love.keypressed:回調(diào)函數(shù),當(dāng)有按鍵被按下時(shí)觸發(fā)
-
love.filesystem.load:加載一個(gè)lua腳本文件但不執(zhí)行
!其他的函數(shù)在用到時(shí)再做解釋
版本區(qū)別以及初始化資源
!首先要注意的是,本次使用的游戲引擎時(shí)love 0.9版本,與最新的love 11.x版本稍有區(qū)別。在0.9版本中顏色使用0~255來(lái)表示,而在11.x版本中是0~1來(lái)表示。
因?yàn)樾枰谱鞯挠螒蚍浅P?#xff0c;所以我們將所用到的資源在第一時(shí)間將其初始化并加載到內(nèi)存中,以便使用。使用到的資源主要有:
-
字體
-
顏色
-
聲音
-
窗口大小與塊大小
-
標(biāo)題
-
邊框
所用到的函數(shù):
-
love.window.setMode:設(shè)置窗口大小,以及樣式
-
love.window.setTitle:設(shè)置標(biāo)題
-
love.graphics.newFont:加載字體文件,大小自定義,返回Font類型
-
love.audio.newSource:加載音效文件
代碼如下:
function love.load ()-- 塊大小,窗口寬高,標(biāo)題cellSize = 20width = 20 * 40height = 20 * 25title = 'SNAKE !'-- 設(shè)置窗口大小和標(biāo)題love.window.setMode (width, height)love.window.setTitle (title)-- 加載不同大小字體fonts = {pixies100 = love.graphics.newFont ('Fonts/Pixies.TTF', 100),pixies30 = love.graphics.newFont ('Fonts/Pixies.TTF', 30),pixies10 = love.graphics.newFont ('Fonts/Pixies.TTF', 10)}-- 加載音效資源sounds = {showMenu = love.audio.newSource ('Sounds/showMenu.wav', 'stream'),switchOption = love.audio.newSource ('Sounds/switchOption.wav', 'stream'),eatFood = love.audio.newSource ('Sounds/eatFood.wav', 'stream'),collided = love.audio.newSource ('Sounds/collided.wav', 'stream'),gameOver = love.audio.newSource ('Sounds/gameOver.wav', 'stream')}-- 邊框數(shù)據(jù)border = {1, 1,width-1, 1,width-1, height-1,1, height-1,1, 1}-- 顏色數(shù)據(jù)colors = {darkGray = { 0.3, 0.3, 0.3, 1 },beiga = { 0.98, 0.91, 0.76, 1 },white = { 1, 1, 1, 1 },paleTurquoise = { 0.7, 1, 1, 1 },}SwitchScence ('Menu') end場(chǎng)景與其切換
!首先我們需要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的場(chǎng)景切換函數(shù),因?yàn)橐粋€(gè)游戲總是有多個(gè)場(chǎng)景
代碼如下:
function SwitchScence (scence)-- 將重要的函數(shù)賦予空值,以免沖突love.update = nillove.draw = nillove.keypressed = nil-- 將需要的場(chǎng)景加載進(jìn)來(lái),并執(zhí)行l(wèi)oad函數(shù)love.filesystem.load ('Scences/'..scence..'.lua') ()love.load () end-- 切換到初始化場(chǎng)景 SwitchScence ('Init')繪制開(kāi)始界面
在這里我們需要認(rèn)識(shí)一些游戲買賣函數(shù):
-
love.graphics.setFont:設(shè)置當(dāng)期字體
-
love.graphics.setColor:設(shè)置當(dāng)前顏色
-
love.graphics.rectangle:繪制矩形
-
love.graphics.line:繪制直線
-
love.graphics.print:在窗口上輸出
!繪制比較簡(jiǎn)單,其他詳情都在代碼里有詳細(xì)注釋,要注意的是我繪制選項(xiàng)的方法。options的有效長(zhǎng)度并不是#options,而是options.count記錄的選項(xiàng)數(shù)量
代碼如下:
-- 游戲標(biāo)題,以及繪制位置 local gameName = {text = title,textX = cellSize * 12,textY = cellSize * 6 }-- 選項(xiàng):開(kāi)始和退出 local options = {{text = "START",textX = cellSize * 18,textY = cellSize * 15 - 5,border = {cellSize*16, cellSize*14,cellSize*24, cellSize*14,cellSize*24, cellSize*17,cellSize*16, cellSize*17,cellSize*16, cellSize*14}},{text = "QUIT",textX = cellSize * 19 - 10,textY = cellSize * 19 - 5,border = {cellSize*16, cellSize*18,cellSize*24, cellSize*18,cellSize*24, cellSize*21,cellSize*16, cellSize*21,cellSize*16, cellSize*18}},-- 一些其他屬性count = 2,selected = 1 }function love.load ()-- 加載并播放背景音樂(lè)sounds.showMenu:play ()-- 設(shè)置米色和藍(lán)色的透明程度為0,為了之后的動(dòng)畫(huà)效果colors.beiga[4] = 0colors.paleTurquoise[4] = 0 endfunction love.draw ()-- 灰色背景l(fā)ove.graphics.setColor (colors.darkGray)love.graphics.rectangle ('fill',0,0,width,height)-- 白色邊框love.graphics.setColor (colors.white)love.graphics.line (border)-- 漸顯效果if colors.beiga[4] < 1 thencolors.beiga[4] = colors.beiga[4] + 0.01colors.paleTurquoise[4] = colors.paleTurquoise[4] + 0.01end-- 設(shè)置字體,在指定位置畫(huà)出米色標(biāo)題love.graphics.setFont (fonts.pixies100)love.graphics.setColor (colors.beiga)love.graphics.print (gameName.text, gameName.textX, gameName.textY)-- 設(shè)置字體love.graphics.setFont (fonts.pixies30)-- 繪制所有選項(xiàng)for i = 1, options.count doif i == options.selected thenlove.graphics.setColor (colors.paleTurquoise)elselove.graphics.setColor (colors.beiga)end-- 繪制選項(xiàng)邊框和字體love.graphics.line (options[i].border)love.graphics.print (options[i].text, options[i].textX, options[i].textY)end endfunction love.keypressed (key)-- 上下箭頭選擇選項(xiàng),回車按鍵確認(rèn)選項(xiàng)if key == 'up' then-- 關(guān)閉切換選項(xiàng)的聲音并重新播放if sounds.switchOption.isPlaying thensounds.switchOption:stop ()endsounds.switchOption:play ()-- 切換當(dāng)前選項(xiàng)索引options.selected = options.selected - 1if options.selected <= 0 thenoptions.selected = options.countendelseif key == 'down' then-- 同上if sounds.switchOption.isPlaying thensounds.switchOption:stop ()endsounds.switchOption:play ()options.selected = options.selected + 1if options.selected > options.count thenoptions.selected = 1endelseif key == 'return' then-- 關(guān)閉顯示界面聲音if sounds.showMenu.isPlaying thensounds.showMenu:stop ()end-- 對(duì)應(yīng)不同選項(xiàng)作出不同回應(yīng)if options.selected == 1 thenSwitchScence ('GameStart')elseif options.selected == 2 thenlove.event.quit ()endend end實(shí)現(xiàn)游戲主體
游戲的實(shí)現(xiàn)方法,主要知道兩個(gè)方面:
- 蛇的移動(dòng)方式:根據(jù)方向獲取下一個(gè)頭的位置,若沒(méi)有吃到食物就將蛇尾刪除,達(dá)到移動(dòng)效果
- 方向隊(duì)列的引入:主要是解決鍵位沖突的問(wèn)題
代碼如下:
-- 游戲窗口與記分窗口的分界線 local boundary = {cellSize*30, 0,cellSize*30, height }-- 當(dāng)前分?jǐn)?shù)的信息 local currentScore = {text = 'SCORE',score = 0,-- 文字的繪圖位置textX = cellSize * 33,textY = cellSize * 2,-- 分?jǐn)?shù)的繪圖位置scoreX = cellSize * 34,scoreY = cellSize * 5 }-- 最高分的信息 local highScore = {text = 'HIGH SCORE',score = 0,-- 同上textX = cellSize * 31,textY = cellSize * 12,scoreX = cellSize * 34,scoreY = cellSize * 15 }-- 提示信息 local notes = {{text = 'ARROW KEY TO MOVE',textX = cellSize * 34,textY = cellSize * 22},{text = 'ENTER KEY TO PAUSE',textX = cellSize * 34,textY = cellSize * 23} }-- 游戲窗口的限制 local limit = { x = 29, y = 24 }-- 蛇的初始化信息 local snake = {-- 蛇身body = {{ x = 2, y = 0 },{ x = 1, y = 0 },{ x = 0, y = 0 }},-- 速度與狀態(tài)speed = 0.1,alive = true, }-- 食物的位置 local food = { x = nil, y = nil }-- 方向隊(duì)列,用于記錄鍵盤(pán)按下的順序以免產(chǎn)生沖突 local directionQueue = { 'right' }-- 計(jì)時(shí)器,暫停狀態(tài)以及最高分文件 local timer = 0 local paused = false local file = nil-- 用于生成食物的可存在位置 local function CreateFood ()local foodPosition = {}-- 遍歷整個(gè)窗口,將可生成食物的位置記錄在foodPosition表里for i = 0, limit.x dofor j = 0, limit.y dolocal possible = true-- 是否與蛇身沖突for index, pair in ipairs (snake.body) doif i == pair.x and j == pair.y thenpossible = falseendendif possible thentable.insert (foodPosition, { x = i, y = j })endendend-- 生成隨機(jī)食物位置local index = love.math.random (#foodPosition)food.x, food.y = foodPosition[index].x, foodPosition[index].y endfunction love.load ()file = love.filesystem.newFile ('HighScore.txt')file:open ('r')highScore.score = file:read ()file:close ()-- 沒(méi)有透明度colors.beiga[4] = 1colors.paleTurquoise[4] = 1CreateFood () endfunction love.draw ()-- 繪制背景l(fā)ove.graphics.setColor (colors.darkGray)love.graphics.rectangle ('fill',0,0,width,height)-- 繪制白色邊框和邊界線love.graphics.setColor (colors.white)love.graphics.line (border)love.graphics.line (boundary)-- 設(shè)置字體和顏色,并在指定位置繪制當(dāng)前分?jǐn)?shù)信息和最高分信息love.graphics.setFont (fonts.pixies30)love.graphics.setColor (colors.beiga)love.graphics.print (currentScore.text, currentScore.textX, currentScore.textY)love.graphics.print (currentScore.score, currentScore.scoreX, currentScore.scoreY)love.graphics.setColor (colors.paleTurquoise)love.graphics.print (highScore.text, highScore.textX, highScore.textY)love.graphics.print (highScore.score, highScore.scoreX, highScore.scoreY)-- 蛇生存和死亡時(shí)使用不同的顏色繪制if snake.alive thenlove.graphics.setColor (colors.paleTurquoise)elselove.graphics.setColor (colors.beiga)end-- 繪制蛇身,蛇頭另繪for index, pair in ipairs (snake.body) doif index == 1 thenlove.graphics.rectangle ('fill',cellSize*pair.x,cellSize*pair.y,cellSize,cellSize)endlove.graphics.rectangle ('fill',cellSize*pair.x+1,cellSize*pair.y+1,cellSize-1*2,cellSize-1*2)end-- 繪制食物love.graphics.setColor (colors.beiga)love.graphics.rectangle ('fill',cellSize*food.x+1,cellSize*food.y+1,cellSize-1*2,cellSize-1*2)-- 如果是暫停狀態(tài),則繪制暫停字樣if paused thenlove.graphics.print ('PAUSED !', cellSize*12, cellSize*11)end-- 設(shè)置字體和顏色并繪制提示信息love.graphics.setFont (fonts.pixies10)love.graphics.setColor (colors.beiga)for i = 1, #notes dolove.graphics.print (notes[i].text, notes[i].textX, notes[i].textY)end endfunction love.update (dt)-- 使用計(jì)時(shí)器timer = timer + dt-- 當(dāng)蛇生存時(shí)if snake.alive then-- 根據(jù)蛇的速度更新游戲if timer > snake.speed thentimer = timer - snake.speed-- 沒(méi)有暫停時(shí)if not paused then-- 下一個(gè)蛇頭位置local nextX = snake.body[1].xlocal nextY = snake.body[1].y-- 當(dāng)方向隊(duì)列中的方向大于1時(shí)除去第一個(gè)方向(當(dāng)前方向)if #directionQueue > 1 thentable.remove (directionQueue, 1)end-- 根據(jù)方向作出改動(dòng)if directionQueue[1] == 'right' thennextX = nextX + 1if nextX > limit.x thennextX = 0endelseif directionQueue[1] == 'left' thennextX = nextX - 1if nextX < 0 thennextX = limit.xendelseif directionQueue[1] == 'down' thennextY = nextY + 1if nextY > limit.y thennextY = 0endelseif directionQueue[1] == 'up' thennextY = nextY - 1if nextY < 0 thennextY = limit.yendend-- 蛇是否可以移動(dòng)(沒(méi)有與自身相撞)local canMove = truefor index, pair in ipairs (snake.body) doif index ~= #snake.bodyand nextX == pair.xand nextY == pair.y thencanMove = falseendend-- 當(dāng)蛇可以移動(dòng)時(shí)if canMove then-- 將新位置加在蛇身的頭,并檢測(cè)是否吃到了食物table.insert (snake.body, 1, { x = nextX, y = nextY })if nextX == food.x and nextY == food.y then-- 播放吃到食物的音效(關(guān)閉之前的音效)if sounds.eatFood.isPlaying thensounds.eatFood:stop ()endsounds.eatFood:play ()-- 分?jǐn)?shù)加一,并生成新的食物位置currentScore.score = currentScore.score + 1CreateFood ()else-- 沒(méi)有吃到食物則刪去蛇身的尾部,達(dá)到移動(dòng)的目的table.remove (snake.body)endelse-- 蛇死亡,并播放相撞的音效snake.alive = falsesounds.collided:play ()endendend-- 等待一秒elseif timer >= 1 then-- 存儲(chǔ)最高分if currentScore.score > tonumber (highScore.score) thenfile:open ('w')file:write (tostring (currentScore.score))file:close ()end-- 切換到游戲結(jié)束場(chǎng)景SwitchScence ('GameOver')end endfunction love.keypressed (key)-- 回車鍵暫停游戲if key == 'return' thenpaused = not pausedend-- 沒(méi)有暫停時(shí)if not paused then-- 記錄方向鍵的按下順序,同方向或相反方向的不記錄if key == 'right'and directionQueue[#directionQueue] ~= 'right'and directionQueue[#directionQueue] ~= 'left' thentable.insert (directionQueue, 'right')elseif key == 'left'and directionQueue[#directionQueue] ~= 'left'and directionQueue[#directionQueue] ~= 'right' thentable.insert (directionQueue, 'left')elseif key == 'down'and directionQueue[#directionQueue] ~= 'down'and directionQueue[#directionQueue] ~= 'up' thentable.insert (directionQueue, 'down')elseif key == 'up'and directionQueue[#directionQueue] ~= 'up'and directionQueue[#directionQueue] ~= 'down' thentable.insert (directionQueue, 'up')endend end實(shí)現(xiàn)最高分的保存與讀取
游戲存檔目錄:
-
Windows XP: C:\Documents and Settings\user\Application Data\LOVE\ or %appdata%\LOVE\
-
Windows Vista and 7,8: C:\Users\user\AppData\Roaming\LOVE or %appdata%\LOVE\
-
Linux:?$XDG_DATA_HOME/love/ or ~/.local/share/love/
-
Mac: /Users/user/Library/Application Support/LOVE/
!寫(xiě)文件只能在存檔目錄
最高分讀取:
file = love.filesystem.newFile ('HighScore.txt') file:open ('r') highScore.score = file:read () file:close ()最高分保存:
file:open ('w') file:write (tostring (currentScore.score)) file:close ()繪制游戲結(jié)束界面
游戲結(jié)束界面的繪制與開(kāi)始界面大致相同,這里不再贅述
代碼如下:
local gameOver = {text = 'GAME OVER !',textX = cellSize * 6,textY = cellSize * 6 }-- 選項(xiàng):開(kāi)始和退出 local options = {{text = "BACK",textX = cellSize * 13 - 15,textY = cellSize * 17 - 5,border = {cellSize*10, cellSize*16,cellSize*18, cellSize*16,cellSize*18, cellSize*19,cellSize*10, cellSize*19,cellSize*10, cellSize*16}},{text = "RETRY",textX = cellSize * 24,textY = cellSize * 17 - 5,border = {cellSize*22, cellSize*16,cellSize*30, cellSize*16,cellSize*30, cellSize*19,cellSize*22, cellSize*19,cellSize*22, cellSize*16}},-- 一些其他屬性count = 2,selected = 1 }function love.load ()sounds.gameOver:play ()-- 設(shè)置米色和藍(lán)色的透明程度為0,為了之后的動(dòng)畫(huà)效果colors.beiga[4] = 0colors.paleTurquoise[4] = 0 endfunction love.draw ()-- 灰色背景l(fā)ove.graphics.setColor (colors.darkGray)love.graphics.rectangle ('fill',0,0,width,height)-- 白色邊框love.graphics.setColor (colors.white)love.graphics.line (border)-- 漸顯效果if colors.beiga[4] < 1 thencolors.beiga[4] = colors.beiga[4] + 0.01colors.paleTurquoise[4] = colors.paleTurquoise[4] + 0.01end-- 設(shè)置字體,在指定位置畫(huà)出米色標(biāo)題love.graphics.setFont (fonts.pixies100)love.graphics.setColor (colors.beiga)love.graphics.print (gameOver.text, gameOver.textX, gameOver.textY)-- 設(shè)置字體love.graphics.setFont (fonts.pixies30)for i = 1, options.count doif i == options.selected thenlove.graphics.setColor (colors.paleTurquoise)elselove.graphics.setColor (colors.beiga)endlove.graphics.line (options[i].border)love.graphics.print (options[i].text, options[i].textX, options[i].textY)end endfunction love.keypressed (key)-- 上下箭頭選擇選項(xiàng),回車按鍵確認(rèn)選項(xiàng)if key == 'left' thenif sounds.gameOver.isPlaying thensounds.gameOver:stop ()endif sounds.switchOption.isPlaying thensounds.switchOption:stop ()endsounds.switchOption:play ()options.selected = options.selected - 1if options.selected <= 0 thenoptions.selected = options.countendelseif key == 'right' thenif sounds.gameOver.isPlaying thensounds.gameOver:stop ()endif sounds.switchOption.isPlaying thensounds.switchOption:stop ()endsounds.switchOption:play ()options.selected = options.selected + 1if options.selected > options.count thenoptions.selected = 1endelseif key == 'return' thenif sounds.gameOver.isPlaying thensounds.gameOver:stop ()endif options.selected == 1 thenSwitchScence ('Menu')elseif options.selected == 2 thenSwitchScence ('GameStart')endend end項(xiàng)目結(jié)構(gòu)
項(xiàng)目結(jié)構(gòu)圖如下
Love2D游戲引擎制作貪吃蛇游戲
總結(jié)
以上是生活随笔為你收集整理的Love2D游戏引擎制作贪吃蛇游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: WPF游戏,使用move游戏开发
- 下一篇: 微信小游戏复活了传统PC游戏