本文旨在根據(jù)LOVE2D官方文檔和教程實現(xiàn)打磚塊的游戲,記錄部分實現(xiàn)過程和重要知識點
- 目標(biāo)摧毀所有磚塊
- 玩家控制球拍左右滑動反彈小球
- 小球摧毀磚塊
- 小球保持在屏幕內(nèi)
- 小球碰到屏幕底部,GAME OVER
引擎配置
-- conf.lua
love.conf = function(t)
t.console = true
t.window.width = 800
t.window.height = 600
end
在加載引擎的時候回調(diào)該函數(shù)修改引擎基本參數(shù),默認(rèn)參數(shù)可看Config Files - LOVE (love2d.org)
物理世界
-- world.lua
local begin_contact_callback = function(fixture_a, fixture_b, contact)
end
local end_contact_callback = function(fixture_a, fixture_b, contact)
end
local pre_solve_callback = function(fixture_a, fixture_b, contact)
end
local post_solve_callback = function(fixture_a, fixture_b, contact)
end
local world = love.physics.newWorld(0, 0)
world:setCallbacks(begin_contact_callback, end_contact_callback, pre_solve_callback, post_solve_callback)
return world
建立了一個無重力的物理世界,為世界的物理碰撞綁定了四個回調(diào)函數(shù),這四個回調(diào)函數(shù)依次的作用是
- 兩個物理實體開始接觸
- 接觸未解除,每幀碰撞處理計算前
- 接觸未解除,每幀碰撞處理計算后
- 兩個物理實體結(jié)束接觸
單一職責(zé)
按單一職責(zé)角度,main.lua
只負(fù)責(zé)創(chuàng)建游戲運行所必須的回調(diào)函數(shù),而以下行為不屬于這個職責(zé)范圍
- 加載和保存所有實體
- 解決各類實體的繪制
- 保存按鍵映射
舉個例子:main.lua
的love.draw
的回調(diào)函數(shù)的函數(shù)體負(fù)責(zé)了解釋各類實體如何繪制的操作,如
love.draw = function()
local ball_x, ball_y = ball.body:getWorldCenter()
love.graphics.circle('fill', ball_x, ball_y, ball.shape:getRadius())
end
可以通過修改實體結(jié)構(gòu),讓每個實體有對自身繪制行為的描述,將love.draw
的一部分職責(zé)分擔(dān)到各個實體上。如下述代碼為ball實體添加了draw
方法實現(xiàn)對自身繪圖行為的描述。
-- entities/ball.lua
local world = require 'world'
local entity = {}
-- 設(shè)置body位置,形狀將以該位置為中心,設(shè)置動態(tài)還是靜態(tài),即會不會受到其他物理實體的影響
entity.body = love.physics.newBody(world, 200, 200, 'dynamic')
entity.body:setMass(32) -- 設(shè)置質(zhì)量kg
entity.body:setLinearVelocity(300, 300) -- 右下角勻速加速度
entity.shape = love.physics.newCircleShape(10) -- 創(chuàng)建一個圓形形狀
entity.fixture = love.physics.newFixture(entity.body, entity.shape) -- 將body和形狀進(jìn)行綁定
entity.fixture:setRestitution(1) -- 設(shè)置彈性系數(shù)
entity.fixture:setUserData(entity) -- 設(shè)置用戶數(shù)據(jù),用于在碰撞回調(diào)時獲取用戶自定義信息來判斷操作
-- 實體對自身繪圖行為的描述
function entity:draw()
pos_x, pos_y = self.body:getWorldCenter() -- 獲取body的位置(也是圓心的位置)
love.graphics.circle('fill', pos_x, pos_y, self.shape:getRadius()) -- 繪制這個圓,還要從形狀那獲取半徑
end
return entity
實體列表
考慮到實體創(chuàng)建和實體管理較難維護(hù),可以用一個實體列表來進(jìn)行統(tǒng)一管理。
修改示例 ball.lua
可以把每個實體腳本包裹進(jìn)一個函數(shù)中,給定位置參數(shù)生成并返回這個實體,上述代碼將修改為
-- entities/ball.lua
local world = require 'world'
-- 導(dǎo)出一個函數(shù),這個函數(shù)需要x,y位置參數(shù),返回一個對象
return function(x, y)
local entity = {}
-- 設(shè)置body位置,形狀將以該位置為中心,設(shè)置動態(tài)還是靜態(tài),即會不會受到物理系統(tǒng)的影響
entity.body = love.physics.newBody(world, x, y, 'dynamic')
entity.body:setMass(32) -- 設(shè)置質(zhì)量kg
entity.body:setLinearVelocity(300, 300) -- 右下角勻速加速度
entity.shape = love.physics.newCircleShape(10) -- 創(chuàng)建一個圓形形狀
entity.fixture = love.physics.newFixture(entity.body, entity.shape) -- 將body和形狀進(jìn)行綁定
entity.fixture:setRestitution(1) -- 設(shè)置彈性系數(shù)
entity.fixture:setUserData(entity) -- 設(shè)置用戶數(shù)據(jù),用于在碰撞回調(diào)時獲取用戶自定義信息來判斷操作
-- 實體對自身繪圖行為的描述
function entity:draw()
pos_x, pos_y = self.body:getWorldCenter() -- 獲取body的位置(也是圓心的位置)
love.graphics.circle('fill', pos_x, pos_y, self.shape:getRadius()) -- 繪制這個圓,還要從形狀那獲取半徑
end
return entity -- 返回對象
end
其他修改示例
再修改其他實體代碼統(tǒng)一成上述形式
boundary-bottom.lua
-- entities/boundary-bottom.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(800, 10)
-- 形狀將以body的位置為中心
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(eneity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
return entity
end
boundary-vertical.lua
-- entities/boundary-vertical.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(10, 600)
-- 形狀將以body的位置為中心
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(eneity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
return entity
end
boundary-top.lua
-- entities/boundary-top.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(800, 10)
-- 形狀將以body的位置為中心
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(eneity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
return entity
end
brick.lua
-- entities/boundary-top.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(50, 20)
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
function entity:draw()
love.graphics.polygon('fill', self.body:getWorldPoints(self.shape:getPoints()))
end
return entity
end
paddle.lua
-- entities/boundary-paddle.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(180, 20) -- 生成一個長方體多邊形
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
return entity
end
創(chuàng)建實體列表
-- main.lua
local boundary_bottom = require('entities/boundary-bottom')
local boundary_vertical = require('entities/boundary-vertical')
local boundary_top = require('entities/boundary-top')
local paddle = require 'entities.paddle'
local ball = require 'entities.ball'
local brick = require 'entities.brick'
local world = require 'world'
local entities = {boundary_bottom(400, 606), boundary_vertical(-6, 300), boundary_vertical(806, 300), boundary_top(400, -6),
paddle(300, 500), ball(200, 200), brick(100, 100), brick(200, 100), brick(300, 100)}
直接調(diào)用實體創(chuàng)建函數(shù)創(chuàng)建各個實體,并放在同一個實體列表內(nèi),再修改love.draw
遍歷這個實體列表調(diào)用各個實體的draw
行為,代碼量大大減少
love.draw = function()
for _, entity in ipairs(entities) do
entity:draw()
end
end
代碼拆分 entities.lua
此時創(chuàng)建實體列表的相關(guān)代碼還在main.lua
內(nèi),將它獨立成entities.lua
-- entities.lua
local boundary_bottom = require 'entities/boundary-bottom'
local boundary_vertical = require 'entities/boundary-vertical'
local boundary_top = require 'entities/boundary-top'
local paddle = require 'entities.paddle'
local ball = require 'entities.ball'
local brick = require 'entities.brick'
return {boundary_bottom(400, 606), boundary_vertical(-6, 300), boundary_vertical(806, 300), boundary_top(400, -6),
paddle(300, 500), ball(200, 200), brick(100, 100), brick(200, 100), brick(300, 100)}
main.lua
只需導(dǎo)入 entities.lua
并使用即可
-- main.lua
local world = require 'world'
local entities = require 'entities'
love.draw = function()
for _, entity in ipairs(entities) do
entity:draw()
end
end
love.update = function(dt)
world:update(dt)
end
輸入處理
輸入系統(tǒng)
專門新建一個文件input.lua
用于輸入處理
-- input.lua
-- 存放輸入系統(tǒng)一切變量和操作的表
local input = {}
-- 各個按鍵對應(yīng)回調(diào)函數(shù)的映射
local press_functions = {}
local release_functions = {}
-- 初始值
input.left = false
input.right = false
input.paused = false
-- 根據(jù)key觸發(fā)對應(yīng)的映射函數(shù)
input.press = function(key)
if press_functions[key] then
press_functions[key]()
end
end
input.release = function(key)
if release_functions[key] then
release_functions[key]()
end
end
-- 如果離開當(dāng)前程序窗口則暫停
input.focused = function(f)
if not focused then
input.paused = true
end
end
press_functions.left = function()
input.left = true
end
press_functions.right = function()
input.right = true
end
press_functions.escape = function()
love.event.quit()
end
press_functions.space = function()
input.paused = not input.paused
end
release_functions.left = function()
input.left = false
end
release_functions.right = function()
input.right = false
end
return input
然后在main.lua
導(dǎo)入input.lua
-- main.lua
local world = require 'world'
local entities = require 'entities'
local input = require 'input'
love.draw = function()
for _, entity in ipairs(entities) do
entity:draw()
end
end
love.update = function(dt)
if not paused then
world:update(dt)
end
end
love.focus = input.focused
love.keypressed = input.press
love.keyreleased = input.release
更新實體位置
監(jiān)測輸入后需要根據(jù)輸入系統(tǒng)的變量實時更新實體位置,修改love.update
,查詢各個實體的update方法,若有則執(zhí)行
love.update = function(dt)
if not input.paused then
for _, entity in ipairs(entities) do
if entity.update then
entity:update(dt)
end
end
world:update(dt)
end
end
修改paddle.lua
的代碼
-- entities/boundary-paddle.lua
local world = require 'world'
local input = require 'input'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(180, 20) -- 生成一個長方體多邊形
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
function entity:update(dt)
-- 兩個按鍵都按了或都不按是不會動的
if input.left and input.right or not input.left and not input.right then
return
end
local self_x, self_y = self.body:getPosition()
if input.left then
-- 用時間增量去計算位置
self.body:setPosition(self_x - 250 * dt, self_y)
elseif input.right then
self.body:setPosition(self_x + 250 * dt, self_y)
end
end
return entity
end
由于paddle在創(chuàng)建的時候是靜態(tài)實體,是不受其他物理實體影響的,兩邊空氣墻真如同空氣,需要手動代碼限制,修改如下
if input.left then
-- 用時間增量去計算位置
local new_x = math.max(self_x - 400 * dt, 90)
self.body:setPosition(new_x, self_y)
elseif input.right then
local new_x = math.min(self_x + 400 * dt, 710)
self.body:setPosition(new_x, self_y)
end
去除摩擦力
雖然小球?qū)嶓w的彈力系數(shù)設(shè)置為1,但是在碰撞過程中會越來越慢,這是默認(rèn)有摩擦力的問題
print(entity.fixture:getFriction())
-- 0.20000000298023
摩擦力是 fixture
的屬性,可以使用 fixture:setFriction
進(jìn)行設(shè)置,修改ball.lua
,在創(chuàng)建實體的過程中添加如下代碼
entity.fixture:setFriction(0) -- 小球受到的摩擦力為0
暫停顯示文字
把文字當(dāng)做一個實體 pause-text.lua
,當(dāng)暫停時繪制這個實體
-- entities/pause-text.lua
local input = require('input')
return function()
-- https://love2d.org/wiki/love.window.getMode
local window_width, window_height = love.window.getMode()
local entity = {}
entity.draw = function(self)
if input.paused then
-- https://love2d.org/wiki/love.graphics.print 用到了coloredtext表
love.graphics.print({{0.2, 1, 0.2, 1}, 'PAUSED'}, math.floor(window_width / 2) - 54,
math.floor(window_height / 2), 0, 2, 2)
end
end
return entity
end
在entities.lua
創(chuàng)建這個實體并添加至列表中。只有當(dāng)游戲暫停時會執(zhí)行打印函數(shù)
三大剛體
static
靜態(tài)剛體,零質(zhì)量,零速度,即不會受到重力或速度影響,但是可以設(shè)置他的位置來進(jìn)行移動
- 物理引擎并不認(rèn)為這種剛體在移動
- 適用于固定位置的對象,地面、墻壁、任何你不希望角色碰撞的游戲?qū)ο?/li>
dynamic
動態(tài)剛體,有質(zhì)量,可以設(shè)置速度,會受到重力影響
- 與三種剛體都有物理效果
kinematic
運動剛體,零質(zhì)量,可以設(shè)置速度,不會受到重力的影響,但是可以設(shè)置速度來進(jìn)行移動
- 這種運動剛體完全由腳本控制
球拍改為運動剛體
將body類型修改為kinematic
,刪除原先的重新設(shè)置位置方式,修改為修改速度來達(dá)到移動效果
-- entities/boundary-paddle.lua
local world = require 'world'
local input = require 'input'
return function(x, y)
local window_width = love.window.getMode()
local entity_width = 120
local entity_height = 20
local entity_speed = 600
-- 計算一次邊界
local left_boundary = entity_width / 2 + 2
local right_boundary = window_width - entity_width / 2 - 2
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'kinematic')
entity.shape = love.physics.newRectangleShape(entity_width, entity_height)
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
function entity:update(dt)
-- 兩個按鍵都按是不會動的
if input.left and input.right then
return
end
local self_x = self.body:getPosition()
if input.left and self_x > left_boundary then
self.body:setLinearVelocity(-entity_speed, 0)
elseif input.right and self_x < right_boundary then
self.body:setLinearVelocity(entity_speed, 0)
else
self.body:setLinearVelocity(0, 0)
end
end
return entity
end
防止小球速度過快
-- entities/ball.lua
local world = require 'world'
-- 導(dǎo)出一個函數(shù),這個函數(shù)需要x,y位置參數(shù),返回一個對象
return function(x, y)
local entity_max_speed = 880
local entity = {}
-- 設(shè)置body位置,形狀將以該位置為中心,設(shè)置動態(tài)還是靜態(tài),即會不會受到其他物理實體的影響
entity.body = love.physics.newBody(world, x, y, 'dynamic')
entity.body:setMass(32) -- 設(shè)置質(zhì)量kg
entity.body:setLinearVelocity(300, 300) -- 右下角勻速加速度
entity.shape = love.physics.newCircleShape(10) -- 創(chuàng)建一個圓形形狀
entity.fixture = love.physics.newFixture(entity.body, entity.shape) -- 將body和形狀進(jìn)行綁定
entity.fixture:setRestitution(1) -- 設(shè)置彈性系數(shù)
entity.fixture:setUserData(entity) -- 設(shè)置用戶數(shù)據(jù),用于在碰撞回調(diào)時獲取用戶自定義信息來判斷操作
entity.fixture:setFriction(0) -- 小球受到的摩擦力為0
-- 實體對自身繪圖行為的描述
function entity:draw()
pos_x, pos_y = self.body:getWorldCenter() -- 獲取body的位置(也是圓心的位置)
love.graphics.circle('fill', pos_x, pos_y, self.shape:getRadius()) -- 繪制這個圓,還要從形狀那獲取半徑
end
function entity:update()
v_x, v_y = self.body:getLinearVelocity()
local speed = math.abs(v_x) + math.abs(v_y)
print(speed)
-- 看看小球反彈之后的速度是否過快
local vel_x_is_critical = math.abs(v_x) > entity_max_speed * 2
local vel_y_is_critical = math.abs(v_y) > entity_max_speed * 2
-- 如果反彈后某一方向移動速度過快則減慢速度
if vel_x_is_critical or vel_y_is_critical then
self.body:setLinearVelocity(v_x * .75, v_y * .75)
end
-- 如果整體速度過大,則設(shè)置阻尼
if speed > entity_max_speed then
self.body:setLinearDamping(0.1)
else
self.body:setLinearDamping(0)
end
end
return entity -- 返回對象
end
銷毀磚塊
需要做以下四件事情
- 修改
world.lua
處理碰撞的函數(shù) -
brick.lua
實體添加碰撞后的處理函數(shù) -
brick.lua
實體添加一個屬性用于表示生命值,如entity.health
-
main.lua
檢查并刪除生命值為0的實體
修改兩個物體實體離開接觸時的函數(shù) end_contact_callback
,檢查兩個物理實體各自是否有end_contact
方法,如果有則執(zhí)行
local end_contact_callback = function(fixture_a, fixture_b, contact)
local entity_a = fixture_a:getUserData()
local entity_b = fixture_b:getUserData()
if entity_a.end_contact then
entity_a.end_contact()
end
if entity_b.end_contact then
entity_b.end_contact()
end
end
修改brick.lua
添加生命值與end_contact
方法,并修改draw
行為,使其能在不同生命的時候顯示不同顏色
-- entities/boundary-top.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(50, 20)
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
entity.health = 2
local step = 1 / entity.health
function entity:draw()
local r, g, b, a = love.graphics.getColor()
love.graphics.setColor({1 - step * entity.health, step * entity.health, 0, 1})
love.graphics.polygon('fill', self.body:getWorldPoints(self.shape:getPoints()))
love.graphics.setColor(r, g, b, a)
end
function entity:end_contact()
self.health = self.health - 1
end
return entity
end
然后修改 main.lua
添加對各個實體生命值的檢查
love.update = function(dt)
if not input.paused then
-- 運行實體的update
for i, entity in ipairs(entities) do
if entity.update then
entity:update(dt)
end
end
-- 檢測實體health
local index = 1
while index <= #entities do
if entities[index].health == 0 then
local entity = table.remove(entities, index)
entity.fixture:destroy()
else
index = index + 1
end
end
world:update(dt)
end
end
批量生成磚塊
每生成一個磚塊實體,需要調(diào)用一次brick
,可以用函數(shù)批量生成,修改entities.lua
-- entities.lua
local boundary_bottom = require 'entities/boundary-bottom'
local boundary_vertical = require 'entities/boundary-vertical'
local boundary_top = require 'entities/boundary-top'
local paddle = require 'entities.paddle'
local ball = require 'entities.ball'
local brick = require 'entities.brick'
local pause_text = require 'entities.pause-text'
local entities = {boundary_bottom(400, 606), boundary_vertical(-6, 300), boundary_vertical(806, 300),
boundary_top(400, -6), paddle(300, 500), ball(200, 200), pause_text()}
local row_width = love.window.getMode() - 20
for number = 0, 38 do
local brick_x = ((number * 60) % row_width) + 40
local brick_y = (math.floor((number * 60) / row_width) * 40) + 80
entities[#entities + 1] = brick(brick_x, brick_y)
end
return entities
狀態(tài)管理
是否暫停、游戲勝利或失敗這種在程序生命期間會動態(tài)變化的變量都稱為狀態(tài)。由于狀態(tài)會越來越多,需要一種方式進(jìn)行有效管理。需要做到以下幾點
- 很容易就能找到和訪問狀態(tài)。就像在
main.lua
導(dǎo)入了entities
實體列表一樣,輕松可得 - 狀態(tài)數(shù)據(jù)只能有一份。如只有一個
paused
變量,而不是每個文件里都有paused
- 狀態(tài)數(shù)據(jù)只有有明確需求時才能訪問。在
ball.lua
獲取paused
是無意義的
現(xiàn)在有哪些狀態(tài)
- entities.lua
- 導(dǎo)出的實體列表里的每個實體對各自的狀態(tài)負(fù)責(zé),如每塊磚都存儲著自己的健康情況
- input.lua
- 當(dāng)前暫停狀態(tài),左右按鍵的狀態(tài)
- world.lua
- 導(dǎo)出的world負(fù)責(zé)整個物理空間的狀態(tài)
實現(xiàn)狀態(tài)管理,新建一個state.lua
文件,用于存儲游戲的大部分狀態(tài),比如將input.lua
中的狀態(tài)遷移到此文件,使input.lua
專心于捕獲和映射用戶輸入。world.lua
和entities.lua
沒有遷移的必要,避免代碼過于臃腫
-- state.lua
return {
left = false,
right = false,
game_over = false,
palette = {{1.0, 0.0, 0.0, 1.0}, -- red
{0.0, 1.0, 0.0, 1.0}, -- green
{0.4, 0.4, 1.0, 1.0}, -- blue
{0.9, 1.0, 0.2, 1.0}, -- yellow
{1.0, 1.0, 1.0, 1.0} -- white
},
paused = false,
stage_cleared = false
}
再修改 input.lua
-- input.lua
local state = require 'state'
-- 各個按鍵對應(yīng)回調(diào)函數(shù)的映射
local press_functions = {}
local release_functions = {}
press_functions.left = function()
state.left = true
end
press_functions.right = function()
state.right = true
end
press_functions.escape = function()
love.event.quit()
end
press_functions.space = function()
state.paused = not state.paused
end
release_functions.left = function()
state.left = false
end
release_functions.right = function()
state.right = false
end
return {
press = function(key)
print(key)
if press_functions[key] then
press_functions[key]()
end
end,
release = function(key)
if release_functions[key] then
release_functions[key]()
end
end,
focused = function(f)
if not f then
state.paused = true
end
end
}
修改main.lua
love.update = function(dt)
if state.game_over or state.paused or state.stage_cleared then
return
end
-- 運行實體的update
for i, entity in ipairs(entities) do
if entity.update then
entity:update(dt)
end
end
-- 檢測實體health
local index = 1
while index <= #entities do
if entities[index].health == 0 then
local entity = table.remove(entities, index)
entity.fixture:destroy()
else
index = index + 1
end
end
world:update(dt)
end
修改pause-text.lua
-- entities/pause-text.lua
local input = require 'input'
local state = require 'state'
return function()
-- https://love2d.org/wiki/love.window.getMode
local window_width, window_height = love.window.getMode()
local entity = {}
entity.draw = function(self)
if state.paused then
-- https://love2d.org/wiki/love.graphics.print 用到了coloredtext表
love.graphics.print({{0.2, 1, 0.2, 1}, 'PAUSED'}, math.floor(window_width / 2) - 54,
math.floor(window_height / 2), 0, 2, 2)
end
end
return entity
end
使用調(diào)色板為磚塊上色
love.graphics.setColor(state.palette[entity.health + 1])
love.graphics.polygon('fill', self.body:getWorldPoints(self.shape:getPoints()))
love.graphics.setColor(state.palette[5])
勝利與失敗
復(fù)制pause-text.lua
為game-over-text.lua
,修改判斷條件為 state.game_over
-- entities/game-over-text.lua
local input = require 'input'
local state = require 'state'
return function()
-- https://love2d.org/wiki/love.window.getMode
local window_width, window_height = love.window.getMode()
local entity = {}
entity.draw = function(self)
if state.game_over then
-- https://love2d.org/wiki/love.graphics.print 用到了coloredtext表
love.graphics.print({{0.2, 1, 0.2, 1}, 'GAME OVER'}, math.floor(window_width / 2) - 54,
math.floor(window_height / 2), 0, 2, 2)
end
end
return entity
end
復(fù)制pause-text.lua
為stage-clear-text.lua
,修改判斷條件為 state.stage_cleared
-- entities/boundary-bottom.lua
local world = require 'world'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(800, 10)
-- 形狀將以body的位置為中心
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
return entity
end
將新增的兩個實體添加至實體列表
修改boundary-bottom.lua
,添加end_contact
事件處理函數(shù)修改全局狀態(tài)“是否失敗”文章來源:http://www.zghlxwxcb.cn/news/detail-667237.html
-- entities/boundary-bottom.lua
local world = require 'world'
local state = require 'state'
return function(x, y)
local entity = {}
entity.body = love.physics.newBody(world, x, y, 'static')
entity.shape = love.physics.newRectangleShape(800, 10)
-- 形狀將以body的位置為中心
entity.fixture = love.physics.newFixture(entity.body, entity.shape)
entity.fixture:setUserData(entity)
function entity:draw()
love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
end
function entity:end_contact()
state.game_over = true
end
return entity
end
修改brick.lua
添加 entity.type = "brick"
,然后修改main.lua
判斷當(dāng)前幀是否還有磚塊文章來源地址http://www.zghlxwxcb.cn/news/detail-667237.html
love.update = function(dt)
if state.game_over or state.paused or state.stage_cleared then
return
end
-- 運行實體的update
local isBrick = false
for i, entity in ipairs(entities) do
if entity.type == "brick" then
isBrick = true
end
if entity.update then
entity:update(dt)
end
end
-- 檢測實體health
local index = 1
while index <= #entities do
if entities[index].health == 0 then
local entity = table.remove(entities, index)
entity.fixture:destroy()
else
index = index + 1
end
end
world:update(dt)
if not isBrick then
state.stage_cleared = true
end
end
到了這里,關(guān)于[Lua][Love] 打磚塊游戲?qū)崿F(xiàn)過程與知識點的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!