Horse3D 游戏引擎研发笔记(六):IBalikun——组件编辑器接口与宿主关联
Horse3D 游æå¼æç åç¬è®°ï¼å ï¼ï¼IBalikunââç»ä»¶ç¼è¾å¨æ¥å£ä¸å®¿ä¸»å ³è
软件ç§å¦_éå¦è 2026-08-15 0 é 读13åéç®æ ï¼æè§£ Horse3D çç»ä»¶ç¼è¾å¨æ¥å£å± IBalikunãä» Balikun åºç±»çåºååéå æºå¶åºåï¼å° IBalikun çå¼ç±»åç³»ç»ä¸å±æ§å®ï¼åå°ç»ä»¶åå访é®å®¿ä¸» IObject ç设计ï¼å®æ´æ¢³çç»ä»¶ä»å£°æå°ç¼è¾ãåºååãè¿è¡æ¶äº¤äºçå ¨é¾è·¯ã
Bilibili 忥è§é¢
Horse3D 游æå¼æç åç¬è®°ï¼å ï¼ï¼IBalikunââç»ä»¶ç¼è¾å¨æ¥å£ä¸å®¿ä¸»å ³è
ä¸ã为ä»ä¹éè¦ IBalikun
åäºç¯ç¬è®°éæ¥å»ºç«äºæ¸²æçº¿ç¨ãæè´¨ç³»ç»ãå
ç
§åç¼è¾å¨æ¡æ¶ãFerghana ç¼è¾å¨å·²ç»è½éè¿ Inspector å±ç¤ºç»ä»¶ç屿§é¢æ¿ââä½é£ä¸ªæ¹æ¡æä¸ä¸ªææ¾çè¾¹çï¼ç»ä»¶å±ç´æ¥ä¾èµ QWidgetï¼Inspector éå object->components() è°ç¨æ¯ä¸ªç»ä»¶ç editor() æ¥è·åçé¢ã
è¿è½è·ï¼ä½ä¸å¤å¥½ãé®é¢æ¯ï¼
- æ¯ä¸ªç»ä»¶åç±»é½è¦æå UI å¸å±ä»£ç ââå建æ ç¾ãå建æ§ä»¶ã设置å¸å±ã注ååè°ï¼éå¤ä¸å®¹æåºéã
- åºååæ²¡æç»ä¸æºå¶ââç»ä»¶çåªäºå段éè¦åå° JSONãåæ®µåå«ä»ä¹ãæä¹è¯»åæ¥ï¼å ¨é æ¯ä¸ªåç±»èªå·±å®ç°ã
- ç»ä»¶æ æ³è®¿é®å®¿ä¸»å¯¹è±¡ââä¸ä¸ªèªå®ä¹èæ¬ç»ä»¶æ³è¯»åå级 Transform çä½ç½®ï¼æ²¡æä»»ä½é徿¿å° IObject æéã
IBalikun å°±æ¯ä¸ºè§£å³è¿ä¸ä¸ªé®é¢è设计çä¸é´å±ãå®ç»§æ¿ Balikun è·å¾åºååè½åï¼åæ¶å¼å ¥å¼ç±»åç³»ç»å屿§å®ï¼è®©åç±»åªé声ææååéåä¸è¡å®è°ç¨å°±è½èªå¨è·å¾ç¼è¾å¨ UI ä¸ JSON åºååãæ¤å¤ï¼å®åå¨å®¿ä¸» IObject æéï¼è®©ç»ä»¶å¯ä»¥åå访é®å级ç»ä»¶åå®¿ä¸»å±æ§ã
äºãç±»å±æ¬¡å ¨æ¯
classDiagram
class IObject {
+addComponent~T~() T&
+component~T~() T*
+hasComponent~T~() bool
+removeComponent~T~() bool
+components() vector~Balikun*~
+transform() Transform&
+parent() IObject*
+children() vector~IObject*~
-m_components
}
class Balikun {
+editor() QWidget*
+update(elapsedMs) void
+toJson() QJsonObject
+fromJson(json) void
+className() QString
#m_setters
#m_getters
#m_onEdited
}
class IBalikun {
+object() IObject*
+setObject(obj) void
+component~T~() T*
+hasComponent~T~() bool
+transform() Transform*
+objectName() QString
#m_object : IObject*
#m_name : QString
}
class Transform {
+translation : Vector3Proxy
+rotation : QuaternionProxy
+scale : Vector3Proxy
+matrix() QMatrix4x4
}
class TestBalikun {
+cnt : intValue
+speed : floatValue
+alias : StringValue
+position : Vector2Value
+color : Vector3Value
}
IObject *-- Balikun
Balikun <|-- IBalikun
Balikun <|-- Transform
IBalikun <|-- TestBalikun
IBalikun ..> IObject
å¾ 1ï¼IBalikun ç±»å±æ¬¡ã Balikun æ¯ææç»ä»¶çåºç±»ï¼IBalikun å Transform æ¯ä¸¤æ¡ä¸åç忝ââåè é¢åç¼è¾å¨ï¼åè æ¯ IObject çåºæåæ¢ç»ä»¶ã
å
³é®è®¾è®¡å³çï¼Transform ç»§æ¿ Balikun ä½ä¸ç»§æ¿ IBalikunãTransform æ¯ IObject æé æ¶èªå¨å建çåºæç»ä»¶ï¼ä¸éè¦ç¼è¾å¨çé¢çæè½åï¼å®çç¼è¾å¨æ¯æåçï¼ç¨ Vector3Proxy å®ç°å¯è§å¯ä»£çï¼ãIBalikun åä¸é¨é¢åéè¦å£°æå¼å±æ§é¢æ¿çç»ä»¶ã
ä¸ãBalikun åºç±»ï¼åºååéå ä¸å»¶è¿å è½½
3.1 éå æ³¨å模å¼
Balikun ä¸ä½¿ç¨è彿°ååºååï¼èæ¯è®©åç±»å¨æé 彿°ä¸éè¿ addSetter / addGetter 注å lambda éå
ãæ¯ä¸ªéå
æè· this 并读åä¸ä¸ªå
·ä½å段ï¼
class Balikun
{
protected:
std::vector<std::function<void(QJsonObject&)>> m_setters;
std::vector<std::function<void(const QJsonObject&)>> m_getters;
std::function<void()> m_onEdited;
public:
void addSetter(std::function<void(QJsonObject &)> setter)
{ m_setters.push_back(std::move(setter)); }
void addGetter(std::function<void(const QJsonObject &)> getter);
QJsonObject toJson() const;
void fromJson(const QJsonObject &json);
};
toJson() éåææ setter éå
ï¼æ¯ä¸ªå JSON åå
¥ä¸ä¸ªå段ï¼fromJson() ååè°ç¨ getter éå
ãè¿ç§è®¾è®¡çä¼å¿æ¯é¶åå°å¼éââç¼è¯æç¡®å®ç±»åï¼è¿è¡ææ éå符串å¹é
ãä»£ä»·æ¯æ æ³è·¨ç±»åæ¹é管çåæ®µï¼ä½é
ååæç屿§å®ï¼è¿ä¸ªä»£ä»·è¢«å®å
¨æ¶é¤ã
3.2 å»¶è¿å è½½ï¼æé åå°±æ¿å° JSON æä¹å
Balikun ç addGetter å®ç°äºä¸ä¸ªç²¾å·§çå»¶è¿å è½½æºå¶ãèè工忍¡å¼ï¼BalikunRegistry ä» JSON å建ç»ä»¶æ¶ï¼æµç¨æ¯ fromJson â æé 彿° â addGetterãæ¤æ¶æé 彿°è¿æ²¡è·å®ï¼getter è¿æ²¡æ³¨åï¼ä½ JSON æ°æ®å·²ç»ä¼ è¿æ¥äºã
è§£å³æ¹æ¡æ¯ä¸ä¸ªå ¨å±ç¼åæ å°è¡¨ï¼
static std::unordered_map<const Balikun *, QJsonObject> s_loadedJson;
void Balikun::addGetter(std::function<void(const QJsonObject &)> getter)
{
QJsonObject loadedJson;
bool hasLoadedJson = false;
{
const std::lock_guard<std::mutex> lock(s_loadedJsonMutex);
const auto found = s_loadedJson.find(this);
if (found != s_loadedJson.end()) {
loadedJson = found->second;
hasLoadedJson = true;
}
}
if (hasLoadedJson)
getter(loadedJson); // ç«å³åºç¨ç¼åç JSON
m_getters.push_back(std::move(getter));
}
å½ getter è¢«æ³¨åæ¶ï¼å¦æå
¨å±è¡¨éå·²æç¼åæ°æ®ï¼å°±ç«å³æ§è¡ä¸æ¬¡ãè¿æå³çåç±»æé 彿°ä¸ç addGetter è°ç¨é¡ºåºå³å®äºå段å 载顺åºââå³ä½¿ fromJson 卿é åè°ç¨ï¼æ°æ®ä¹ä¸ä¼ä¸¢å¤±ãæææ¶èªå¨æ¸
é¤ç¼åæ¡ç®ã
3.3 className ä¸å·¥åå¹é
className() é»è®¤å®ç°éè¿ typeid æ¨å¯¼ç±»ååï¼ä¸ BalikunRegistry çå½åè§åä¸è´ãå·¥åå建ç»ä»¶æ¶ï¼ç¨ç±»åå¹é
JSON ä¸çç»ä»¶ç±»ååæ®µï¼å®ç°ååºååæ¶çç±»åè·¯ç±ã
åãIBalikunï¼ç¼è¾å¨æ¥å£ä¸å¼ç±»åç³»ç»
4.1 æ¥å£å®ä¹
IBalikun å¨ Balikun åºç¡ä¸å¼å ¥ä¸å±è½åï¼ç¼è¾å¨çé¢çæãå¼ç±»åç³»ç»ãå®¿ä¸»å¯¹è±¡å ³èã
class DRAGON_EXPORT IBalikun : public Balikun
{
public:
explicit IBalikun(const QString &name);
QWidget *editor() override;
virtual void onEditor(QWidget *editor, QVBoxLayout *layout) = 0;
~IBalikun() override;
IObject *object() const;
void setObject(IObject *object);
template<typename T> T *component();
template<typename T> bool hasComponent() const;
std::vector<Balikun *> components() const;
Transform *transform() const;
protected:
QString m_name;
IObject *m_object = nullptr;
};
editor() æ¯å·¥åæ¹æ³ââå建ä¸ä¸ª QGroupBoxï¼å
å« QVBoxLayoutï¼ç¶åè°ç¨åç±»å®ç°ç onEditor() å¾å¸å±éå¡«å
æ§ä»¶ï¼
QWidget *IBalikun::editor()
{
auto *widget = new QGroupBox(m_name);
auto *layout = new QVBoxLayout(widget);
layout->setContentsMargins(8, 8, 8, 8);
onEditor(widget, layout);
return widget;
}
åç±»åªéè¦å®ç° onEditor()ï¼å¨æ¹æ³ä½éè°ç¨å±æ§å®å³å¯ãä¸éè¦æå¨å建 QGroupBoxãä¸éè¦ç®¡ç layout çå½å¨æã
4.2 å¼ç±»åç³»ç»
IBalikun çç¼è¾å¨çé¢ä¸æ¯æå QWidgetï¼èæ¯éè¿ä¸å¥å¼ç±»åä»£çæ¥å£°æå¼æå»ºã弿æä¾äºç§å¼ç±»åï¼æ¯ç§å°è£ äºå¯¹åºç Qt æ§ä»¶ååè°æºå¶ï¼
| å¼ç±»å | C++ åçç±»å | Qt æ§ä»¶ | 屿§å® |
|---|---|---|---|
intValue | int | QSpinBox | BALIKUN_INT_PROPERTY |
floatValue | float | QDoubleSpinBox | BALIKUN_FLOAT_PROPERTY |
StringValue | QString | QLineEdit | BALIKUN_STRING_PROPERTY |
Vector2Value | QVector2D | 2Ã QDoubleSpinBox | BALIKUN_VECTOR2_PROPERTY |
Vector3Value | QVector3D | 3Ã QDoubleSpinBox | BALIKUN_VECTOR3_PROPERTY |
æ¯ä¸ªå¼ç±»åé½ç»§æ¿ QObjectï¼å
·å¤å¤è§å¾åæ¥è½åââåä¸ä¸ªå¼å¯ä»¥å
³èå¤ä¸ªæ§ä»¶å®ä¾ï¼éè¿ QVector<QPointer<...>> 管çï¼ï¼ä¿®æ¹ä»»æä¸ä¸ªæ§ä»¶ä¼åæ¥ææå
¶ä»æ§ä»¶ãåæ¶æ¯æ addCallback 注åå¼åæ´åè°ã
以 intValue 为ä¾ï¼
class BALIKUN_EXPORT intValue : public QObject
{
public:
explicit intValue(int value = 0) noexcept;
int value() const noexcept;
void setValue(int value) noexcept;
QSpinBox *create(QWidget *parent = nullptr);
intValue &operator=(int value) noexcept;
operator int() const noexcept;
void addCallback(std::function<void(int)> callback);
private:
int m_value = 0;
QVector<QPointer<QSpinBox>> m_spinBoxes;
std::vector<std::function<void(int)>> m_callbacks;
};
éå¼è½¬æ¢è¿ç®ç¬¦ operator int() 让å¼ç±»åå¨è¡¨è¾¾å¼ä¸ååçç±»å䏿 ·ä½¿ç¨ââinfo() << "cnt" << cnt éç cnt æ¯ intValueï¼ä½è¾åºæ¶èªå¨è½¬ä¸º intãcreate() æ¹æ³æ¯æ¬¡å建ä¸ä¸ªæ°çå
³èæ§ä»¶ï¼èªå¨åæ¥å½åå¼å¹¶æ³¨ååè°ã
äºã屿§å®ï¼ä¸è¡ä»£ç 宿ä¸ä»¶äº
å¼ç±»åæ¬èº«åªç®¡çæ§ä»¶ååè°ï¼ä½è¦å®æ´æ¥å
¥ç¼è¾å¨è¿éè¦ï¼å建 UI è¡ã注ååºåå setter/getterãæ³¨ååæ´åè°è§¦å m_onEditedãè¿ä¸æ¥å¨æ¯ä¸ªå±æ§ä¸é½éå¤ï¼å æ¤è¢«å°è£
为å®ã
以 BALIKUN_INT_PROPERTY 为ä¾ï¼
#define BALIKUN_INT_PROPERTY(displayName, member) \
do { \
layout->addLayout(create(QStringLiteral(displayName), member, editor)); \
addSetter([this](QJsonObject &json) { \
json.insert(QStringLiteral(#member), int(member)); \
}); \
addGetter([this](const QJsonObject &json) { \
if (json.contains(QStringLiteral(#member))) \
member = json.value(QStringLiteral(#member)).toInt(); \
}); \
member.addCallback([this](int) { \
if (m_onEdited) m_onEdited(); \
}); \
} while (0)
ä¸è¡å®å®æä¸ä»¶äºï¼
- UI å建 â
create()çææ ç¾ + æ§ä»¶çæ°´å¹³å¸å±ï¼å å ¥ç¼è¾å¨ layoutã - åºååæ³¨å â å Balikun åºç±»æ³¨å setterï¼å JSONï¼å getterï¼è¯» JSONï¼ï¼å段ååèª
#memberå符åã - ç¼è¾åè° â å¼åæ´æ¶è§¦å
m_onEditedï¼éç¥ç¼è¾å¨å·æ°ã
Vector ç±»åç¨æä¸åââJSON ä¸ä»¥åµå¥å¯¹è±¡åå¨ {x, y, z} åæ®µï¼ä½å®ç模å¼å®å
¨ä¸è´ãè¿ç§å£°æå¼ç¼ç¨è®©ç»ä»¶å¼åè
åªéåæå声æåä¸è¡å®è°ç¨ï¼ä¸å¿
å
³å¿ UI æå»ºãåºååæ³¨åãåè°è¿æ¥çä»»ä½ç»èã
å ãå®¿ä¸»å ³èï¼ä»ç»ä»¶ååè®¿é® IObject
6.1 é®é¢ä¸æ¹æ¡
å¨ ECS æ¶æä¸ï¼ç»ä»¶é常åªç¥éèªå·±çæ°æ®ï¼æ æ³è®¿é®å级ç»ä»¶æå®¿ä¸»å¯¹è±¡ãä½å¨å®é å¼åä¸ï¼ç»ä»¶ç»å¸¸éè¦è¯»åå级ç»ä»¶çç¶æââæ¯å¦èªå®ä¹èæ¬ç»ä»¶éè¦è¯»å Transform ä½ç½®æ¥åé»è¾å¤æã
IBalikun éè¿åå¨ IObject* æéè§£å³äºè¿ä¸ªé®é¢ã使ä¹è®¾ç½®è¿ä¸ªæéï¼ç»ä»¶æ¯è¢« IObject::addComponent å建çï¼ç»ä»¶ä¸ç¥éèªå·±ç宿主æ¯è°ã
æ¹æ¡æ¯ï¼å¨ addComponent ä¸ï¼ç»ä»¶åå»ºå®æ¯åèªå¨æ³¨å
¥å®¿ä¸»æéãIBalikun æä¾ä¸ä¸ª protected ç setObject æ¹æ³ï¼IObject éè¿è¾
婿¹æ³ setComponentHost è°ç¨å®ï¼
void IObject::setComponentHost(Balikun *component, IObject *host)
{
if (auto *ibalikun = dynamic_cast<IBalikun *>(component))
ibalikun->setObject(host);
}
dynamic_cast ç¡®ä¿åªæ IBalikun åç±»æè¢«è®¾ç½®æéââTransform çé IBalikun ç»ä»¶ä¸åå½±åï¼dynamic_cast è¿å nullptr ç´æ¥è·³è¿ã
6.2 èªå¨æ³¨å ¥æµç¨
flowchart LR
A["IObject::addComponent()"] --> B["å建 T ç»ä»¶"]
B --> C["emplace å° m_components"]
C --> D["setComponentHost(result, this)"]
D --> E{"dynamic_cast"}
E -- æå --> F["ibalikun->setObject(this)"]
E -- 失败 --> G["Transform çé IBalikun<br/>ç»ä»¶ï¼è·³è¿"]
F --> H["ç»ä»¶å¯éè¿ component()<br/>访é®å级ç»ä»¶"]
F --> I["ç»ä»¶å¯éè¿ transform()<br/>访é®å®¿ä¸»åæ¢"]
F --> J["ç»ä»¶å¯éè¿ objectName()<br/>è·å宿主åç§°"]
å¾ 2ï¼ç»ä»¶æè½½ä¸å®¿ä¸»æéæ³¨å ¥æµç¨ã addComponent å建ç»ä»¶åï¼setComponentHost éè¿ dynamic_cast 夿æ¯å¦ä¸º IBalikun åç±»ï¼æ¯åæ³¨å ¥å®¿ä¸»æéã
ç§»é¤ç»ä»¶æ¶ä¹ä¼æ¸ 空æéï¼é¿å æ¬åå¼ç¨ï¼
template<typename T>
bool removeComponent()
{
const auto it = m_components.find(std::type_index(typeid(T)));
if (it == m_components.end())
return false;
setComponentHost(it->second.get(), nullptr); // æ¸
空宿主æé
m_components.erase(it);
return true;
}
6.3 ç»ä»¶è®¿é®ä»£çæ¹æ³
æäºå®¿ä¸»æéåï¼IBalikun æä¾äºä¸å¥ä»£çæ¹æ³ï¼è®©ç»ä»¶åå¨èªå·±èº«ä¸è°ç¨ä¸æ ·è®¿é®å®¿ä¸»çç»ä»¶å屿§ï¼
template<typename T>
T *component()
{
return m_object ? m_object->component<T>() : nullptr;
}
Transform *transform() const
{
return m_object ? &m_object->transform() : nullptr;
}
QString objectName() const
{
return m_object ? m_object->name() : QString{};
}
IObject *parentObject() const
{
return m_object ? m_object->parent() : nullptr;
}
std::vector<IObject *> childObjects() const
{
return m_object ? m_object->children() : std::vector<IObject *>{};
}
æææ¹æ³é½å¤çäº m_object == nullptr çæ
åµï¼ç»ä»¶æªæè½½å°å¯¹è±¡æ¶ï¼ï¼è¿åå®å
¨ç空å¼ãè¿å¨ç»ä»¶åå
æµè¯æç¬ç«åå»ºåºæ¯ä¸å¾éè¦ââç»ä»¶å¯ä»¥å
æé åæè½½ã
ä¸ã宿ï¼TestBalikun 宿´å®ç°
ç¨ä¸ä¸ªç¤ºä¾ç»ä»¶ä¸²èæææ¦å¿µãTestBalikun å±ç¤ºäºä¸ä¸ªå
¸å IBalikun åç±»ç宿´åæ³ï¼
// TestBalikun.h
#pragma once
#include "IBalikun.h"
using namespace Horse;
class TestBalikun : public IBalikun
{
public:
TestBalikun();
intValue cnt;
floatValue speed;
StringValue alias;
Vector2Value position;
Vector3Value color;
public:
void onEditor(QWidget *editor, QVBoxLayout *layout) override;
void update(qint64 elapsedMilliseconds) override;
};
// TestBalikun.cpp
#include "TestBalikun.h"
#include "Clydesdale.h"
TestBalikun::TestBalikun()
: IBalikun(QStringLiteral("æµè¯ç»ä»¶"))
{
}
void TestBalikun::onEditor(QWidget *editor, QVBoxLayout *layout)
{
BALIKUN_INT_PROPERTY("个æ°", cnt);
BALIKUN_FLOAT_PROPERTY("é度", speed);
BALIKUN_STRING_PROPERTY("åç§°", alias);
BALIKUN_VECTOR2_PROPERTY("ä½ç½®", position);
BALIKUN_VECTOR3_PROPERTY("é¢è²", color);
}
void TestBalikun::update(qint64 elapsedMilliseconds)
{
info() << "cnt" << cnt << "TestBalikun::update" << elapsedMilliseconds << "ms";
}
å¦ææ²¡æ IBalikun å屿§å®ï¼å®ç°åæ ·çåè½éè¦ï¼æå¨å建 5 ç»æ ç¾ + æ§ä»¶ãæå¨æ³¨å 5 å¥ JSON åºååãæå¨è¿æ¥ 5 个å¼åæ´ä¿¡å·ââè³å° 80+ è¡éå¤ä»£ç ãèç°å¨ onEditor åªé 5 è¡å®è°ç¨ã
update() æ¹æ³å±ç¤ºäºå¼ç±»åçéå¼è½¬æ¢ââcntï¼intValueï¼å¯ä»¥ç´æ¥ç¨ << è¾åºå°æ¥å¿æµï¼å 为 operator int() ä¼èªå¨è§¦åãæ¥å¿ä½¿ç¨äºé¡¹ç®çº¦å®ç info() å®ï¼å½å空é´ä¸º Horseï¼å®ä¹å¨ Clydesdale.h ä¸ã
å «ãåºååå ¨æµç¨
æåºååæºå¶ä¸²èµ·æ¥çä¸ä¸ªå®æ´çæ°æ®æµã以 TestBalikun 为ä¾ï¼toJson() çè¾åºï¼
{
"name": "æµè¯ç»ä»¶",
"cnt": 42,
"speed": 1.5,
"alias": "Hero",
"position": { "x": 0.0, "y": 0.0 },
"color": { "x": 1.0, "y": 0.0, "z": 0.0 }
}
æ´ä¸ªæµç¨ï¼
- IBalikun æé 彿°æ³¨å
nameåæ®µç setter/getterã - TestBalikun æé 宿ï¼5 个å¼ç±»åæåå·²é»è®¤æé ï¼ã
onEditor()被è°ç¨æ¶ï¼5 ä¸ªå±æ§å®å注åä¸å¯¹ setter/getterã- æ¤æ¶ Balikun å ±ææ 6 ç» setter + 6 ç» getterï¼name + 5 ä¸ªå±æ§ï¼ã
toJson()éå 6 个 setterï¼çæä¸è¿° JSONãfromJson()éå 6 个 getterï¼ä» JSON æ¢å¤ææå段ã
å»¶è¿å è½½çå®æåºæ¯ï¼å½ BalikunRegistry å·¥åå建ç»ä»¶æ¶ï¼æµç¨æ¯ fromJson â æé 彿° â addGetterãæ¤æ¶ JSON 已被ç¼åå°å
¨å±æ å°è¡¨ï¼addGetter æ³¨åæ¶ç«å³æ§è¡ä¸æ¬¡ getter åºç¨æ°æ®ï¼ç¡®ä¿ä¸ä¸¢å¤±ãæé 彿°å®æåï¼å
¨å±æ å°è¡¨ä¸çæ¡ç®å¨æææ¶èªå¨æ¸
é¤ã
ä¹ã模åä¾èµï¼ä¸ºä»ä¹ IBalikun ä» Balikun ç§»å°äº Dragon
9.1 é®é¢èµ·æº
æå IBalikun ä½äº Balikun 模åï¼ä»
ç¨åå声æå¼ç¨ IObjectï¼
// å¨ Balikun 模åä¸
class IObject; // åå声æ
class BALIKUN_EXPORT IBalikun : public Balikun
{
IObject *m_object = nullptr; // æéï¼åå声æè¶³å¤
};
è¿å¨åå声æé¶æ®µæ²¡é®é¢ââåä¸ä¸ªæéç¡®å®ä¸éè¦å®æ´å®ä¹ãä½å½ IBalikun éè¦æ·»å æä½ IObject ç»ä»¶çæ¹æ³ï¼component<T>()ãtransform() çï¼æ¶ï¼æ¨¡æ¿æ¹æ³å¿
é¡»å¨å¤´æä»¶å
èå±å¼ï¼ç¼è¯å¨éè¦çå° IObject::component<T>() ç宿´å®ä¹ãåå声æä¸å¤ç¨äºã
9.2 ç§»å¨å³ç
å° IBalikun ä» Balikun 模åç§»å
¥ Dragon 模åï¼IObject æå¨ç模åï¼ï¼å¯ä»¥ç´æ¥ #include "Object3D.h" è·å宿´å®ä¹ãç§»å¨åä¾èµå
³ç³»ä¿æååï¼
flowchart TD
subgraph Balikun["Balikun 模åï¼åºç¡å±ï¼"]
B1["Balikun åºç±»"]
B2["intValue / floatValue / StringValue"]
B3["Vector2Value / Vector3Value"]
B4["Transform"]
B5["BalikunRegistry"]
end
subgraph Dragon["Dragon 模åï¼å¼æå±ï¼"]
D1["IObject / Object3D"]
D2["IBalikun"]
D3["Light / Camera / Material"]
D4["RenderThread / Scenario"]
end
subgraph Samples["EditorSample"]
S1["TestBalikun"]
end
Dragon -- "target_link_libraries(PUBLIC Balikun)" --> Balikun
Samples -- "龿¥ Dragon + Balikun" --> Dragon
Samples -- "龿¥ Balikun::Core" --> Balikun
å¾ 3ï¼æ¨¡åä¾èµæ¹åã Dragon â Balikun å§ç»ååï¼IBalikun ç§»å ¥ Dragon åç´æ¥ include Object3D.hï¼æ¶é¤è·¨æ¨¡ååå声æçé®é¢ã
9.3 è¿ç§»ç»è
ç§»å¨æ¶åçå ·ä½åæ´ï¼
| 忴项 | æ§å¼ï¼Balikun 模åï¼ | æ°å¼ï¼Dragon 模åï¼ |
|---|---|---|
| æä»¶ä½ç½® | Sinohorse/Balikun/IBalikun.h/.cpp | Sinohorse/Dragon/IBalikun.h/.cpp |
| 导åºå® | BALIKUN_EXPORT | DRAGON_EXPORT |
| å ¨å±å¤´ | balikun_global.h | dragon_global.h |
| IObject å¼ç¨ | class IObject; åå声æ | #include "Object3D.h" |
| CMake 注å | Balikun/CMakeLists.txt | Dragon/CMakeLists.txt |
Balikun 模åä»ä¿çå¼ç±»åå TransformãIBalikun å¨ Dragon ä¸éè¿ #include "Balikun.h" çå¼å
¥è¿äºç±»åââDragon ç CMake å·²ç» target_link_libraries(PUBLIC Balikun)ï¼include è·¯å¾é PUBLIC ä¼ æï¼æ éé¢å¤é
ç½®ã
EditorSample å 为 TestBalikun ç»§æ¿ IBalikunï¼éè¦å¨ CMakeLists 䏿¾å¼é¾æ¥ Dragonï¼ä¹ååªé¾æ¥ Balikun::Coreï¼ã
åã设计åè
| è®¾è®¡ç¹ | å½åæ¹æ¡ | ä¼ç¹ | åç»æ¼è¿ |
|---|---|---|---|
| åºååæºå¶ | éå æ³¨åï¼addSetter/addGetterï¼ | é¶åå°å¼éãæ¯æè¿è¡æ¶å¨æå段 | å¯èèèªå¨æ³¨åå æ°æ® |
| 屿§ UI | å¼ç±»å + 屿§å® | ä¸è¡å®å®æ UI + åºåå + åè° | 坿©å±æ´å¤ç±»åï¼boolãenumãcolorï¼ |
| 宿主æé | dynamic_cast + setComponentHost | 对é IBalikun ç»ä»¶éæ | Transform çä¹å¯èèææå®¿ä¸»æé |
| å¼ç±»åå¤è§å¾ | QPointer 管çå¤ä¸ªæ§ä»¶å®ä¾ | åä¸å¼å¤å¤ç¼è¾èªå¨åæ¥ | å¯èèæ°æ®ç»å®æ¡æ¶ |
| å»¶è¿å è½½ | å ¨å±æ å°è¡¨ç¼å JSON | è§£å³å·¥åæ¨¡å¼æé åååºååé®é¢ | å¯èèä¼ å ¥æé åæ° |
| 模åå½å± | IBalikun å¨ Dragon | æ¨¡æ¿æ¹æ³å¯ç´æ¥è®¿é® IObject 宿´å®ä¹ | å¯èèæåæ¥å£ä¸å®ç° |
åä¸ãå½åææ
- Balikun åºç±»æä¾åºååéå æºå¶åå»¶è¿å è½½ï¼æ¯æå·¥å模å¼ä¸çæé åååºååã
- IBalikun å¨ Balikun åºç¡ä¸å¼å ¥ç¼è¾å¨æ¥å£ãå¼ç±»åç³»ç»å屿§å®ï¼è®©ç»ä»¶å¼åè ä¸è¡å®å³å¯å®æ UI å建 + åºååæ³¨å + åè°è¿æ¥ã
- äºç§å¼ç±»åï¼intãfloatãstringãVector2ãVector3ï¼è¦ç常è§å±æ§ç±»åï¼åæ¯æå¤è§å¾åæ¥åéå¼è½¬æ¢ã
- IObject::addComponent èªå¨æ³¨å
¥å®¿ä¸»æéï¼IBalikun æä¾
component<T>()ãtransform()çä»£çæ¹æ³è®©ç»ä»¶åå访é®å®¿ä¸»ã - IBalikun ä» Balikun 模åç§»å ¥ Dragon 模åï¼æ¶é¤è·¨æ¨¡ååå声æé®é¢ï¼ä¾èµå ³ç³»ä¿æååã
- TestBalikun 示ä¾å±ç¤ºäºå®æ´å¼åæµç¨ï¼å£°æå¼ç±»åæåãè°ç¨å±æ§å®ãå®ç° onEditor å updateã
åäºãä¸ä¸æ¥
| ä¼å 级 | æ¹å | ç®æ |
|---|---|---|
| P0 | æ´å¤å¼ç±»å | æ¯æ boolãenumãcolor ç常ç¨å±æ§ç±»å |
| P1 | 屿§å æ°æ® | ç¨å æ°æ®ç»ä¸é©±å¨ Inspectorï¼åå°ç»ä»¶å¯¹ QWidget çç´æ¥ä¾èµ |
| P1 | Transform 宿主æé | 让 Transform 乿æ IObject æéï¼æ¶é¤ friend class çéè¦ |
| P2 | ç»ä»¶é´éä¿¡ | åºäº Mustang æ¶æ¯æ»çº¿å®ç°ç»ä»¶é´äºä»¶è®¢é |
| P2 | çéè½½ | çå¬åºæ¯ JSON ååï¼è¿è¡æ¶é建ç»ä»¶ |
| P2 | æ¤ééå | é å屿§å®çéå æºå¶å®ç°å±æ§åæ´ç Undo/Redo |
项ç®ä»åº
- Giteeï¼gitee.com/shendeyidi/â¦
æ¬ç³»åè®°å½ Horse3D 游æå¼æä»é¶å¼å§çç åè¿ç¨ï¼æ¬¢è¿äº¤æµã
Aitishiku.com