设计概述

这个模块是一个基于Qt的蓝图式技能编辑器状态机,主要用于游戏开发中的技能状态管理。核心功能包括:

  • 状态节点(开始、结束、普通状态)的可视化

  • 状态间连线的绘制与管理

  • 状态转换逻辑的可视化编辑

  • 动作选择与配置

核心类设计

1. 状态节点类 (QSkeBlendGraphics)

class QSkeBlendGraphics : public QGraphicsItem {
public:// 状态类型枚举enum StateType {SKE_BELEN_STATUE_EMPTY,    // 空状态SKE_BELEN_STATUE_NORMAL,   // 普通状态SKE_BELEN_STATUE_BEGIN,    // 开始状态SKE_BELEN_STATUE_END       // 结束状态};// 核心方法void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;QRectF boundingRect() const override;void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;void setSkaName(QString name); // 设置动作名称private:StateType m_state;     // 当前状态类型QString m_name;        // 状态名称QString m_skaName;     // 关联的动作名称QPointF m_pos;         // 位置信息int m_nProgerssValue;  // 进度值(0-100)QAnimationDlg* m_pAniViewWidget; // 父窗口指针
};

2. 状态连线类 (QLineArray)

class QLineArray : public QGraphicsItem {
public:// 核心方法void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;QRectF boundingRect() const override;void setLineItem(QPointF startP, QPointF endP); // 设置连线起止点private:QSkeBlendGraphics* m_skeStar; // 起始状态节点QSkeBlendGraphics* m_skeEnd;  // 结束状态节点QPointF m_EndP;               // 终点位置QPointF m_MidP;               // 中点位置(用于箭头计算)QPointF m_points[3];          // 箭头三角形点
};

3. 状态场景管理类 (QSkeblendScene)

class QSkeblendScene : public QGraphicsScene {
public:// 场景操作void drawBackground(QPainter *painter, const QRectF &rect) override;void deleteSelect(); // 删除选中项void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override;private:QAnimationDlg* m_pAniWnd; // 父窗口bool m_bShowFrid;          // 是否显示网格QSkeBlendGraphics* m_pSelCOpy; // 当前复制的状态
};

4. 状态视图类 (QSkeblendGraphicsView)

class QSkeblendGraphicsView : public QGraphicsView {
public:// 视图操作void wheelEvent(QWheelEvent* event) override; // 滚轮缩放void drawBackground(QPainter *painter, const QRectF &rect) override;// 缩放功能void zoomIn();void zoomOut();void zoomOriginal();private:bool m_wheelZoomEnabled; // 是否启用滚轮缩放qreal m_zoomFactor;      // 当前缩放因子
};

核心功能实现

状态节点绘制

void QSkeBlendGraphics::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {// 根据状态类型设置不同颜色switch(m_state) {case SKE_BELEN_STATUE_NORMAL:painter->setBrush(isSelected() ? QColor(100,100,100) : QColor(118,118,118));break;case SKE_BELEN_STATUE_BEGIN:painter->setBrush(QColor(45,206,46)); // 绿色break;case SKE_BELEN_STATUE_END:painter->setBrush(QColor(219,12,12)); // 红色break;case SKE_BELEN_STATUE_EMPTY:painter->setBrush(QColor(114,124,114)); // 灰色break;}// 绘制圆角矩形作为状态节点主体QRect rcRectItem(10, 10, RECT_BLEND_GRAPHICS_NE_WIGHT, RECT_BLEND_GRAPHICS_NE_HEIGHT);painter->drawRoundRect(rcRectItem, RECT_BLEND_GRAPHICS_NE_RECT, RECT_BLEND_GRAPHICS_NE_RECT);// 添加渐变效果QLinearGradient Linear(QPointF(10, 10), QPointF(10, rcRectItem.height()));// ... 根据状态类型和选中状态设置渐变颜色// 绘制状态名称painter->setPen(QColor(225,225,225));QFont font = painter->font();font.setPointSize(10);painter->setFont(font);painter->drawText(QPoint(10 + nXposFont, 25), m_name);// 绘制进度条(如果有)if(m_nProgerssValue < 99) {painter->setBrush(QColor(45,46,45));painter->drawRoundedRect(nXposStar, nYPosStar, width, height, 2, 2);// 绘制进度int progressWidth = (m_nProgerssValue * totalWidth) / 100;painter->setBrush(QColor(0,122,204));painter->drawRect(progressRect);}
}

