iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
自我挑戰組

寫遊戲初體驗系列 第 24

Day 24 EnTT

  • 分享至 

  • xImage
  •  

EnTT

github

前言

當初在寫完ECS之後測試完一直覺得怪怪的,對自己不是很自信,總感覺自己ECS寫壞了寫爛了,所以為了測試我寫的是不是對的,就去稍微聊解一下這個lib。

當然我沒有讀它的code,畢竟有點太多,所以我只打算拿它來測試。
事實上EnTT不只有ECS的功能,作者寫完ECS覺得不夠就加了許多功能近去,但這裏我們只測試它的ECS
它的ECS當然比我們自己寫的功能要多,但我只使用了裡面的幾個,只要能達到成千上萬個沙奈朵掉下來就好。

環境

這邊當初搞了我好一段時間,但其實只要把它當成你project裡的submodule就可以了。

或著把它的entt資料夾直接複製一分到你的專案李。

開始吧

submodule弄好之後只要一個簡單的include就好。

#include "entt/entt.hpp"

一樣的3個Component。

struct Transform {

    float x_;
    float y_;
};

struct RigidBody {

    float v_;
};


struct Graphic {

    Gardevoir *gardevoir;
    sf::Texture texture_;
    sf::Sprite sprite_;
};

這邊我會比較EnTT與我們自己寫的用法小差異

  • 宣告
entt::registry registry;
  • 產生Entity
for (auto i = 0; i < MAX_ENTITES; ++i)
{
    auto entity = registry.create();
    registry.emplace<Transform>(entity, randPositionX(generator), randPositionY(generator));
    registry.emplace<Graphic>(entity, gardevoir);
    registry.emplace<RigidBody>(entity, 10.0f);
}

這樣就結束了。
回想一下我們寫的,我們要先進行註冊對吧。
當然或許它的emplace裡有實現註冊的方法,不過我們不知道。

接這我們來寫系統吧。

一樣我們只有兩個系統,當我寫完時我才發現,根本87%像。

class PhysicSystem {

public:

    PhysicSystem() = default;

    void update(entt::registry& registry, float dt);

};


class GraphicSystem {

public:
    GraphicSystem() = default;

    void update(entt::registry& registry);

    void setSprite(entt::registry& registry);

    void render(entt::registry& registry, sf::RenderTarget& targer);
};


void PhysicSystem::update(entt::registry& registry, float dt) {

    auto view = registry.view<Transform, RigidBody>();

    for(auto entity: view) {

        auto& transform = view.get<Transform>(entity);
        auto& rigidBody = view.get<RigidBody>(entity);

        transform.y_ += rigidBody.v_ * dt;
        rigidBody.v_ += 10 * dt;
    }
}

void GraphicSystem::update(entt::registry& registry) {

    auto view = registry.view<Transform, Graphic>();

    for (auto entity: view) {

        auto& transform = view.get<Transform>(entity);
        auto& graphic = view.get<Graphic>(entity);

        graphic.sprite_.setPosition(transform.x_, transform.y_);	
    }
}


void GraphicSystem::setSprite(entt::registry& registry) {

    auto view = registry.view<Graphic>();

    for (auto entity: view) {

        auto& graphic = view.get<Graphic>(entity);
        graphic.sprite_.setTexture(graphic.gardevoir->texture_);
        graphic.sprite_.setScale(0.1, 0.1);
    }

}

void GraphicSystem::render(entt::registry& registry, sf::RenderTarget& target) {

    auto view = registry.view<Graphic>();

    for(auto entity : view) {

        auto& graphic = view.get<Graphic>(entity);
        target.draw(graphic.sprite_);
    }
}

比較一下update的地方

這是我們的

void PhysicSystem::update(float dt) {

    for(auto const& entity : Entities_) {

        auto& transform = ecs.getComponent<Transform>(entity);
        auto& rigidBody = ecs.getComponent<RigidBody>(entity);

        transform.y_ += rigidBody.v_ * dt;

        rigidBody.v_ +=  10 * dt;
    }
}

這是EnTT

void PhysicSystem::update(entt::registry& registry, float dt) {

    auto view = registry.view<Transform, RigidBody>();

    for(auto entity: view) {

        auto& transform = view.get<Transform>(entity);
        auto& rigidBody = view.get<RigidBody>(entity);

        transform.y_ += rigidBody.v_ * dt;
        rigidBody.v_ += 10 * dt;
    }
}

迴圈裡做的事是一模一樣的,根據Entity ID拿到相對應的Component,然後進行更新。

Enttview方法就只是在篩選所要的Entity而已,而我們不需要這樣做是因為我們在為Entity加入Component的時候,就已經利用SignatureSystem篩選它所要的Entity

所以用Entt能夠在你初始化的時候少寫很多東西,用起來真的很方便!

接著我們的遊戲循環想當然的一模一樣囉

while(running) {

    auto startTime = std::chrono::high_resolution_clock::now();

    sf::Event event;

    while(window.pollEvent(event)) {

        if(event.type == sf::Event::Closed)
            running = false;
    }

    graphicSystem.update(registry);
    physicSystem.update(registry, dt);

    window.clear(bgColor);

    graphicSystem.render(registry, window);

    window.display();
    auto endTime = std::chrono::high_resolution_clock::now();
    dt = std::chrono::duration<float, std::chrono::seconds::period>(endTime - startTime).count();

    std::cout << dt << "\n";
}

我們會發現使用起來跟自己的大同小異,但實際上Entt還有許多非常強大的功能,所以之後使用ECS的功能應該就用Entt這個lib


上一篇
Day 23 Entity Component System
下一篇
Day 25 Particle System 01
系列文
寫遊戲初體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言