Love2D游戏引擎制作贪吃蛇游戏
預覽游戲
love2d游戲引擎重要函數
詳情:
-
love.load:當游戲開始時被調用且僅調用一次
-
love.draw:回調函數,每幀更新一次游戲畫面
-
love.update:回調函數,每幀更新一次游戲狀態
-
love.keypressed:回調函數,當有按鍵被按下時觸發
-
love.filesystem.load:加載一個lua腳本文件但不執行
!其他的函數在用到時再做解釋
版本區別以及初始化資源
!首先要注意的是,本次使用的游戲引擎時love 0.9版本,與最新的love 11.x版本稍有區別。在0.9版本中顏色使用0~255來表示,而在11.x版本中是0~1來表示。
因為需要制作的游戲非常小,所以我們將所用到的資源在第一時間將其初始化并加載到內存中,以便使用。使用到的資源主要有:
-
字體
-
顏色
-
聲音
-
窗口大小與塊大小
-
標題
-
邊框
所用到的函數:
-
love.window.setMode:設置窗口大小,以及樣式
-
love.window.setTitle:設置標題
-
love.graphics.newFont:加載字體文件,大小自定義,返回Font類型
-
love.audio.newSource:加載音效文件
代碼如下:
function love.load ()-- 塊大小,窗口寬高,標題cellSize = 20width = 20 * 40height = 20 * 25title = 'SNAKE !'-- 設置窗口大小和標題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')}-- 邊框數據border = {1, 1,width-1, 1,width-1, height-1,1, height-1,1, 1}-- 顏色數據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場景與其切換
!首先我們需要實現一個簡單的場景切換函數,因為一個游戲總是有多個場景
代碼如下:
function SwitchScence (scence)-- 將重要的函數賦予空值,以免沖突love.update = nillove.draw = nillove.keypressed = nil-- 將需要的場景加載進來,并執行load函數love.filesystem.load ('Scences/'..scence..'.lua') ()love.load () end-- 切換到初始化場景 SwitchScence ('Init')繪制開始界面
在這里我們需要認識一些游戲買賣函數:
-
love.graphics.setFont:設置當期字體
-
love.graphics.setColor:設置當前顏色
-
love.graphics.rectangle:繪制矩形
-
love.graphics.line:繪制直線
-
love.graphics.print:在窗口上輸出
!繪制比較簡單,其他詳情都在代碼里有詳細注釋,要注意的是我繪制選項的方法。options的有效長度并不是#options,而是options.count記錄的選項數量
代碼如下:
-- 游戲標題,以及繪制位置 local gameName = {text = title,textX = cellSize * 12,textY = cellSize * 6 }-- 選項:開始和退出 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 ()-- 加載并播放背景音樂sounds.showMenu:play ()-- 設置米色和藍色的透明程度為0,為了之后的動畫效果colors.beiga[4] = 0colors.paleTurquoise[4] = 0 endfunction love.draw ()-- 灰色背景love.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-- 設置字體,在指定位置畫出米色標題love.graphics.setFont (fonts.pixies100)love.graphics.setColor (colors.beiga)love.graphics.print (gameName.text, gameName.textX, gameName.textY)-- 設置字體love.graphics.setFont (fonts.pixies30)-- 繪制所有選項for i = 1, options.count doif i == options.selected thenlove.graphics.setColor (colors.paleTurquoise)elselove.graphics.setColor (colors.beiga)end-- 繪制選項邊框和字體love.graphics.line (options[i].border)love.graphics.print (options[i].text, options[i].textX, options[i].textY)end endfunction love.keypressed (key)-- 上下箭頭選擇選項,回車按鍵確認選項if key == 'up' then-- 關閉切換選項的聲音并重新播放if sounds.switchOption.isPlaying thensounds.switchOption:stop ()endsounds.switchOption:play ()-- 切換當前選項索引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-- 關閉顯示界面聲音if sounds.showMenu.isPlaying thensounds.showMenu:stop ()end-- 對應不同選項作出不同回應if options.selected == 1 thenSwitchScence ('GameStart')elseif options.selected == 2 thenlove.event.quit ()endend end實現游戲主體
游戲的實現方法,主要知道兩個方面:
- 蛇的移動方式:根據方向獲取下一個頭的位置,若沒有吃到食物就將蛇尾刪除,達到移動效果
- 方向隊列的引入:主要是解決鍵位沖突的問題
代碼如下:
-- 游戲窗口與記分窗口的分界線 local boundary = {cellSize*30, 0,cellSize*30, height }-- 當前分數的信息 local currentScore = {text = 'SCORE',score = 0,-- 文字的繪圖位置textX = cellSize * 33,textY = cellSize * 2,-- 分數的繪圖位置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 }},-- 速度與狀態speed = 0.1,alive = true, }-- 食物的位置 local food = { x = nil, y = nil }-- 方向隊列,用于記錄鍵盤按下的順序以免產生沖突 local directionQueue = { 'right' }-- 計時器,暫停狀態以及最高分文件 local timer = 0 local paused = false local file = nil-- 用于生成食物的可存在位置 local function CreateFood ()local foodPosition = {}-- 遍歷整個窗口,將可生成食物的位置記錄在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-- 生成隨機食物位置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 ()-- 沒有透明度colors.beiga[4] = 1colors.paleTurquoise[4] = 1CreateFood () endfunction love.draw ()-- 繪制背景love.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)-- 設置字體和顏色,并在指定位置繪制當前分數信息和最高分信息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)-- 蛇生存和死亡時使用不同的顏色繪制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)-- 如果是暫停狀態,則繪制暫停字樣if paused thenlove.graphics.print ('PAUSED !', cellSize*12, cellSize*11)end-- 設置字體和顏色并繪制提示信息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)-- 使用計時器timer = timer + dt-- 當蛇生存時if snake.alive then-- 根據蛇的速度更新游戲if timer > snake.speed thentimer = timer - snake.speed-- 沒有暫停時if not paused then-- 下一個蛇頭位置local nextX = snake.body[1].xlocal nextY = snake.body[1].y-- 當方向隊列中的方向大于1時除去第一個方向(當前方向)if #directionQueue > 1 thentable.remove (directionQueue, 1)end-- 根據方向作出改動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-- 蛇是否可以移動(沒有與自身相撞)local canMove = truefor index, pair in ipairs (snake.body) doif index ~= #snake.bodyand nextX == pair.xand nextY == pair.y thencanMove = falseendend-- 當蛇可以移動時if canMove then-- 將新位置加在蛇身的頭,并檢測是否吃到了食物table.insert (snake.body, 1, { x = nextX, y = nextY })if nextX == food.x and nextY == food.y then-- 播放吃到食物的音效(關閉之前的音效)if sounds.eatFood.isPlaying thensounds.eatFood:stop ()endsounds.eatFood:play ()-- 分數加一,并生成新的食物位置currentScore.score = currentScore.score + 1CreateFood ()else-- 沒有吃到食物則刪去蛇身的尾部,達到移動的目的table.remove (snake.body)endelse-- 蛇死亡,并播放相撞的音效snake.alive = falsesounds.collided:play ()endendend-- 等待一秒elseif timer >= 1 then-- 存儲最高分if currentScore.score > tonumber (highScore.score) thenfile:open ('w')file:write (tostring (currentScore.score))file:close ()end-- 切換到游戲結束場景SwitchScence ('GameOver')end endfunction love.keypressed (key)-- 回車鍵暫停游戲if key == 'return' thenpaused = not pausedend-- 沒有暫停時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實現最高分的保存與讀取
游戲存檔目錄:
-
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/
!寫文件只能在存檔目錄
最高分讀取:
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 ()繪制游戲結束界面
游戲結束界面的繪制與開始界面大致相同,這里不再贅述
代碼如下:
local gameOver = {text = 'GAME OVER !',textX = cellSize * 6,textY = cellSize * 6 }-- 選項:開始和退出 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 ()-- 設置米色和藍色的透明程度為0,為了之后的動畫效果colors.beiga[4] = 0colors.paleTurquoise[4] = 0 endfunction love.draw ()-- 灰色背景love.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-- 設置字體,在指定位置畫出米色標題love.graphics.setFont (fonts.pixies100)love.graphics.setColor (colors.beiga)love.graphics.print (gameOver.text, gameOver.textX, gameOver.textY)-- 設置字體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)-- 上下箭頭選擇選項,回車按鍵確認選項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項目結構
項目結構圖如下
Love2D游戲引擎制作貪吃蛇游戲
總結
以上是生活随笔為你收集整理的Love2D游戏引擎制作贪吃蛇游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF游戏,使用move游戏开发
- 下一篇: 微信小游戏复活了传统PC游戏