Lua实现Unity象素鸟小游戏要点记录:
游戏玩法简介
不用物理引擎实现像素鸟在障碍物之间飞行,通过配表配置小鸟向下的加速度和点击一次屏幕给小鸟赋值一次初始速度和向上加速度来模拟小鸟飞行。障碍物根据配置难度在固定距离随机生成。
功能实现简述
飞行障碍实现
创建AmusementParkBirdObstacleCell障碍控件。游戏运行时,根据固定的配置距离,生成不同难度的障碍实例。障碍物分为上,下两部份,中间有可穿行的空隙。
AmusementParkBirdObstacleCell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
---@class AmusementParkBirdObstacleCell
local m = {
View = nil,
---@type number 移动速度
Speed = 0,
---@type UnityEngine.Collider2D
TopCollider2D = nil,
---@type UnityEngine.Collider2D
BottomCollider2D = nil,
}
function m.New(view)
local obj = Clone(m)
obj:Init(view)
return obj
end
function m:Init(view)
self.View = view
LuaCodeInterface.BindOutlet(self.View, self)
self.TopCollider2D = self.View.transform:Find("Top").gameObject:GetComponent(typeof(UnityEngine.Collider2D))
self.BottomCollider2D = self.View.transform:Find("Bottom").gameObject:GetComponent(typeof(UnityEngine.Collider2D))
self:AddListener()
end
function m:AddListener()
end
function m:RemoveListener()
end
---界面轮询。
---@param elapseSeconds number
---@param realElapseSeconds number
---@return void
function m:OnUpdate(elapseSeconds, realElapseSeconds)
self.View.transform:Translate(Vector3.New(self.Speed * UnityEngine.Time.deltaTime * -1, 0, 0))
end
---@param speed number
function m:SetData(speed)
self.Speed = speed
end
function m:Dispose()
AssetUtil.UnloadAsset(self)
self:RemoveListener()
LuaCodeInterface.ClearOutlet(self.View, self)
UnityEngine.Object.Destroy(self.View)
self.View = nil
end
return m
控制小鸟上下移动速度
创建小鸟角色对象AmusementParkBirdPlayer,其移动只在Y轴方向移动。如果不点击屏幕给予向上的初始速度和加速度,小鸟会向下加速度掉落,当碰触到地面和障碍时,小鸟死亡,游戏结束。
AmusementParkBirdPlayer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
---@class AmusementParkBirdPlayer
local m = {
View = nil,
---@type UnityEngine.Rigidbody2D
Rigidbody2D = nil,
---@type UnityEngine.Collider2D
BirdCollider2D = nil,
---@type Vector3 玩家初始位置
StartPos = Vector3.New(0,0,0),
---@type number Y轴方向速度
Speed = 0,
---@type number 加速度
Acceleration = 0,
}
function m.New(view)
local obj = Clone(m)
obj:Init(view)
return obj
end
function m:Init(view)
self.View = view
LuaCodeInterface.BindOutlet(self.View, self)
self.BirdCollider2D = self.View:GetComponent(typeof(UnityEngine.Collider2D))
self.Rigidbody2D = self.View:GetComponent("Rigidbody2D")
self.Rigidbody2D.simulated = false
self.StartPos = self.View.transform.localPosition
self.Acceleration = -AmusementParkBirdGameModule.apBirdGameData:GetCfgData().VerticalDownAcceleration
self:AddListener()
end
function m:AddListener()
end
function m:RemoveListener()
end
---界面轮询。
---@param elapseSeconds number
---@param realElapseSeconds number
---@return void
function m:OnUpdate(elapseSeconds, realElapseSeconds)
self.Speed = self.Speed + self.Acceleration
local pos = self.View.transform.localPosition
pos.y = pos.y + self.Speed * UnityEngine.Time.deltaTime
self.View.transform.localPosition = pos
end
---设置向上初速度和加速度
---@param acceleration number 加速度
---@param speed number 初始速度
function m:SetData(acceleration,speed)
self.Acceleration = acceleration
if speed then
self.Speed = speed
end
end
---重置玩家状态
function m:ResetPlayer()
self.Rigidbody2D.simulated = false
self.View.transform.localPosition = self.StartPos
self.View.transform.localRotation = Vector3.New(0,0,0)
self.Speed = 0
self.Acceleration = -AmusementParkBirdGameModule.apBirdGameData:GetCfgData().VerticalDownAcceleration
end
---玩家死亡
function m:PlayerDead()
self.Rigidbody2D.simulated = true
log("游戏结束 小鸟死亡")
end
---检测小鸟与障碍物碰撞
---@param collider2D UnityEngine.Collider2D 目标对象collider2D
---@return boolean
function m:CheckBirdBoundsIntersects(collider2D)
return self.BirdCollider2D.bounds:Intersects(collider2D.bounds)
end
function m:Dispose()
AssetUtil.UnloadAsset(self)
self:RemoveListener()
LuaCodeInterface.ClearOutlet(self.View, self)
UnityEngine.Object.Destroy(self.View)
self.View = nil
end
return m
障碍碰撞检测
小鸟在飞行过程中,通过collider2D碰撞检测,是否与障碍物相撞 self.BirdCollider2D.bounds:Intersects(collider2D.bounds)
实例
---@class AmusementParkGameFlappyBirdUI
local AmusementParkGameFlappyBirdUI = {
---@type number
PassTime = 0,
---@type AmusementParkBirdBG
ParkBirdBG = nil,
---@type AmusementParkBirdObstacleCell[]
BirdObstacleCells = {},
---@type AmusementParkBirdObstacleCell 上一个被创建的障碍物
LastBirdObstacleCell = nil,
---@type Vector3 障碍物出生位置(固定在屏幕右侧)
BirthLocation = Vector3.New(670,0,0),
---@type UnityEngine.GameObject[] 障碍物预设集合
ObstaclePrefabs = {},
---@type AmusementParkBirdPlayer
BirdPlayer = nil,
---@type UnityEngine.Collider2D 上边界
UpCollider2D = nil,
---@type UnityEngine.Collider2D 下边界
DownCollider2D = nil,
}
AmusementParkGameFlappyBirdUI = Base:Extend("AmusementParkGameFlappyBirdUI", "IQIGame.Onigao.UI.AmusementParkGameFlappyBirdUI", AmusementParkGameFlappyBirdUI)
require("IQIGame.UIExternalApi.AmusementParkGameFlappyBirdUIApi")
local AmusementParkBirdBG = require("IQIGame.UI.ExploreHall.AmusementPark.AmusementParkBirdGame.AmusementParkBirdBG")
local AmusementParkBirdObstacleCell = require("IQIGame.UI.ExploreHall.AmusementPark.AmusementParkBirdGame.AmusementParkBirdObstacleCell")
local AmusementParkBirdPlayer = require("IQIGame.UI.ExploreHall.AmusementPark.AmusementParkBirdGame.AmusementParkBirdPlayer")
---界面初始化。
---@return void
function AmusementParkGameFlappyBirdUI:OnInit()
self.DelegateOnClickBtnClose = function() self:OnClickBtnClose() end
self.DelegateOnClickBtnStartGame = function() self:OnClickBtnStartGame() end
self.DelegateOnClickBtnRank = function() self:OnClickBtnRank() end
self.DelegateOnClickBtnRest = function() self:OnClickBtnRest() end
self.DelegateUpdateBirdGameRank = function() self:RefreshRank() end
self.DelegateOnClick = function() self:OnClick() end
self.UpCollider2D = self.Top:GetComponent(typeof(UnityEngine.Collider2D))
self.DownCollider2D = self.Bottom:GetComponent(typeof(UnityEngine.Collider2D))
self.ParkBirdBG = AmusementParkBirdBG.New(self.BGNode)
self.BirdPlayer = AmusementParkBirdPlayer.New(self.Player)
self.ObstaclePrefabs = {}
for i = 1, self.BalkPrefabs.transform.childCount do
local objTrs = self.BalkPrefabs.transform:Find(i)
if objTrs then
self.ObstaclePrefabs[i] = objTrs.gameObject
end
end
end
---OnInit预加载资源路径列表。
---@return table
function AmusementParkGameFlappyBirdUI:GetPreloadAssetPaths()
return nil
end
---OnOpen预加载资源路径列表。
---@return table
function AmusementParkGameFlappyBirdUI:GetOpenPreloadAssetPaths(userData)
return nil
end
---OnOpen时调用,判断当前UI是否在卡顿结束后手动显示
---@return boolean
function AmusementParkGameFlappyBirdUI:IsManualShowOnOpen(userData)
return false
end
---UI是否有独立的背景音乐,如果有则返回,否则返回nil,注意一个UI同时只能有一个背景音乐,如果需要切换,调用self.UIController:ChangeBGM()方法
---@return number @SoundCid
function AmusementParkGameFlappyBirdUI:GetBGM(userData)
return nil
end
---界面打开。
---@param userData table
---@return void
function AmusementParkGameFlappyBirdUI:OnOpen(userData)
AmusementParkBirdGameModule.GetBirdGameRank()
self:ResetGame()
end
---界面关闭。
---@param userData table
---@return void
function AmusementParkGameFlappyBirdUI:OnClose(userData)
end
---添加侦听。
---@return void
function AmusementParkGameFlappyBirdUI:OnAddListeners()
self.BtnClose:GetComponent("Button").onClick:AddListener(self.DelegateOnClickBtnClose)
self.BtnStartGame:GetComponent("Button").onClick:AddListener(self.DelegateOnClickBtnStartGame)
self.BtnRank:GetComponent("Button").onClick:AddListener(self.DelegateOnClickBtnRank)
self.BtnRest:GetComponent("Button").onClick:AddListener(self.DelegateOnClickBtnRest)
self.BtnJump:GetComponent("Button").onClick:AddListener(self.DelegateOnClick)
EventDispatcher.AddEventListener(EventID.APUpdateBirdGameRankEvent,self.DelegateUpdateBirdGameRank)
end
---移除侦听。
---@return void
function AmusementParkGameFlappyBirdUI:OnRemoveListeners()
self.BtnClose:GetComponent("Button").onClick:RemoveListener(self.DelegateOnClickBtnClose)
self.BtnStartGame:GetComponent("Button").onClick:RemoveListener(self.DelegateOnClickBtnStartGame)
self.BtnRank:GetComponent("Button").onClick:RemoveListener(self.DelegateOnClickBtnRank)
self.BtnRest:GetComponent("Button").onClick:RemoveListener(self.DelegateOnClickBtnRest)
self.BtnJump:GetComponent("Button").onClick:RemoveListener(self.DelegateOnClick)
EventDispatcher.RemoveEventListener(EventID.APUpdateBirdGameRankEvent,self.DelegateUpdateBirdGameRank)
end
---界面暂停。
---@return void
function AmusementParkGameFlappyBirdUI:OnPause()
end
---界面暂停恢复。
---@return void
function AmusementParkGameFlappyBirdUI:OnResume()
end
---界面遮挡。
---@return void
function AmusementParkGameFlappyBirdUI:OnCover()
end
---界面遮挡恢复。
---@return void
function AmusementParkGameFlappyBirdUI:OnReveal()
end
---界面激活。
---@param userData table
---@return void
function AmusementParkGameFlappyBirdUI:OnRefocus(userData)
end
---界面轮询。
---@param elapseSeconds number
---@param realElapseSeconds number
---@return void
function AmusementParkGameFlappyBirdUI:OnUpdate(elapseSeconds, realElapseSeconds)
if AmusementParkBirdGameModule.apBirdGameData.startGame then
self.ParkBirdBG:OnUpdate(elapseSeconds, realElapseSeconds)
self.BirdPlayer:OnUpdate(elapseSeconds, realElapseSeconds)
if PlayerModule.GetServerTime() - self.PassTime > 1 then
self.PassTime = PlayerModule.GetServerTime()
self:RefreshScore()
AmusementParkBirdGameModule.PixelBird()
end
---检障碍物创建
if self.LastBirdObstacleCell then
local direction = self.BirthLocation.x - self.LastBirdObstacleCell.View.transform.localPosition.x
if direction >= AmusementParkBirdGameModule.apBirdGameData:GetCfgData().BalkCoolDown then
self.LastBirdObstacleCell = nil
self:CreateObstacle()
end
end
for i, v in pairs(self.BirdObstacleCells) do
v:OnUpdate(elapseSeconds, realElapseSeconds)
if v.View.transform.localPosition.x < -self.BirthLocation.x then
v:Dispose()
self.BirdObstacleCells[i] = nil
end
end
---碰撞检测
local result = self:CheckCollision()
if result then
self:GameOver()
end
end
end
---界面深度改变。
---@param uiGroupDepth number
---@param depthInUIGroup number
---@return void
function AmusementParkGameFlappyBirdUI:OnDepthChanged(uiGroupDepth, depthInUIGroup)
end
---加载资源成功
---该方法委托类型为底层框架类型
---@param assetName string
---@param asset table
---@param duration number
---@param userData table
---@return void
function AmusementParkGameFlappyBirdUI:OnLoadSucceed(assetName, asset, duration, userData)
end
---加载资源失败
---该方法委托类型为底层框架类型
---@param assetName string
---@param status number
---@param errorMessage string
---@param userData table
---@return void
function AmusementParkGameFlappyBirdUI:OnLoadFailed(assetName, status, errorMessage, userData)
end
---销毁
function AmusementParkGameFlappyBirdUI:OnDestroy()
AssetUtil.UnloadAsset(self)
self.ParkBirdBG:Dispose()
self.BirdPlayer:Dispose()
self:CleanObstacles()
end
function AmusementParkGameFlappyBirdUI:OnClickBtnClose()
UIModule.CloseSelf(self)
end
---创建障碍物
function AmusementParkGameFlappyBirdUI:CreateObstacle()
local index = math.random(1,#AmusementParkBirdGameModule.apBirdGameData:GetCfgData().BalkGroup)
local id = AmusementParkBirdGameModule.apBirdGameData:GetCfgData().BalkGroup[index]
local obj = UnityEngine.Object.Instantiate(self.ObstaclePrefabs[id])
obj:SetActive(true)
local speed = AmusementParkBirdGameModule.apBirdGameData:GetCfgData().HorizontalSpeed
local cell = AmusementParkBirdObstacleCell.New(obj)
cell.View.transform:SetParent(self.ObstacleNode.transform,false)
cell.View.transform.localPosition = self.BirthLocation
cell:SetData(speed)
table.insert(self.BirdObstacleCells,cell)
self.LastBirdObstacleCell = cell
end
function AmusementParkGameFlappyBirdUI:UpdateView()
self.ResultView:SetActive(false)
---@type AmusementParkBirdGameData
local apBirdGameData = AmusementParkBirdGameModule.apBirdGameData
self.ParkBirdBG:SetSpeed(apBirdGameData:GetCfgData().HorizontalSpeed)
UGUIUtil.SetText(self.TextCurrentLV,AmusementParkGameFlappyBirdUIApi:GetString("TextCurrentLV",apBirdGameData:GetCfgData().Level))
self:RefreshScore()
self:RefreshRank()
end
---清空障碍物
function AmusementParkGameFlappyBirdUI:CleanObstacles()
for i, v in pairs(self.BirdObstacleCells) do
v:Dispose()
end
self.BirdObstacleCells = {}
end
function AmusementParkGameFlappyBirdUI:RefreshScore()
UGUIUtil.SetText(self.TextGameScore,AmusementParkGameFlappyBirdUIApi:GetString("TextGameScore",AmusementParkBirdGameModule.apBirdGameData:GetGameScore()))
UGUIUtil.SetText(self.TextMaxLv,AmusementParkGameFlappyBirdUIApi:GetString("TextCurrentLV",AmusementParkBirdGameModule.maxLv))
UGUIUtil.SetText(self.TextMaxScore,AmusementParkGameFlappyBirdUIApi:GetString("TextGameScore",AmusementParkBirdGameModule.maxScore))
end
function AmusementParkGameFlappyBirdUI:RefreshRank()
local showMyRank = AmusementParkBirdGameModule.myRanking
self.TextRankTag:SetActive(false)
if showMyRank > 999 then
showMyRank = 999
self.TextRankTag:SetActive(true)
end
UGUIUtil.SetText(self.TextRank,AmusementParkGameFlappyBirdUIApi:GetString("TextRank",showMyRank))
end
function AmusementParkGameFlappyBirdUI:OnClick()
local speed = AmusementParkBirdGameModule.apBirdGameData:GetCfgData().VerticalUpSpeed
local acceleration = AmusementParkBirdGameModule.apBirdGameData:GetCfgData().VerticalUpAcceleration
self.BirdPlayer:SetData(acceleration,speed)
end
---碰撞检测
---@return boolean
function AmusementParkGameFlappyBirdUI:CheckCollision()
local top = false
---边界检测
top = self.BirdPlayer:CheckBirdBoundsIntersects(self.UpCollider2D)
if top then
return true
end
top = self.BirdPlayer:CheckBirdBoundsIntersects(self.DownCollider2D)
if top then
return true
end
---障碍物检测
for i, v in pairs(self.BirdObstacleCells) do
top = self.BirdPlayer:CheckBirdBoundsIntersects(v.TopCollider2D)
if not top then
top = self.BirdPlayer:CheckBirdBoundsIntersects(v.BottomCollider2D)
end
if top then
return true
end
end
return top
end
---游戏结束
function AmusementParkGameFlappyBirdUI:GameOver()
AmusementParkBirdGameModule.PixelBird()
AmusementParkBirdGameModule.apBirdGameData:EndGame()
self.BirdPlayer:PlayerDead()
self.ResultView:SetActive(true)
end
---重置游戏
function AmusementParkGameFlappyBirdUI:ResetGame()
AmusementParkBirdGameModule.CreateNewGame()
self.ParkBirdBG:ResetPos()
self.BirdPlayer:ResetPlayer()
self.BtnStartGame:SetActive(true)
self:CleanObstacles()
self:UpdateView()
end
---开始游戏
function AmusementParkGameFlappyBirdUI:OnClickBtnStartGame()
self.BtnStartGame:SetActive(false)
self.ParkBirdBG:SetStartMove(true)
AmusementParkBirdGameModule.apBirdGameData:StartGame()
self:CreateObstacle()
end
---重置游戏
function AmusementParkGameFlappyBirdUI:OnClickBtnRest()
self:ResetGame()
end
---查看排行榜
function AmusementParkGameFlappyBirdUI:OnClickBtnRank()
UIModule.Open(Constant.UIControllerName.AmusementParkGameFlappyBirdRankUI,Constant.UILayer.UI)
end
return AmusementParkGameFlappyBirdUI