当前位置: 首页 > news >正文

Qt蓝图式技能编辑器状态机模块设计与实现

设计概述

这个模块是一个基于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.lryc.cn/news/572487.html

相关文章:

  • html实现登录与注册功能案例(不写死且只使用js)
  • 深入解析select模型:FD_SET机制与1024限制的终极指南
  • Linux系统远程操作和程序编译
  • 23.ssr和csr的对比?如何依赖node.js实现
  • [11-5]硬件SPI读写W25Q64 江协科技学习笔记(20个知识点)
  • 嵌入式编译工具链熟悉与游戏移植
  • 基于C#的Baumer相机二次开发教程
  • OpenSSL引擎 + PKCS11 + SoftHSM2认证
  • WHAT - React Native 开发 App 从 0 到上线全流程周期
  • 【嵌入式】鲁班猫玩法大全
  • 第1章: 伯努利模型的极大似然估计与贝叶斯估计
  • 软件工程(期末复习班)
  • 23种设计模式--简单工厂模式理解版
  • Arduino Nano 33 BLE Sense Rev 2开发板使用指南之【外设开发】
  • 零基础指南:利用Cpolar内网穿透实现Synology Drive多端笔记同步
  • Linux基本指令篇 —— mkdir指令
  • MFC中使用CRichEditCtrl控件让文本框中的内容部分加粗
  • 分布变化的模仿学习算法
  • 257. 二叉树的所有路径(js)
  • 【数据治理】要点整理-信息技术服务治理第5部分-数据治理规范-GBT+34960.5-2018
  • C#设计模式之AbstractFactory_抽象工厂_对象创建新模式-练习制作PANL(一)
  • C# winform教程(二)----GroupBox
  • vscode设置代码字体
  • Web 应用防火墙(WAF)工作原理、防护策略与部署模式深度剖析
  • css语法中的选择器与属性详解:嵌套声明、集体声明、全局声明、混合选择器
  • 什么是池化
  • 啊啊啊啊啊啊啊啊code
  • 打卡Day55
  • C++实现手写strlen函数
  • LeeCode2294划分数组使最大值为K