状态连线绘制

void QLineArray::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {painter->setRenderHint(QPainter::Antialiasing, true);// 设置连线颜色(选中/未选中)if (isSelected()) {painter->setBrush(m_SelColor);painter->setPen(QPen(m_SelColor, 2, Qt::SolidLine));} else {painter->setBrush(m_Color);painter->setPen(QPen(m_Color, 2, Qt::SolidLine));}// 绘制连接线QLineF line(0, 0, m_EndP.x(), m_EndP.y());painter->drawLine(line);// 绘制箭头painter->drawPolygon(m_points, 3);
}void QLineArray::CreatePointNodes() {// 计算箭头位置float angle = atan2(m_MidP.y(), m_MidP.x()) + PI;const float arrowLength = 15;const float arrowAngle = 0.3;m_points[0] = m_MidP;m_points[1].setX(m_MidP.x() + arrowLength * cos(angle - arrowAngle));m_points[1].setY(m_MidP.y() + arrowLength * sin(angle - arrowAngle));m_points[2].setX(m_MidP.x() + arrowLength * cos(angle + arrowAngle));m_points[2].setY(m_MidP.y() + arrowLength * sin(angle + arrowAngle));
}

场景背景绘制

void QSkeblendScene::drawBackground(QPainter *painter, const QRectF &rect) {if (m_bShowFrid) {// 绘制网格背景for (int i = 0; i < 300; i++) {if (i % 10 == 0) {painter->setPen(QPen(QColor(25,25,25), 1));} else {painter->setPen(QPen(QColor(34,34,34), 1));}// 绘制水平线painter->drawLine(startX, startY + i * gridH, gridW * 1000 + startX, startY + i * gridH);// 绘制垂直线painter->drawLine(startX + gridW * i, startY, startX + i * gridW, startY + gridH * 1000);}} else {// 纯色背景painter->setPen(Qt::NoPen);painter->setBrush(QBrush(QColor(192,192,192)));painter->drawRect(rect);}
}

视图缩放功能

void QSkeblendGraphicsView::wheelEvent(QWheelEvent* event) {if (m_wheelZoomEnabled && (event->modifiers() & Qt::ControlModifier)) {if (event->angleDelta().y() > 0) {zoomIn(); // 放大} else {zoomOut(); // 缩小}} else {QGraphicsView::wheelEvent(event);}
}void QSkeblendGraphicsView::zoomIn() {m_zoomFactor *= 1.2;if (m_zoomFactor > 256) m_zoomFactor = 256;performZoom();
}void QSkeblendGraphicsView::zoomOut() {m_zoomFactor /= 1.2;if (m_zoomFactor < 0.5) m_zoomFactor = 0.5;performZoom();
}void QSkeblendGraphicsView::performZoom() {QTransform transform;transform.scale(m_zoomFactor, m_zoomFactor);setTransform(transform);
}

功能流程图

效果展示

状态节点效果

  • 开始状态:绿色圆角矩形

  • 结束状态:红色圆角矩形

  • 普通状态:灰色圆角矩形

  • 空状态:深灰色圆角矩形

  • 选中状态:蓝色边框和发光效果

  • 进度显示:节点底部蓝色进度条

连线效果

  • 状态间连线为直线

  • 连线中点处有三角形箭头指示方向

  • 选中连线时变为蓝色

场景效果

  • 可切换网格背景/纯色背景

  • 支持Ctrl+滚轮缩放

  • 支持拖拽移动节点位置

技术亮点

  1. 灵活的状态管理

    • 通过枚举清晰区分不同类型的状态

    • 每个状态节点独立维护自己的属性和外观

  2. 高效的渲染机制

    • 使用QPainter进行高效的自定义绘制

    • 通过渐变和圆角效果提升视觉体验

    • 针对选中状态提供特殊视觉效果

  3. 交互体验优化

    • 支持Ctrl+滚轮平滑缩放

    • 节点拖拽时实时更新连线位置

    • 右键菜单提供上下文相关操作

  4. 可扩展的架构

    • 通过信号槽机制实现组件间通信

    • 状态数据与UI分离,便于扩展

总结

这个蓝图式技能编辑器状态机模块为游戏开发提供了一套直观、灵活的状态管理工具。通过精心设计的可视化界面和流畅的交互体验,开发者可以高效地构建复杂的技能状态转换逻辑。模块采用Qt强大的图形框架实现,具有良好的可扩展性和稳定性,能够满足游戏开发中各种复杂的状态管理需求。

当然最终实现效果 跟unity的状态机 差不多,要看你自己怎么自绘了,比如可以给状态块添加渐变模型。内部实现结果的方式,反正就像qwidget一样进去绘制,然后把结点间的连续,做成连续播放,就可以让美术清晰的知道状态间的过渡效果

unity的状态机如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87632.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87632.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87632.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity AR识别物体的内容语音读取+使用说明功能

因之前一直在开发项目&#xff0c;断断续续写了一点博客&#xff0c;最后统一写了一下博客记录学习内容。 可以看到我的工作一直在进行。 目录 一、识别内容语音读取 二、点击齿轮按钮弹出使用说明界面 开发步骤 1. 创建齿轮按钮 UI 2. 创建使用说明面板 UI 3. 编写控制…

Unable to start embedded Tomcat

通常是由于xml文件配置错误导致 1. mapper 指向错误 <resultMap id"Waybill" type"c.Waybill"> 2. 字段类型错误 <result column"wstatus" property"stus" javaType"TINYINT"/>TINYINT 是数据库类型<resu…

Mac电脑 充电限制保护工具 AlDente Pro

AlDente Pro一款充电限制保护工具&#xff0c;是可以限制最大充电百分比来保护电池的工具。 锂离子和聚合物电池&#xff08;如 MacBook 中的电池&#xff09;在40&#xff05; 至 80&#xff05; 之间运行时&#xff0c;使用寿命最长。 始终将电池电量保持在 100&#xff05…

KungfuBot——基于物理约束和自适应运动追踪的人形全身控制PBHC,用于学习打拳或跳舞(即RL下的动作模仿和运控)

前言 昨天618&#xff0c;我司「七月在线」同事朝阳为主力&#xff0c;我打杂&#xff0c;折腾了整整一天&#xff0c;终于可以通过VR摇操宇树G1了——当然&#xff0c;摇操是为了做训练数据的采集&#xff0c;从而方便 下一步的模型(策略)训练&#xff0c;最终实现机器人自主…

Kafka多副本机制

副本和副本因子 Kafka 会为每个 Partition 创建多个副本。这些副本分布在不同的 Broker 上。副本确保了数据的冗余存储&#xff0c;即使某个 Broker 宕机或失效&#xff0c;其他副本可以继续提供服务。 副本因子指的是每个 Partition 有多少个副本。副本因子的设置决定了一个…

Vue3类似百度风格搜索框组件

Vue3百度风格搜索框组件&#xff0c;使用vue3进行设计&#xff0c;亦有vue3TS的版本。 vue3组件如下&#xff1a; <template><!-- 搜索组件容器 --><div class"search-container"><!-- 百度Logo - 新样式 --><div class"logo-conta…

智净未来:华为智选IAM以科技巧思优化家庭健康饮水体验

在中国家庭中&#xff0c;净水器早已成为厨房标配&#xff0c;但传统净水设备的使用体验却远未达到理想状态。根据《2023年中国家庭净水器使用调研报告》显示&#xff0c;超过65%的用户对传统净水器存在不满&#xff0c;主要痛点集中在功能单一、操作复杂、维护麻烦、噪音大、废…

细说STM32单片机SPI-Flash芯片的FatFS移植

目录 一、SPI-Flash芯片硬件电路 二、CubeMX项目基础设置 1、RCC、SYS、Code Generator、USART6、NVIC 2、RTC 3、SPI2 4、GPIO 5、FatFS模式 6、FatFS参数设置概述 &#xff08;1&#xff09;Version组 &#xff08;2&#xff09;Function Parameters组 1&#x…

ubuntu 22.04 安装部署logstash 7.10.0详细教程

安装部署logstash 7.10.0详细教程 一、下载并安装二、新建配置文件三、赋权文件权限四、检测文件grok语法是否异常五、启动服务六、安装启动常见问题 【背景】 整个elk安装是基于ubuntu 22.04和jdk 11环境。logstash采用 *.deb方式安装&#xff0c;需要服务器能联网。ubuntu 22…

JVM对象创建与内存分配机制深度剖析

对象创建的主要流程 类加载检查 在创建对象之前&#xff0c;JVM 首先会检查该类是否已经加载、解析并初始化&#xff1a; 如果没有&#xff0c;则会通过类加载机制加载类元信息&#xff08;Class Metadata&#xff09;到方法区。 这个过程包括&#xff1a;加载&#xff08;load…

Navicat 技术指引 | TiDB 的 AI 查询交互功能

目前&#xff0c;Navicat 两款工具支持对 TiDB 数据库的管理开发功能&#xff1a;一款是旗舰款 Navicat Premium&#xff0c;另一款是其轻量化功能的 Navicat Premium Lite&#xff08;官方轻量级免费版&#xff09;。Navicat 自版本 17.1 开始支持 TiDB 7。它支持的系统有 Win…

以list为输入条件,查询数据库表,java中的mapper层和mybatis层应该怎么写?

根据一个 List 中的两个字段 rangeCode 和 unitcd&#xff0c;查询数据库表 model_engineering_spatial_unit。这个需求在 Java MyBatis 项目中非常常见&#xff0c;下面我将为你详细写出 Mapper 接口&#xff08;Java&#xff09; 和 MyBatis XML 映射文件 的写法。 ✅ 前提…

pyspark 创建DataFrame

from pyspark.sql import SparkSession from pyspark.sql import StructType, StructField, IntegerType,StringType spark SparkSession.builder.appName(test).getOrCreate() 1、 从列表中创建DataFrame data [(1,"alice"),(2,Blob),(3,Charlie)] columns [&qu…

Vim:从入门到进阶的高效文本编辑器之旅

目录 一、Vim简介 二、Vim的基础操作 2.1 进入和退出Vim 2.2 Vim的三种模式 2.3 基础移动 三、Vim的高效编辑技巧 3.1 文本编辑 3.2 文本删除与修改 3.3 复制与粘贴 四、Vim的进阶使用 4.1 搜索与替换 4.2 寄存器与宏 4.3 插件与配置 五、结语 在编程界&#xff0…

Docker基础理论与阿里云Linux服务器安装指南

文章目录 一、Docker核心概念二、阿里云环境准备三、Docker安装与配置四、核心容器部署示例五、开发环境容器化六、运维管理技巧七、安全加固措施 一、Docker核心概念 容器化本质&#xff1a; 轻量级虚拟化技术&#xff0c;共享主机内核进程级隔离&#xff08;cgroups/namespac…

c#使用笔记之try catch和throw

一、try catch 一种报错的捕捉机制&#xff0c;try块里运行的代码出现错误的时候就会去执行catch块所以一般catch块里都是把错误打印出来或者保存到log日志里&#xff1b; 1.1、具体使用 catch可以用&#xff08;&#xff09;来选择捕捉什么类型的错误&#xff0c;一般用Exc…

(新手友好)MySQL学习笔记(9):索引(常见索引类型,查找结构的发展(二分查找法,二叉搜索树,平衡二叉树,B树,B+树))

目录 索引 常见索引类型 B树 二分查找法 二叉搜索树和平衡二叉树 B树和B树 索引 index&#xff0c;是存储引擎用于快速找到数据的一种数据结构。 MySQL默认使用InnoDB存储引擎&#xff0c;该存储引擎是最重要&#xff0c;使用最广泛的&#xff0c;除非有非常特别的原因需要使用…

进程间通信1(匿名管道)Linux

1 进程间通信的必要性 首先要明确进程间是相互独立的&#xff08;独享一份虚拟地址空间&#xff0c;页表&#xff0c;资源&#xff09;&#xff0c;那怎么样才能使得两个进程间实现资源的发送&#xff1f;所以&#xff0c;两个进程一定需要看到同一份资源&#xff0c;并且⼀个…

CAN2.0、DoIP、CAN-FD汽车协议详解与应用

一、CAN2.0 协议详解与应用示例 1. 技术原理与特性 协议架构&#xff1a;基于 ISO 11898 标准&#xff0c;采用载波监听多路访问 / 冲突检测&#xff08;CSMA/CD&#xff09;机制&#xff0c;支持 11 位&#xff08;CAN2.0A&#xff09;或 29 位&#xff08;CAN2.0B&#xff…

使用nvm管理npm和pnpm

1.使用nvm管理npm // 查看nvm版本 nvm -v // 查看可安装的 node 版本 nvm ls-remote // 安装指定 node 版本 nvm install 24.0.0 // 查看当前已安装的 node 版本及当前使用的版本 nvm list // 使用某个版本 node nvm use 24.0.0 // 卸载指定 node 版本 nvm uninstall 16.20.1…