如何在2D世界中检测碰撞事件并在Urho3D中运行回调?

时间:2017-11-27 06:34:08

标签: urho3d

我设法检测到3D中的碰撞,但是"类似的" 2D不起作用。

对于3D,我这样做:

SubscribeToEvent(E_NODECOLLISION, URHO3D_HANDLER(Main, HandleNodeCollision));

并在发生冲突时调用回调:

void HandleNodeCollision(StringHash eventType, VariantMap& eventData) {
    std::cout << "asdf" << std::endl;
}

但是当我为2D尝试相同时,它永远不会被调用。

下面的完整可运行代码,使用以下样板测试:https://github.com/cirosantilli/Urho3D-cheat/blob/e2c955a45d8328fd5f8bf4df5685653452cb28a7/collision.cpp和Urho3D @ 5e8a275:

#include <iostream>

#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Core/Object.h>
#include <Urho3D/Engine/Application.h>
#include <Urho3D/Engine/Engine.h>
#include <Urho3D/Engine/EngineDefs.h>
#include <Urho3D/Graphics/Camera.h>
#include <Urho3D/Graphics/DebugRenderer.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/Graphics/Renderer.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/Input/InputEvents.h>
#include <Urho3D/Physics/PhysicsEvents.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/Scene/SceneEvents.h>
#include <Urho3D/Urho2D/CollisionBox2D.h>
#include <Urho3D/Urho2D/CollisionCircle2D.h>
#include <Urho3D/Urho2D/PhysicsWorld2D.h>
#include <Urho3D/Urho2D/RigidBody2D.h>

#include <Urho3D/Scene/Component.h>

using namespace Urho3D;

class Main : public Application {
    URHO3D_OBJECT(Main, Application);
    public:
    Main(Context* context) : Application(context) {}
    virtual void Setup() override {
        engineParameters_[EP_FULL_SCREEN] = false;
        engineParameters_[EP_WINDOW_TITLE] = __FILE__;
        engineParameters_[EP_WINDOW_HEIGHT] = 512;
        engineParameters_[EP_WINDOW_WIDTH] = 512;
    }
    void Start() {
        auto windowWidth = 10.0f;
        auto windowHeight = windowWidth;
        auto groundWidth = windowWidth;
        auto groundHeight = 1.0f;
        auto ballRadius = 0.5f;
        auto ballRestitution = 0.8f;
        auto ballDensity = 1.0f;

        // TODO: not working. Is there any way to avoid creating a custom
        // Component as in the ragdoll example?
        SubscribeToEvent(E_NODECOLLISION, URHO3D_HANDLER(Main, HandleNodeCollision));
        SubscribeToEvent(E_POSTRENDERUPDATE, URHO3D_HANDLER(Main, HandlePostRenderUpdate));
        SubscribeToEvent(E_KEYDOWN, URHO3D_HANDLER(Main, HandleKeyDown));

        // Scene
        this->scene_ = new Scene(this->context_);
        this->scene_->CreateComponent<Octree>();
        this->scene_->CreateComponent<DebugRenderer>();
        this->scene_->CreateComponent<PhysicsWorld2D>();
        auto physicsWorld = scene_->GetComponent<PhysicsWorld2D>();
        physicsWorld->SetGravity(Vector2(0.0f, -10.0f));

        // Graphics
        auto cameraNode_ = this->scene_->CreateChild("Camera");
        // Center of the camera.
        cameraNode_->SetPosition(Vector3(0.0f, windowHeight / 2.0, -1.0f));
        auto camera = cameraNode_->CreateComponent<Camera>();
        camera->SetOrthographic(true);
        camera->SetOrthoSize(windowWidth);
        auto renderer = GetSubsystem<Renderer>();
        SharedPtr<Viewport> viewport(new Viewport(context_, this->scene_, cameraNode_->GetComponent<Camera>()));
        renderer->SetViewport(0, viewport);

        // Ground
        {
            auto node = this->scene_->CreateChild("Ground");
            node->SetPosition(Vector3(0.0f, groundHeight / 2.0f, 0.0f));
            node->CreateComponent<RigidBody2D>();
            auto collisionBox2d = node->CreateComponent<CollisionBox2D>();
            collisionBox2d->SetSize(Vector2(groundWidth, groundHeight));
        }

        // Falling balls
        {
            auto nodeLeft  = this->scene_->CreateChild("BallLeft");
            {
                auto& node = nodeLeft;
                node->SetPosition(Vector3(-windowWidth / 4.0f, windowHeight / 2.0f, 0.0f));
                auto body = node->CreateComponent<RigidBody2D>();
                body->SetBodyType(BT_DYNAMIC);
                auto collisionCircle2d = node->CreateComponent<CollisionCircle2D>();
                collisionCircle2d->SetRadius(ballRadius);
                collisionCircle2d->SetDensity(ballDensity);
                collisionCircle2d->SetRestitution(ballRestitution);
            }
            auto nodeRight = nodeLeft->Clone();
            nodeRight->SetPosition(Vector3(windowWidth / 4.0f, windowHeight * (3.0f / 4.0f), 0.0f));
        }
    }
    void Stop() {}
    private:
    SharedPtr<Scene> scene_;
    void HandleNodeCollision(StringHash eventType, VariantMap& eventData) {
        std::cout << "asdf" << std::endl;
    }
    void HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData) {
        auto physicsWorld = this->scene_->GetComponent<PhysicsWorld2D>();
        physicsWorld->DrawDebugGeometry();
    }
    void HandleKeyDown(StringHash /*eventType*/, VariantMap& eventData) {
        using namespace KeyDown;
        int key = eventData[P_KEY].GetInt();
        if (key == KEY_ESCAPE) {
            engine_->Exit();
        }
    }
};

URHO3D_DEFINE_APPLICATION_MAIN(Main);

类似的可运行和正常工作的3D版本可在以下位置找到:https://github.com/cirosantilli/Urho3D-cheat/blob/e2c955a45d8328fd5f8bf4df5685653452cb28a7/collision3d.cpp

1 个答案:

答案 0 :(得分:2)

2D事件名称为E_NODEBEGINCONTACT2D

只需将E_NODECOLLISION替换为E_NODEUPDATECONTACT2D即可。

发现于:https://discourse.urho3d.io/t/solved-help-with-collision-detection/1667

此文件中包含所有2D事件的名称:https://github.com/urho3d/Urho3D/blob/26ff4fce30bcc8f5a9f21e0e938d221cb2a53eaa/Source/Urho3D/Urho2D/PhysicsEvents2D.h#L35它们是:

  • E_PHYSICSUPDATECONTACT2D:联系时。一次为两个机构。
  • E_PHYSICSBEGINCONTACT2D:开始联系
  • E_PHYSICSENDCONTACT2D:联系结束
  • E_NODEUPDATECONTACT2D:联系时。每个身体一次。
  • E_NODEBEGINCONTACT2D:开始联系
  • E_NODEENDCONTACT2D:结束联系

这是我更新的工作代码,它还从事件中提取碰撞信息:https://github.com/cirosantilli/Urho3D-cheat/blob/353d0353328fc4deb788336f740c7df00d3415f1/collision.cpp#L110