IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Lua语言实现Unity红点系统 -> 正文阅读

[游戏开发]Lua语言实现Unity红点系统


前言

曾几何时,导师问我对红点系统的想法,我思考了一下大概说了一下我的思路,与项目组的红点系统的实现方式不一样,但是也具备理论可行性,于是导师让我自己实现一套红点系统,并能应用到项目当中去,最终实现成功,在此记录,代码中用到了一点项目中封装的方法。


一、设计思路

提供了一个结点类来实现内部逻辑,以及一个manager类提供对外接口。

1. 结点类
红点系统说白了就是树的数据结构,于是节点信息存储哪些便是关键,节点结构如下:

  • 节点名(nodeName),我将节点名设置为结点的key,也就是唯一标识,这也就要求节点名不能重名。(也可以用ID来设置唯一标识)
  • 父节点名(parentNodeName),可通过父节点名索引到父节点。
  • 存储子节点信息的表(childNodeMap)。
  • 计数(count),对子节点来说,count为1或者0即红点状态显示与否,对中间节点来说,count是它的所有红点显示的子节点的数量,当有子节点显示是即count > 0,则中间节点也显示,中间节点的表现应当完全由叶子节点决定。
  • gameobject,每个节点对应unity中的游戏物体

除了节点结构,还维护了两张表,gameobjectMap{}用来存储gameobject和对应节点,nodeNameMap{}用来存储节点名和对应节点,防止每次创建新节点时检验避免重复创建。
此外还有一些方法来实现对应逻辑。包括创建节点,设置父节点,绑定游戏物体,递归刷新红点树等。

2. manager类
manager类里提供了一些对外的接口,后续可以根据需要不断优化。基础的有创建新节点,绑定gameobject,从叶节点开始刷新红点树等。


二、Lua实现

1.节点类

local RedPointNode = luaclass("RedPointNode")  --封装的方法,lua实现类

--key是gameobject value是节点,存储信息保证gameobject和节点一对一
local gameObjectMap = {}

--key是nodeName,value是节点,nodeName作为唯一标识要求不能重名,防止重复创造红点节点
local nodeNameMap = {}

function RedPointNode:initialize(nodeName,parentNodeName)
	self:Init(nodeName,parentNodeName)
end

--节点信息初始化
function RedPointNode:Init(nodeName,parentNodeName)
	self.nodeName = nodeName
	self.parentNodeName = parentNodeName
	self.childNodeMap = {}  --key是子节点名,value是子节点
	self.count = 0
	self.gameobject = nil

	nodeNameMap[nodeName] = self

	--将新加入的节点加到父节点的childMap中
	if parentNodeName then
		self:SetParentNode(RedPointNode:GetNodeByName(parentNodeName))
	end
end

--红点是否显示
function RedPointNode:IsShow()
	return self.count > 0
end

--添加子节点
function RedPointNode:AddChildNode(childNode)
	self.childNodeMap[childNode.nodeName] = childNode
	childNode.parentNode = self
end

--设置父节点,传入父节点,注意区分节点和节点名
function RedPointNode:SetParentNode(parentNode)
	if not parentNode then
		logError("父节点不存在")
		return
	end
	self.parentNode = parentNode
	if parentNode then
		parentNode:AddChildNode(self)
	end
end

--根据节点名从nodeNameMap中获取节点
function RedPointNode:GetNodeByName(nodeName)
	return nodeNameMap[nodeName]
end

--根据节点名获取子节点
function RedPointNode:GetChildNode(nodeName)
	for k,v in pairs(self.childNodeMap or {}) do
		if k == nodeName then
			return v
		end
	end
end

--移除子节点
function RedPointNode:RemoveChildNode(nodeName)
	self.childNodeMap[nodeName] = nil
end

--从叶节点刷新红点状态
function RedPointNode:UpdateLeafNode(isShow)
	if self:IsShow() == isShow then
		logError("叶子节点状态不变")
		return
	end
	self:UpdateNode(isShow)
end

--递归刷新红点树
function RedPointNode;UpdateNode(isShow)
	if isShow == true then
		self.count = self.count + 1
	elseif isShow == false then
		self.count = self.count - 1
	end
	
	self:RefreshVisible()
	
	if self.parentNode then
		self.parentNode:UpdateNode(isShow)
	end
end

--为红点绑定gameobject,要求gameobject和节点一对一
function RedPointNode:SetGameObject(gameObject)
	if gameObject then --把gameobject上绑定的节点取消,防止一个节点绑定多个gameobject
		if gameObjectMap[gameObject] then
			gameObjectMap[gameObject].gameObject = nil
		end
	end

	if self.gameObject then  --把节点原来对应的gameObject取消,防止一个节点绑定多个gameobject
		gameObjectMap[self.gameObject] = nil
	end
	self.gameObject = gameObject
	if gameObject then
		gameObjectMap[gameObject] = self
	end
	
	self:RefreshVisible()
end

--刷新红点对象显示
function RedPointNode:RefreshVisible()
	if self.gameObject then
		if CSLuaHelper.IsNull(self.gameObject) == 1 then
			logError("gameObject is destory")
			return
		end
	
	self.gameObject:SetActive(self:IsShow())
	end
end


2.红点树管理类,接口类

local RedPointClass = {}

--创建新节点,传入节点名(ID)和父节点
function RedPointClass:CreateNode(nodeName,parentNodeName)
	if nodeNameMap[nodeName] then
		logError("节点已经存在")
		return
	end
	return RedPointNode(nodeName,parentNodeName)
end

--为该节点设置gameObject,传入一个gameobject
function RedPointClass:SetNodeGameObject(nodeName,gameObject)
	if not nodeNameMap[nodeName] then
		logError("该节点不存在")
		return
	end
	nodeNameMap[nodeName]:SetGameObject(gameObject)
end

--从叶节点开始向上刷新红点树,调用者必须是叶节点
function RedPointClass:RefreshFromLeaf(nodeName,isShow)
	if Linq.Count(nodeNameMap[nodeName].childNodeMap ~= 0 then  --不是叶节点
		logError("调用者必须是叶节点")
		return
	end
	nodeNameMap[nodeName]:UpdateLeafNode(isShow)
end

function RedPointClass:Log()
	logError("用于debug")
end

return RedPointClass
	 
	 

总结

该红点系统的使用流程为

  1. 创建节点
  2. 绑定gameobject
  3. 叶节点调用刷新红点树

需要注意的地方有:

  • 必须先从根节点开始创建节点,子节点创建要保证父节点已经存在。
  • 节点名(nodeName)在这个系统中是唯一标识,是每个节点的key,也就是说不允许重名出现,如果有重名需求,可以在节点信息中添加self.Id来作为key,再维护一张“ ID—节点” 表。
  • 红点树的维护是在游戏init的时候就生成,而绑定gameObject是在页面initUI的时候操作,所以在每次绑定完gameObject需要再刷新一次表现。
  • 中间节点完全由子节点影响表现,对于刷新红点树接口只能叶节点调用,递归刷新上层节点,中间节点的表现取决于它有没有子节点有红点存在。
  • 对于叶子节点的count应当控制在1 or 0,即对应显示和不显示的表现,所以当对已经显示(count == 1)的叶子节点刷新isShow为显示的时候,企图给count+1,应当进行处理,判断叶子节点状态有没有改变,count是0亦如此。
  • 根据需求可以在接口类实现更多接口例如获取子节点,从nodeNameMap中获取节点,删除节点等,也可以在节点类进行拓展以实现更多功能。
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-08 11:04:24  更:2021-09-08 11:04:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/22 7:57:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码