管理游戏规则
让我们创建 LevelManager 组件来管理游戏规则、关卡状态和用户界面。 管理器创建一个图形用户界面,并显示游戏结束前的剩余时间。 它还检查并显示离开游戏区域的剩余物体数量。
步骤1。设置定时器和游戏界面#
分配了 LevelManager 组件的节点应该存在于世界中,以使规则生效。 它将管理计时器并更新游戏的 widget 用户界面。
- 创建一个新的 C++ 组件 并将其命名为 LevelManager。
-
IDE中编写以下代码并保存解决方案。构建和运行的解决方案组件生成一个属性文件。
请注意,LevelManager 组件的 init() 方法设置为按 2nd 顺序调用,以确保它是 在 ObjectGenerator 组件之后初始化,该组件创建所有物理对象并将其作为父对象(ObjectGenerator 的初始化顺序设置为 1st)。#pragma once #include <UnigineComponentSystem.h> #include <UnigineWidgets.h> #include <UnigineGame.h> #include <UnigineString.h> class LevelManager : public Unigine::ComponentBase { public: // declare constructor and destructor for our class and define a property name. COMPONENT_DEFINE(LevelManager, ComponentBase) // declare methods to be called at the corresponding stages of the execution sequence COMPONENT_INIT(init, 2); // 2nd initialization order COMPONENT_UPDATE(update); COMPONENT_SHUTDOWN(shutdown); // level timer PROP_PARAM(Float, timer, 100.0f); void decPhysicalObjectsNum(); void setEndGameCallback(Unigine::CallbackBase *callback) { endGameEvent = callback; } protected: void init(); void update(); void shutdown(); void initGUI(); private: Unigine::CallbackBase *endGameEvent = nullptr; bool isCounting = true; int physicalObjectsNum; Unigine::WidgetLabelPtr widget_timer, widget_goal; Unigine::ObjectTextPtr endText; };
#include "LevelManager.h" using namespace Unigine; using namespace Math; REGISTER_COMPONENT(LevelManager); void LevelManager::init() { LevelManager::initGUI(); // find the object text node of the widget endText = checked_ptr_cast<ObjectText>(Game::getPlayer()->findNode("header_text", 1)); // count dynamic objects in the level physicalObjectsNum = node->getNumChildren(); } void LevelManager::initGUI() { // get a GUI pointer GuiPtr gui = Gui::getCurrent(); // create a label widget and set up its parameters widget_timer = WidgetLabel::create(gui, "Time Left:"); widget_timer->setPosition(10, 10); widget_timer->setFontColor(vec4_red); widget_goal = WidgetLabel::create(gui, "Objects Left: "); widget_goal->setPosition(10, 30); widget_goal->setFontColor(vec4_blue); // add widgets to the GUI gui->addChild(widget_timer, Gui::ALIGN_OVERLAP); gui->addChild(widget_goal, Gui::ALIGN_OVERLAP); } void LevelManager::update() { // decrease the timer if (isCounting) { timer = timer - Game::getIFps(); if (timer <= 0) { //set end game text if (endText) endText->setText("Game Over"); if (endGameEvent) endGameEvent->run(); isCounting = false; } } // show the current time and objects left to clear if (isCounting) { widget_timer->setText(String::format("Time Left: %.2f s", timer.get())); widget_goal->setText(String::format("Objects Left: %d", physicalObjectsNum)); } //hide the widgets on endgame else { widget_timer->setEnabled(false); widget_goal->setEnabled(false); } //win if (physicalObjectsNum <= 0) { if (endText) endText->setText("Success!"); if (endGameEvent) endGameEvent->run(); isCounting = false; } } void LevelManager::shutdown() { widget_timer.deleteLater(); widget_goal.deleteLater(); } void LevelManager::decPhysicalObjectsNum() { physicalObjectsNum--; }
- 切换回 UnigineEditor 并创建一个名为 level_manager 的新 Dummy Node 并将其放置在世界某处。
-
通过 UnigineEditor 中的 Parameters 窗口将 LevelManager 组件添加到 level_manager 节点。
步骤2。检测物理对象#
只有 level_manager 的子节点会被 Kill Zone 的触发器删除。 让我们将 之前创建的每个物理对象 作为子节点添加到 level_manager 节点。 为了使规则正常运行,您还需要向 KillZone 组件添加一个新条件和一个方法调用,以检查输入的节点是否具有附加了LevelManager 组件的父节点。
-
在你的 IDE 中打开 KillZone 组件,添加一个 levelManager 字段并替换 Enter callback 函数根据以下代码。
#pragma once #include <UnigineComponentSystem.h> #include <UnigineWorlds.h> //========================== NEW - BEGIN =============================== #include "LevelManager.h" //=========================== NEW - END ================================ class KillZone : public Unigine::ComponentBase { public: // declare constructor and destructor for our class and define a property name. COMPONENT_DEFINE(KillZone, ComponentBase) // declare methods to be called at the corresponding stages of the execution sequence COMPONENT_INIT(init); protected: void init(); void enterEventHandler(const Unigine::NodePtr &target); private: // the area into which an object should fall Unigine::WorldTriggerPtr trigger; //========================== NEW - BEGIN =============================== LevelManager *levelManager; //=========================== NEW - END ================================ };
#include "KillZone.h" using namespace Unigine; REGISTER_COMPONENT(KillZone); void KillZone::init() { trigger = checked_ptr_cast<WorldTrigger>(node); // subscribe for the Enter event (when an object enters the area) if (trigger) trigger->getEventEnter().connect(this, &KillZone::enterEventHandler); } void KillZone::enterEventHandler(const NodePtr &target) { //========================== NEW - BEGIN =============================== levelManager = getComponentInParent<LevelManager>(target); // check if the parent node has a LevelManager component attached if (levelManager) { // delete the entered node and decrease the amount of physical objects levelManager->decPhysicalObjectsNum(); target.deleteLater(); } //=========================== NEW - END ================================ }
-
让我们设置level_manager节点作为一个家长物理对象。在IDE中打开ObjectGenerator组件和替换的代码与下列相应的文件。保存您的IDE中的代码,构建和运行的解决方案组件和再生一个属性文件切换回UnigineEditor。
#include <UnigineComponentSystem.h> #include <UnigineGame.h> #pragma once class ObjectGenerator : public Unigine::ComponentBase { public: COMPONENT_DEFINE(ObjectGenerator, ComponentBase); COMPONENT_INIT(init, 1); // 1st initialization order //========================== NEW - BEGIN =============================== PROP_PARAM(Node, levelManager); //=========================== NEW - END ================================ protected: void init(); };
#include "ObjectGenerator.h" #include <UniginePrimitives.h> using namespace Unigine; REGISTER_COMPONENT(ObjectGenerator); void ObjectGenerator::init() { //========================== NEW - BEGIN =============================== if (levelManager) { //=========================== NEW - END ================================ // cube ObjectMeshDynamicPtr box = Primitives::createBox(Math::vec3(1.0f)); //========================== NEW - BEGIN =============================== box->setParent(levelManager); //========================== NEW - END =============================== box->setTriggerInteractionEnabled(1); box->setIntersection(1, 0); box->setIntersectionMask(0x00000080, 0); // check the BulletIntersection bit box->setWorldTransform(translate(Math::Vec3(0.5f, 7.5f, 1.0f))); box->setMaterialPath("materials/mesh_base_0.mat", "*"); box->setName("box"); Unigine::BodyRigidPtr bodyBox = BodyRigid::create(box); ShapeBoxPtr shapeBox = ShapeBox::create(bodyBox, Math::vec3(1.0f)); ShapeSphere::create(bodyBox, 0.5f); bodyBox->setShapeBased(0); bodyBox->setMass(2.0f); // sphere ObjectMeshDynamicPtr sphere = Primitives::createSphere(0.5f, 9, 32); //========================== NEW - BEGIN =============================== sphere->setParent(levelManager); //========================== NEW - END =============================== sphere->setTriggerInteractionEnabled(1); sphere->setIntersection(1, 0); sphere->setIntersectionMask(0x00000080, 0); // check the BulletIntersection bit sphere->setWorldTransform(translate(Math::Vec3(4.5f, 5.5f, 1.0f))); sphere->setMaterialPath("materials/mesh_base_1.mat", "*"); sphere->setName("sphere"); BodyRigidPtr bodySphere = BodyRigid::create(sphere); ShapeSphere::create(bodySphere, 0.5f); bodySphere->setShapeBased(0); bodySphere->setMass(2.0f); // capsule ObjectMeshDynamicPtr capsule = Primitives::createCapsule(0.5f, 1.0f, 9, 32); //========================== NEW - BEGIN =============================== capsule->setParent(levelManager); //========================== NEW - END =============================== capsule->setTriggerInteractionEnabled(1); capsule->setIntersection(1, 0); capsule->setIntersectionMask(0x00000080, 0); // check the BulletIntersection bit capsule->setWorldTransform(translate(Math::Vec3(4.5f, 0.5f, 3.0f))); capsule->setMaterialPath("materials/mesh_base_2.mat", "*"); capsule->setName("capsule"); BodyRigidPtr bodyCapsule = BodyRigid::create(capsule); ShapeCapsule::create(bodyCapsule, 0.5f, 1.0f); bodyCapsule->setShapeBased(0); bodyCapsule->setMass(2.0f); //========================== NEW - BEGIN =============================== } //=========================== NEW - END ================================ }
-
选择object_generator节点World Nodes窗口拖动level_manager节点的对应字段ObjectGenerator财产。
- 保存更改。去File->Save World或者按Ctrl+S热键。
- 切换到您的IDE。保存更改到解决方案,然后构建和运行游戏的游戏规则。
最新更新:
2023-11-29
Help improve this article
Was this article helpful?
(or select a word/phrase and press Ctrl+Enter)