【Unity】RPG2D龙城纷争(六)关卡编辑器之角色编辑

更新日期:2024年6月26日。
项目源码:第五章发布(正式开始游戏逻辑的章节)

索引

  • 简介
    • 一、角色编辑模式
      • 1.将字段限制为只读
      • 2.创建角色(刷角色)
      • 3.预览所有角色
      • 4.编辑选中角色属性
      • 5.移动角色位置
      • 6.移除角色

简介

上一篇完成的关卡编辑器已支持创建关卡环境(主要由地块单元组成),本篇,在关卡环境的基础上,需要完成角色编辑、要诀编辑等功能(角色编辑模式)。

一、角色编辑模式

1.将字段限制为只读

在开始角色编辑模式之前,我们对角色(Role)地块(Block)类定义的字段进行一些改进,为一些字段添加ReadOnly特性标记:

    public class Role : HTBehaviour
    {
        /// <summary>
        /// 角色头像
        /// </summary>
        [Label("角色头像"), ReadOnly] public Sprite HeadImage;

		//其他省略......
	}

    public class Block : HTBehaviour
    {
        /// <summary>
        /// 类型
        /// </summary>
        [Label("类型"), ReadOnly] public BlockType Type;

		//其他省略......
	}

ReadOnly使得该字段为只读的,在检视器面板上不可编辑。

在这里插入图片描述

这样做的目的是防止这些属性被不小心篡改,因为他们都将交由关卡编辑器来权衡设置。

当然你也可以不这样做,只需去掉ReadOnly标记即可。

2.创建角色(刷角色)

试想一下角色编辑的功能该如何展现,第一步必然是能够创建角色,在这里我们想像刷地块一样,鼠标停留到一个位置,直接就能在该位置刷出一个角色。

那么,着手开干:

        /// <summary>
        /// 是否激活角色刷子
        /// </summary>
        private bool _isActiveRoleBrush = false;
        /// <summary>
        /// 角色刷子类型名称
        /// </summary>
        private string[] _roleBrushTypeName = new string[] { "玩家", "敌人" };
        /// <summary>
        /// 角色刷子类型(刷出来的角色属于此阵营)
        /// </summary>
        private RoleCamp _roleBrushType = RoleCamp.Player;
        /// <summary>
        /// 角色刷子数据集(刷出来的角色使用此数据集)
        /// </summary>
        private RoleDataSet _roleDataSet;

        /// <summary>
        /// 创建一个角色
        /// </summary>
        /// <param name="block">角色所在地块</param>
        /// <param name="dataSet">角色数据集</param>
        private void CreateRole(Block block, RoleDataSet dataSet)
        {
        	//通过角色模板 _roleTmp 创建一个新角色
            GameObject obj = PrefabUtility.InstantiatePrefab(_roleTmp) as GameObject;
            obj.name = "Role";
            obj.transform.SetParent(_level.RolesRoot);
            obj.transform.localPosition = new Vector3(block.transform.position.x, block.transform.position.y, -1);
            obj.transform.localRotation = Quaternion.identity;
            obj.transform.localScale = Vector3.one;
            obj.SetActive(true);

			//为角色生成一个随机ID,并应用刷子类型(角色阵营),这里类似刷地块的逻辑
            Role role = obj.GetComponent<Role>();
            role.ID = Guid.NewGuid().ToString();
            role.Name = dataSet.name;
            role.Camp = _roleBrushType;
            //设置角色数据集
            role.SetDataSet(dataSet);
            _roles.Add(role);

			//与地块建立关联
            role.StayBlock = block;
            block.StayRole = role;

            EditorUtility.SetDirty(role);
            EditorUtility.SetDirty(block);

            Selection.activeGameObject = obj;
        }

如上,完成了创建角色的方法,再通过刷子相关的控制变量,实现UI控件面板后:

在这里插入图片描述

要实现按1键开刷的功能,依然是在OnSceneGui方法中补充代码:

        private void OnSceneGui(SceneView sceneView)
        {
            if (Event.current == null)
                return;

            if (_editMode == EditMode.Map && _isActiveMapBrush)
            {
               //地块编辑模式
            }
            else if (_editMode == EditMode.Role && _isActiveRoleBrush && _roleDataSet != null)
            {
                if (Event.current.isKey && Event.current.keyCode == KeyCode.Alpha1 && Event.current.type == EventType.KeyDown)
                {
                	//将Scene视图坐标转换为世界坐标
                    Vector2 pos = ScreenToWorldPointInScene(sceneView.camera, Event.current.mousePosition);
                    //获取坐标位置的地块
                    Block block = GetBlockByPoint(pos);
                    if (block)
                    {
                    	//必须该地块不存在角色
                        if (block.StayRole == null)
                        {
                        	//才在该地块创建一个角色
                            CreateRole(block, _roleDataSet);
                        }
                    }
                }

                EditorGUIUtility.AddCursorRect(sceneView.position, MouseCursor.SlideArrow);
            }
        }

此时,我们便可以创建一个角色数据集,然后开刷了:

在这里插入图片描述

不过,刚刷出来的角色是没有头像的,这里显示为红色是因为他所属敌方阵营

而且,角色头像前面已经被我们搞成ReadOnly了,这里也修改不了啊(检视器面板只能看),所以,迫切需要在关卡编辑器中实现对这一个个灰色属性的编辑功能。

3.预览所有角色

首先,为了能全局预览场景中的所有角色,我们先将所有角色按阵营进行分类展示:

        /// <summary>
        /// 玩家角色数量
        /// </summary>
        private int _playerNum;
        /// <summary>
        /// 敌人角色数量
        /// </summary>
        private int _enemyNum;
        /// <summary>
        /// 当前选中的角色物体
        /// </summary>
        private GameObject _currentSelectRoleObj;
        /// <summary>
        /// 当前选中的角色
        /// </summary>
        private Role _currentSelectRole;
        /// <summary>
        /// 是否显示所有玩家角色
        /// </summary>
        private bool _isShowPlayer = false;
        /// <summary>
        /// 是否显示所有敌人角色
        /// </summary>
        private bool _isShowEnemy = false;

通过加入上面的控制代码,然后再结合UI控件代码,实现在2个区域(玩家、敌人阵营)分别预览所有角色(UI控件代码就不贴了,看看源码就一目了然):

在这里插入图片描述

4.编辑选中角色属性

我们规定同时只能选中一个角色,进而进入编辑此角色状态。

那么,当选中角色时(Scene视图中选中角色物体),角色会被赋予到_currentSelectRoleObj_currentSelectRole

Tip:为了避免重复GetComponent<Role>(),使用_currentSelectRole来缓存当前角色物体身上的Role组件。

        private void EditRoleGUI()
        {
        		//如果Scene视图中选择的目标物体改变
                if (_currentSelectRoleObj != Selection.activeGameObject)
                {
                	//则尝试获取其上的Role组件
                    _currentSelectRoleObj = Selection.activeGameObject;
                    _currentSelectRole = _currentSelectRoleObj != null ? _currentSelectRoleObj.GetComponent<Role>() : null;
                }
                if (_currentSelectRole != null)
                {
                	//此时便选中了角色,在这里展示角色的相关属性,同时支持编辑
                }
        }

通过敲完繁琐的UI控件代码后,现在的编辑器界面便是这样:

在这里插入图片描述

在这里,我们可以重新赋予角色的数据集,以更换其内核。

赋予头像灰色头像(仅当角色禁用时展示),头像改变后,会立即体现在角色头像渲染器上:

在这里插入图片描述

角色的ID属性极其重要,在关卡间角色的属性继承存档读档剧情对话等一系列需要定位指定角色的功能,都是通过ID来确定的,所以ID不能重复,当然这里默认生成的Guid.NewGuid()是绝对不重复的。

只不过,为了方便后续关卡进行对应,主角的ID建议单独设置,比如某个主角ID为001,那么在所有关卡中,他的ID都必须为001

当我们把角色状态切换为Not Yet On Stage时,此角色将延时登场:

在这里插入图片描述

然后,下面列出了角色的8个要诀栏位对应的数据集,我们可以创建一系列要诀数据集,然后给每个角色都进行配置,4-8栏位会自动根据角色的等级进行激活,当然,也可以在后期使用要诀研习系统,为指定的角色学习任意要诀。

在这里插入图片描述

5.移动角色位置

如果我们想修改一个角色的位置,直接删了重新刷是一种笨办法,但因为角色的位置与其所处的地块存在直接关联,我们手动调节角色的位置自然是不可行的,所以需要实现控制角色移动的功能,比如:

        if (GUILayout.Button("上移", "ButtonLeft"))
        {
        	//保留角色所站的旧地块
            Block oldBlock = _currentSelectRole.StayBlock;
            //获取角色位置上方+1格的地块,为新地块
            Block newBlock = GetBlockByIndex(oldBlock.Pos + new Vector2Int(0, 1));
            if (newBlock != null && newBlock.StayRole == null)
            {
                _currentSelectRole.transform.localPosition = new Vector3(newBlock.transform.position.x, newBlock.transform.position.y, -1);

				//交换新、旧地块的关联属性
                oldBlock.StayRole = null;
                _currentSelectRole.StayBlock = newBlock;
                newBlock.StayRole = _currentSelectRole;

                EditorUtility.SetDirty(oldBlock);
                EditorUtility.SetDirty(newBlock);
                EditorUtility.SetDirty(_currentSelectRole);
            }
        }

需要上、下、左、右移动功能,才能让角色可以变换到地图中的任意位置:

在这里插入图片描述

6.移除角色

同样的,自然需要移除角色的功能,我们在UI面板上已经画好了控件,只需实现对应的移除角色功能即可:

        /// <summary>
        /// 移除一个角色
        /// </summary>
        /// <param name="role">角色</param>
        private void RemoveRole(Role role)
        {
            _roles.Remove(role);

            Block block = role.StayBlock;
            role.StayBlock = null;
            block.StayRole = null;

			//立即销毁角色物体
            DestroyImmediate(role.gameObject);
            EditorUtility.SetDirty(block);
        }

至此,角色编辑的功能便初步完成了,我们能够在关卡上任意布局角色编辑角色属性编辑角色要诀等,为后续驱动角色,进而驱动整个游戏逻辑打下了坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/747817.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux OpenGrok搭建

文章目录 一、目的二、环境三、相关概念3.1 OpenGrok3.2 CTags3.3 Tomcat 四、OpenGrok搭建4.1 安装jdk4.2 安装ctags依赖4.3 安装universal-ctags4.3.1 下载universal-ctags4.3.2 编译&&安装universal-ctags 4.4 安装Tomcat4.4.1 下载&&解压Tomcat4.4.2 启动T…

HQChart使用教程30-K线图如何对接第3方数据41-分钟K线叠加股票增量更新

HQChart使用教程30-K线图如何对接第3方数据40-日K叠加股票增量更新 叠加股票叠加分钟K线更新Request 字段说明Data.symbol 协议截图返回json数据结构overlaydata HQChart代码地址交流 叠加股票 示例地址:https://jones2000.github.io/HQChart/webhqchart.demo/samples/kline_i…

泰迪智能科技大数据挖掘企业服务平台典型合作案例介绍

泰迪大数据挖掘企业服务平台 是一款通用的、企业级、智能化的数据分析模型构建与数据应用场景设计工具&#xff0c;能够一体化地完成数据集成、模型构建、模型发布&#xff0c;为数据分析、探索、服务流程提供支撑&#xff0c;提供完整的数据探索、多数据源接入、特征处理、模型…

软硬链接 以及 动静态链接

目录 1 软硬链接 2 动静态库 1 软硬链接 不知道大家也没有仔细看过我们的 windows 中的快捷方式的内容&#xff0c;我们右键点开一个快捷方式然后查看其属性&#xff0c;我们发现有一个 目标 的内容 这个目标是一串路径&#xff0c;这也就是我们的程序的安装路径中的一个.exe…

浅浅谈谈如何利用Javase+多线程+计算机网络的知识做一个爬CSDN阅读量总访问量的程序

目录 我们发现csdn的文章 首先为了印证我们的想法 我们用postman往csdn我们任意一篇文章发起post请求 发送请求 ​编辑获得响应结果 我们发现我们的阅读量上涨 PostRequestSender类 但是我们经过测试发现 定义一个字符串数组 把URL放进去 然后延迟启动 在线程池里面…

redis哨兵模式(Redis Sentinel)

哨兵模式的背景 当主服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费事费力&#xff0c;还会造成一段时间内服务不可用。这不是一种推荐的方式。 为了解决单点故障和提高系统的可用性&#xff0c;需要一种自动化的监…

司美格鲁肽在中国获批!深度解析报告附上

在中国&#xff0c;肥胖问题日益严重&#xff0c;但有效的治疗方法却相对匮乏。然而&#xff0c;这一现状随着国家药品监督管理局&#xff08;NMPA&#xff09;对诺和诺德公司研发的司美格鲁肽注射液&#xff08;商品名&#xff1a;诺和盈&#xff09;的批准而得到改变。6月25日…

JavaEE之HTTP协议(1)_HTTP基础知识,HTTP 请求、响应格式,方法,状态码

一、HTTP协议 1.1 基本概念: HTTP全称超文本传输协议&#xff0c;是一种无状态的、应用层的协议&#xff0c;它基于请求/响应模型。客户端&#xff08;通常是Web浏览器&#xff09;通过发送HTTP请求到服务器来获取或发送信息&#xff0c;服务器则返回HTTP响应作为回应。HTTP协…

【设计模式】行为型-策略模式

策略模式&#xff0c;如春风吹过&#xff0c;随心所欲&#xff0c;变幻无穷&#xff0c;每一丝风都是一种选择。 文章目录 一、订单处理二、策略模式三、策略模式的核心组成四、运用策略模式五、策略模式的应用场景六、小结推荐阅读 一、订单处理 场景假设&#xff1a;有一个…

使用CDN方式创建Vue3.0应用程序

CDN 的全称是 content delivery network&#xff0c;即内容分发网络。它是构建在现在的互联网基础之上的一层智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分发和调度等功能模块&#xff0c;使用户就近获取所需内容&#xff0c…

2023 年度国家科学技术奖励公布

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

引用别的组件

在脚本中&#xff0c;也可以引用别的物体下的组件。 第一种办法&#xff0c; &#xff08;1&#xff09;添加一个变量&#xff0c; public GameObject bgmNode ; 然后在检查器里指定这个引用。 例如&#xff1a;在背景音乐空物体下面有个Audio Source组件 游戏主控脚本代码…

Python | Leetcode Python题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; class Solution:def dfs(self, grid, r, c):grid[r][c] 0nr, nc len(grid), len(grid[0])for x, y in [(r - 1, c), (r 1, c), (r, c - 1), (r, c 1)]:if 0 < x < nr and 0 < y < nc and grid[x][y] "1":self.d…

网约车停运损失费:2、协商过程

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

Jackson和fastjson解决序列化时字段属性大小写改变的问题

在部分特殊场景下&#xff0c;我们可能会把实体的字段属性改成全部大写&#xff0c;但是在返回前端时&#xff0c;字段会被序列化成小写。 比如我们有一个这个类属性都是大写&#xff1a; 后端接口是这样的 然后我们请求后&#xff0c;会发现我们的字段被变成全部小写的。 …

windows USB 设备驱动开发-总章

通用串行总线 (USB) 提供可扩展的即插即用串行接口&#xff0c;确保外围设备的标准、低成本的连接。 USB 设备包括键盘、鼠标、游戏杆、打印机、扫描仪、存储设备、调制解调器、视频会议摄像头等。USB-IF 是一个特别兴趣组 (SIG)&#xff0c;负责维护官方 USB 规范、测试规范和…

vs code + Keil Assistant 配置 Keil 单片机开发

1、 先安装vscode完成后 安装插件 2 安装C/C 与 keil Assistant 需说明一下 Assistant 1.7.0版本有bug F7按不了 所以安装1.6.2版本 以下是我的安装插件 EMBEDDED IDE 可安装 可不安装 随便你 3 配置 Assistant 4、设置C/C 目录 ${workspaceFolder}/**D:/Keil_v5/C51/INC/**…

构建 Audio Unit 应用程序

构建 Audio Unit 应用程序 构建 Audio Unit 应用程序从选择设计模式开始I/O Pass ThroughI/O Without a Render Callback FunctionI/O with a Render Callback FunctionOutput-Only with a Render Callback Function其他设计模式 构建应用程序配置 audio session指定 audio uni…

Linux系统安装和卸载nginx

&#x1f4d6;Linux系统安装和卸载nginx ✅下载✅安装✅启动nginx✅安装成系统服务✅常见问题&#xff1a;80端口被占用了✅卸载✅目录结构 以下介绍的是以源码编译安装方式&#xff1a; ✅下载 官方地址&#xff1a;https://nginx.org/en/download.html 123云盘地址&#x…

MySQL表解锁

查看锁信息 show full processlist 如果一个表被锁定了&#xff0c;会有一个 “Waiting for table metadata lock” 的提示&#xff0c;表明该表正在等待锁定。 解锁表 删除state上有值的事务 kill query 事务id 表解锁完成