refactor(构建系统): 移除示例项目中的冗余资源打包逻辑
refactor(文档): 更新节点系统教程避免双重引用问题 fix(四叉树): 修复碰撞检测中的缓冲区越界问题 refactor(空间索引示例): 使用 getChildren() 替代私有 vector 存储节点 style(精灵批处理): 调整代码格式和初始化顺序
This commit is contained in:
parent
010e48753c
commit
1b72a1c992
|
|
@ -53,8 +53,8 @@ void main() {
|
||||||
)";
|
)";
|
||||||
|
|
||||||
GLSpriteBatch::GLSpriteBatch()
|
GLSpriteBatch::GLSpriteBatch()
|
||||||
: vao_(0), vbo_(0), ibo_(0), currentTexture_(nullptr), currentIsSDF_(false),
|
: vao_(0), vbo_(0), ibo_(0), vertexCount_(0), currentTexture_(nullptr),
|
||||||
vertexCount_(0), drawCallCount_(0), spriteCount_(0), batchCount_(0) {
|
currentIsSDF_(false), drawCallCount_(0), spriteCount_(0), batchCount_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GLSpriteBatch::~GLSpriteBatch() { shutdown(); }
|
GLSpriteBatch::~GLSpriteBatch() { shutdown(); }
|
||||||
|
|
@ -111,7 +111,8 @@ bool GLSpriteBatch::init() {
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
E2D_LOG_INFO("GLSpriteBatch initialized with capacity for {} sprites", MAX_SPRITES);
|
E2D_LOG_INFO("GLSpriteBatch initialized with capacity for {} sprites",
|
||||||
|
MAX_SPRITES);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,18 +141,17 @@ void GLSpriteBatch::begin(const glm::mat4 &viewProjection) {
|
||||||
batchCount_ = 0;
|
batchCount_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLSpriteBatch::needsFlush(const Texture& texture, bool isSDF) const {
|
bool GLSpriteBatch::needsFlush(const Texture &texture, bool isSDF) const {
|
||||||
if (currentTexture_ == nullptr) {
|
if (currentTexture_ == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否需要刷新:纹理改变、SDF 状态改变或缓冲区已满
|
// 检查是否需要刷新:纹理改变、SDF 状态改变或缓冲区已满
|
||||||
return (currentTexture_ != &texture) ||
|
return (currentTexture_ != &texture) || (currentIsSDF_ != isSDF) ||
|
||||||
(currentIsSDF_ != isSDF) ||
|
|
||||||
(vertexCount_ + VERTICES_PER_SPRITE > MAX_VERTICES);
|
(vertexCount_ + VERTICES_PER_SPRITE > MAX_VERTICES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLSpriteBatch::addVertices(const SpriteData& data) {
|
void GLSpriteBatch::addVertices(const SpriteData &data) {
|
||||||
// 计算变换后的顶点位置
|
// 计算变换后的顶点位置
|
||||||
glm::vec2 anchorOffset(data.size.x * data.anchor.x,
|
glm::vec2 anchorOffset(data.size.x * data.anchor.x,
|
||||||
data.size.y * data.anchor.y);
|
data.size.y * data.anchor.y);
|
||||||
|
|
@ -172,10 +172,14 @@ void GLSpriteBatch::addVertices(const SpriteData& data) {
|
||||||
// v0(左上) -- v1(右上)
|
// v0(左上) -- v1(右上)
|
||||||
// | |
|
// | |
|
||||||
// v3(左下) -- v2(右下)
|
// v3(左下) -- v2(右下)
|
||||||
Vertex v0{transform(0, 0), glm::vec2(data.texCoordMin.x, data.texCoordMin.y), color};
|
Vertex v0{transform(0, 0), glm::vec2(data.texCoordMin.x, data.texCoordMin.y),
|
||||||
Vertex v1{transform(data.size.x, 0), glm::vec2(data.texCoordMax.x, data.texCoordMin.y), color};
|
color};
|
||||||
Vertex v2{transform(data.size.x, data.size.y), glm::vec2(data.texCoordMax.x, data.texCoordMax.y), color};
|
Vertex v1{transform(data.size.x, 0),
|
||||||
Vertex v3{transform(0, data.size.y), glm::vec2(data.texCoordMin.x, data.texCoordMax.y), color};
|
glm::vec2(data.texCoordMax.x, data.texCoordMin.y), color};
|
||||||
|
Vertex v2{transform(data.size.x, data.size.y),
|
||||||
|
glm::vec2(data.texCoordMax.x, data.texCoordMax.y), color};
|
||||||
|
Vertex v3{transform(0, data.size.y),
|
||||||
|
glm::vec2(data.texCoordMin.x, data.texCoordMax.y), color};
|
||||||
|
|
||||||
vertexBuffer_[vertexCount_++] = v0;
|
vertexBuffer_[vertexCount_++] = v0;
|
||||||
vertexBuffer_[vertexCount_++] = v1;
|
vertexBuffer_[vertexCount_++] = v1;
|
||||||
|
|
@ -196,50 +200,52 @@ void GLSpriteBatch::draw(const Texture &texture, const SpriteData &data) {
|
||||||
spriteCount_++;
|
spriteCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLSpriteBatch::drawBatch(const Texture& texture, const std::vector<SpriteData>& sprites) {
|
void GLSpriteBatch::drawBatch(const Texture &texture,
|
||||||
|
const std::vector<SpriteData> &sprites) {
|
||||||
if (sprites.empty()) {
|
if (sprites.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果当前有未提交的批次且纹理不同,先刷新
|
// 如果当前有未提交的批次且纹理不同,先刷新
|
||||||
if (currentTexture_ != nullptr && currentTexture_ != &texture) {
|
if (currentTexture_ != nullptr && currentTexture_ != &texture) {
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTexture_ = &texture;
|
currentTexture_ = &texture;
|
||||||
currentIsSDF_ = sprites[0].isSDF; // 假设批量中的精灵 SDF 状态一致
|
currentIsSDF_ = sprites[0].isSDF; // 假设批量中的精灵 SDF 状态一致
|
||||||
|
|
||||||
// 分批处理,避免超过缓冲区大小
|
// 分批处理,避免超过缓冲区大小
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
while (index < sprites.size()) {
|
while (index < sprites.size()) {
|
||||||
size_t remainingSpace = (MAX_VERTICES - vertexCount_) / VERTICES_PER_SPRITE;
|
size_t remainingSpace = (MAX_VERTICES - vertexCount_) / VERTICES_PER_SPRITE;
|
||||||
size_t batchSize = std::min(sprites.size() - index, remainingSpace);
|
size_t batchSize = std::min(sprites.size() - index, remainingSpace);
|
||||||
|
|
||||||
for (size_t i = 0; i < batchSize; ++i) {
|
for (size_t i = 0; i < batchSize; ++i) {
|
||||||
addVertices(sprites[index + i]);
|
addVertices(sprites[index + i]);
|
||||||
spriteCount_++;
|
spriteCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
index += batchSize;
|
index += batchSize;
|
||||||
|
|
||||||
// 如果还有更多精灵,刷新当前批次
|
// 如果还有更多精灵,刷新当前批次
|
||||||
if (index < sprites.size()) {
|
if (index < sprites.size()) {
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
batchCount_++;
|
batchCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLSpriteBatch::drawImmediate(const Texture& texture, const SpriteData& data) {
|
void GLSpriteBatch::drawImmediate(const Texture &texture,
|
||||||
|
const SpriteData &data) {
|
||||||
// 立即绘制,不缓存 - 用于需要立即显示的情况
|
// 立即绘制,不缓存 - 用于需要立即显示的情况
|
||||||
flush(); // 先提交当前批次
|
flush(); // 先提交当前批次
|
||||||
|
|
||||||
currentTexture_ = &texture;
|
currentTexture_ = &texture;
|
||||||
currentIsSDF_ = data.isSDF;
|
currentIsSDF_ = data.isSDF;
|
||||||
addVertices(data);
|
addVertices(data);
|
||||||
spriteCount_++;
|
spriteCount_++;
|
||||||
|
|
||||||
flush(); // 立即提交
|
flush(); // 立即提交
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,7 +276,8 @@ void GLSpriteBatch::flush() {
|
||||||
|
|
||||||
// 更新 VBO 数据 - 只更新实际使用的部分
|
// 更新 VBO 数据 - 只更新实际使用的部分
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount_ * sizeof(Vertex), vertexBuffer_.data());
|
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount_ * sizeof(Vertex),
|
||||||
|
vertexBuffer_.data());
|
||||||
|
|
||||||
// 绘制
|
// 绘制
|
||||||
glBindVertexArray(vao_);
|
glBindVertexArray(vao_);
|
||||||
|
|
@ -280,7 +287,7 @@ void GLSpriteBatch::flush() {
|
||||||
|
|
||||||
drawCallCount_++;
|
drawCallCount_++;
|
||||||
batchCount_++;
|
batchCount_++;
|
||||||
|
|
||||||
// 重置状态
|
// 重置状态
|
||||||
vertexCount_ = 0;
|
vertexCount_ = 0;
|
||||||
currentTexture_ = nullptr;
|
currentTexture_ = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -248,9 +248,12 @@ void QuadTree::collectCollisions(
|
||||||
if (!current)
|
if (!current)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// 确保 ancestorEnd 不超过当前 buffer 大小
|
||||||
|
size_t validAncestorEnd = std::min(item.ancestorEnd, collisionBuffer_.size());
|
||||||
|
|
||||||
// 检测当前节点对象与祖先对象的碰撞
|
// 检测当前节点对象与祖先对象的碰撞
|
||||||
for (const auto &[obj, bounds] : current->objects) {
|
for (const auto &[obj, bounds] : current->objects) {
|
||||||
for (size_t i = item.ancestorStart; i < item.ancestorEnd; ++i) {
|
for (size_t i = item.ancestorStart; i < validAncestorEnd; ++i) {
|
||||||
const auto &[ancestorObj, ancestorBounds] = collisionBuffer_[i];
|
const auto &[ancestorObj, ancestorBounds] = collisionBuffer_[i];
|
||||||
if (bounds.intersects(ancestorBounds)) {
|
if (bounds.intersects(ancestorBounds)) {
|
||||||
collisions.emplace_back(ancestorObj, obj);
|
collisions.emplace_back(ancestorObj, obj);
|
||||||
|
|
@ -277,10 +280,15 @@ void QuadTree::collectCollisions(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 恢复祖先列表(模拟递归返回)
|
// 恢复祖先列表(模拟递归返回)
|
||||||
if (stack.empty() ||
|
// 只有当栈顶元素的祖先范围与当前不同时,才需要恢复
|
||||||
(stack.back().ancestorStart != oldSize &&
|
if (stack.empty()) {
|
||||||
stack.back().ancestorEnd != collisionBuffer_.size())) {
|
|
||||||
collisionBuffer_.resize(oldSize);
|
collisionBuffer_.resize(oldSize);
|
||||||
|
} else {
|
||||||
|
const auto& nextItem = stack.back();
|
||||||
|
// 如果下一个节点的祖先范围与当前不同,则需要恢复到其祖先起始位置
|
||||||
|
if (nextItem.ancestorStart != oldSize) {
|
||||||
|
collisionBuffer_.resize(oldSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -528,6 +528,42 @@ void GameOverLayer::initPanel(int score, float screenHeight) {
|
||||||
- 引擎会自动在渲染前调用
|
- 引擎会自动在渲染前调用
|
||||||
- 如果需要强制更新变换,可以手动调用
|
- 如果需要强制更新变换,可以手动调用
|
||||||
|
|
||||||
|
7. **避免双重引用**:
|
||||||
|
- 节点通过 `addChild()` 添加到场景后,由场景统一管理
|
||||||
|
- **不要**额外存储 `shared_ptr` 到 vector 中,避免双重引用问题
|
||||||
|
- 使用 `getChildren()` 访问子节点,配合 `dynamic_cast` 筛选特定类型
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// ❌ 错误:双重引用
|
||||||
|
class BadScene : public Scene {
|
||||||
|
private:
|
||||||
|
std::vector<Ptr<Sprite>> sprites_; // 不要这样做!
|
||||||
|
public:
|
||||||
|
void createSprite() {
|
||||||
|
auto sprite = Sprite::create(texture);
|
||||||
|
addChild(sprite);
|
||||||
|
sprites_.push_back(sprite); // 双重引用!
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ 正确:通过 getChildren() 访问
|
||||||
|
class GoodScene : public Scene {
|
||||||
|
public:
|
||||||
|
void createSprite() {
|
||||||
|
auto sprite = Sprite::create(texture);
|
||||||
|
addChild(sprite); // 场景统一管理
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSprites() {
|
||||||
|
for (const auto& child : getChildren()) {
|
||||||
|
if (auto sprite = dynamic_cast<Sprite*>(child.get())) {
|
||||||
|
// 处理 sprite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## 下一步
|
## 下一步
|
||||||
|
|
||||||
- [04. 资源管理](./04_Resource_Management.md) - 深入了解资源加载
|
- [04. 资源管理](./04_Resource_Management.md) - 深入了解资源加载
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,10 @@ public:
|
||||||
Scene::onUpdate(dt);
|
Scene::onUpdate(dt);
|
||||||
|
|
||||||
// 清除之前的碰撞状态
|
// 清除之前的碰撞状态
|
||||||
for (auto& box : boxes_) {
|
for (const auto& child : getChildren()) {
|
||||||
box->setColliding(false);
|
if (auto box = dynamic_cast<CollidableBox*>(child.get())) {
|
||||||
|
box->setColliding(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用场景的空间索引查询所有碰撞
|
// 使用场景的空间索引查询所有碰撞
|
||||||
|
|
@ -82,11 +84,16 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void createBox(float x, float y) {
|
||||||
std::vector<Ptr<CollidableBox>> boxes_;
|
auto box = makePtr<CollidableBox>(50.0f, 50.0f, Color(0.3f, 0.7f, 1.0f, 0.8f));
|
||||||
|
box->setPosition(Vec2(x, y));
|
||||||
|
addChild(box); // 通过 addChild 管理节点生命周期
|
||||||
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**注意**:节点通过 `addChild()` 添加到场景后,由场景统一管理生命周期。不要额外存储 `shared_ptr` 到 vector 中,避免双重引用问题。
|
||||||
|
|
||||||
## 空间索引策略
|
## 空间索引策略
|
||||||
|
|
||||||
### 切换策略
|
### 切换策略
|
||||||
|
|
@ -123,18 +130,19 @@ public:
|
||||||
Scene::onEnter();
|
Scene::onEnter();
|
||||||
|
|
||||||
// 创建100个碰撞节点
|
// 创建100个碰撞节点
|
||||||
createNodes(100);
|
createPhysicsNodes(100);
|
||||||
|
|
||||||
E2D_LOG_INFO("创建了 {} 个碰撞节点", nodes_.size());
|
|
||||||
E2D_LOG_INFO("空间索引已启用: {}", isSpatialIndexingEnabled());
|
E2D_LOG_INFO("空间索引已启用: {}", isSpatialIndexingEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdate(float dt) override {
|
void onUpdate(float dt) override {
|
||||||
Scene::onUpdate(dt);
|
Scene::onUpdate(dt);
|
||||||
|
|
||||||
// 更新所有节点位置
|
// 更新所有物理节点位置(通过 getChildren() 访问)
|
||||||
for (auto& node : nodes_) {
|
for (const auto& child : getChildren()) {
|
||||||
node->update(dt, screenWidth_, screenHeight_);
|
if (auto node = dynamic_cast<PhysicsNode*>(child.get())) {
|
||||||
|
node->update(dt, screenWidth_, screenHeight_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用空间索引进行碰撞检测
|
// 使用空间索引进行碰撞检测
|
||||||
|
|
@ -150,8 +158,10 @@ public:
|
||||||
private:
|
private:
|
||||||
void performCollisionDetection() {
|
void performCollisionDetection() {
|
||||||
// 清除之前的碰撞状态
|
// 清除之前的碰撞状态
|
||||||
for (auto& node : nodes_) {
|
for (const auto& child : getChildren()) {
|
||||||
node->setColliding(false);
|
if (auto node = dynamic_cast<PhysicsNode*>(child.get())) {
|
||||||
|
node->setColliding(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用引擎自带的空间索引进行碰撞检测
|
// 使用引擎自带的空间索引进行碰撞检测
|
||||||
|
|
@ -180,9 +190,25 @@ private:
|
||||||
E2D_LOG_INFO("切换到四叉树策略");
|
E2D_LOG_INFO("切换到四叉树策略");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取物理节点数量
|
||||||
|
size_t getPhysicsNodeCount() const {
|
||||||
|
size_t count = 0;
|
||||||
|
for (const auto& child : getChildren()) {
|
||||||
|
if (dynamic_cast<PhysicsNode*>(child.get())) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**关键改进**:
|
||||||
|
- 使用 `getChildren()` 代替私有 vector 存储节点引用
|
||||||
|
- 通过 `dynamic_cast` 筛选特定类型的子节点
|
||||||
|
- 避免双重引用,简化生命周期管理
|
||||||
|
|
||||||
## 关键要点
|
## 关键要点
|
||||||
|
|
||||||
1. **必须调用 `setSpatialIndexed(true)`** - 启用节点的空间索引
|
1. **必须调用 `setSpatialIndexed(true)`** - 启用节点的空间索引
|
||||||
|
|
|
||||||
|
|
@ -72,20 +72,5 @@ target("collision_demo")
|
||||||
print("Warning: romfs directory not found at " .. romfs)
|
print("Warning: romfs directory not found at " .. romfs)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 打包时将资源复制到 package 目录
|
|
||||||
after_package(function (target)
|
|
||||||
local target_dir = path.directory(target:targetfile())
|
|
||||||
local assets_dir = path.join(target_dir, "assets")
|
|
||||||
local package_dir = target:packagedir()
|
|
||||||
if os.isdir(assets_dir) and package_dir then
|
|
||||||
local package_assets = path.join(package_dir, "assets")
|
|
||||||
if not os.isdir(package_assets) then
|
|
||||||
os.mkdir(package_assets)
|
|
||||||
end
|
|
||||||
os.cp(path.join(assets_dir, "**"), package_assets)
|
|
||||||
print("Copied assets to package: " .. package_assets)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
target_end()
|
target_end()
|
||||||
|
|
|
||||||
|
|
@ -73,20 +73,5 @@ target("flappy_bird")
|
||||||
print("Warning: romfs directory not found at " .. romfs)
|
print("Warning: romfs directory not found at " .. romfs)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 打包时将资源复制到 package 目录
|
|
||||||
after_package(function (target)
|
|
||||||
local target_dir = path.directory(target:targetfile())
|
|
||||||
local assets_dir = path.join(target_dir, "assets")
|
|
||||||
local package_dir = target:packagedir()
|
|
||||||
if os.isdir(assets_dir) and package_dir then
|
|
||||||
local package_assets = path.join(package_dir, "assets")
|
|
||||||
if not os.isdir(package_assets) then
|
|
||||||
os.mkdir(package_assets)
|
|
||||||
end
|
|
||||||
os.cp(path.join(assets_dir, "**"), package_assets)
|
|
||||||
print("Copied assets to package: " .. package_assets)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
target_end()
|
target_end()
|
||||||
|
|
|
||||||
|
|
@ -72,20 +72,5 @@ target("hello_world")
|
||||||
print("Warning: romfs directory not found at " .. romfs)
|
print("Warning: romfs directory not found at " .. romfs)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 打包时将资源复制到 package 目录
|
|
||||||
after_package(function (target)
|
|
||||||
local target_dir = path.directory(target:targetfile())
|
|
||||||
local assets_dir = path.join(target_dir, "assets")
|
|
||||||
local package_dir = target:packagedir()
|
|
||||||
if os.isdir(assets_dir) and package_dir then
|
|
||||||
local package_assets = path.join(package_dir, "assets")
|
|
||||||
if not os.isdir(package_assets) then
|
|
||||||
os.mkdir(package_assets)
|
|
||||||
end
|
|
||||||
os.cp(path.join(assets_dir, "**"), package_assets)
|
|
||||||
print("Copied assets to package: " .. package_assets)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
target_end()
|
target_end()
|
||||||
|
|
|
||||||
|
|
@ -72,20 +72,5 @@ target("push_box")
|
||||||
print("Warning: romfs directory not found at " .. romfs)
|
print("Warning: romfs directory not found at " .. romfs)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 打包时将资源复制到 package 目录
|
|
||||||
after_package(function (target)
|
|
||||||
local target_dir = path.directory(target:targetfile())
|
|
||||||
local assets_dir = path.join(target_dir, "assets")
|
|
||||||
local package_dir = target:packagedir()
|
|
||||||
if os.isdir(assets_dir) and package_dir then
|
|
||||||
local package_assets = path.join(package_dir, "assets")
|
|
||||||
if not os.isdir(package_assets) then
|
|
||||||
os.mkdir(package_assets)
|
|
||||||
end
|
|
||||||
os.cp(path.join(assets_dir, "**"), package_assets)
|
|
||||||
print("Copied assets to package: " .. package_assets)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
target_end()
|
target_end()
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
#include <cmath>
|
|
||||||
#include <extra2d/extra2d.h>
|
#include <extra2d/extra2d.h>
|
||||||
#include <iomanip>
|
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
||||||
|
|
@ -106,19 +103,15 @@ public:
|
||||||
setBackgroundColor(Color(0.05f, 0.05f, 0.1f, 1.0f));
|
setBackgroundColor(Color(0.05f, 0.05f, 0.1f, 1.0f));
|
||||||
|
|
||||||
// 创建100个碰撞节点
|
// 创建100个碰撞节点
|
||||||
createNodes(100);
|
createPhysicsNodes(100);
|
||||||
|
|
||||||
// 加载字体
|
// 加载字体
|
||||||
loadFonts();
|
loadFonts();
|
||||||
|
|
||||||
E2D_LOG_INFO("创建了 {} 个碰撞节点", nodes_.size());
|
|
||||||
E2D_LOG_INFO("空间索引已启用: {}", isSpatialIndexingEnabled());
|
E2D_LOG_INFO("空间索引已启用: {}", isSpatialIndexingEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
void onExit() override {
|
void onExit() override {
|
||||||
// 先清理 nodes_ 向量
|
|
||||||
nodes_.clear();
|
|
||||||
|
|
||||||
// 显式移除所有子节点,确保在场景析构前正确清理空间索引
|
// 显式移除所有子节点,确保在场景析构前正确清理空间索引
|
||||||
// 这必须在 Scene::onExit() 之前调用,因为 onExit() 会将 running_ 设为 false
|
// 这必须在 Scene::onExit() 之前调用,因为 onExit() 会将 running_ 设为 false
|
||||||
removeAllChildren();
|
removeAllChildren();
|
||||||
|
|
@ -131,9 +124,11 @@ public:
|
||||||
|
|
||||||
auto startTime = std::chrono::high_resolution_clock::now();
|
auto startTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// 更新所有节点位置
|
// 更新所有物理节点位置
|
||||||
for (auto &node : nodes_) {
|
for (const auto &child : getChildren()) {
|
||||||
node->update(dt, screenWidth_, screenHeight_);
|
if (auto node = dynamic_cast<PhysicsNode *>(child.get())) {
|
||||||
|
node->update(dt, screenWidth_, screenHeight_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto updateEndTime = std::chrono::high_resolution_clock::now();
|
auto updateEndTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
@ -149,7 +144,8 @@ public:
|
||||||
collisionEndTime - updateEndTime)
|
collisionEndTime - updateEndTime)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
stats_.nodeCount = nodes_.size();
|
// 统计物理节点数量
|
||||||
|
stats_.nodeCount = getPhysicsNodeCount();
|
||||||
|
|
||||||
// 获取当前使用的空间索引策略
|
// 获取当前使用的空间索引策略
|
||||||
stats_.strategyName = getSpatialManager().getStrategyName();
|
stats_.strategyName = getSpatialManager().getStrategyName();
|
||||||
|
|
@ -310,9 +306,9 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建指定数量的节点
|
* @brief 创建指定数量的物理节点
|
||||||
*/
|
*/
|
||||||
void createNodes(size_t count) {
|
void createPhysicsNodes(size_t count) {
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 gen(rd());
|
std::mt19937 gen(rd());
|
||||||
std::uniform_real_distribution<float> posX(50.0f, screenWidth_ - 50.0f);
|
std::uniform_real_distribution<float> posX(50.0f, screenWidth_ - 50.0f);
|
||||||
|
|
@ -326,38 +322,70 @@ private:
|
||||||
auto node = makePtr<PhysicsNode>(20.0f, color, static_cast<int>(i));
|
auto node = makePtr<PhysicsNode>(20.0f, color, static_cast<int>(i));
|
||||||
node->setPosition(Vec2(posX(gen), posY(gen)));
|
node->setPosition(Vec2(posX(gen), posY(gen)));
|
||||||
addChild(node);
|
addChild(node);
|
||||||
nodes_.push_back(node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取物理节点数量
|
||||||
|
*/
|
||||||
|
size_t getPhysicsNodeCount() const {
|
||||||
|
size_t count = 0;
|
||||||
|
for (const auto &child : getChildren()) {
|
||||||
|
if (dynamic_cast<PhysicsNode *>(child.get())) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取所有物理节点
|
||||||
|
*/
|
||||||
|
std::vector<PhysicsNode *> getPhysicsNodes() const {
|
||||||
|
std::vector<PhysicsNode *> nodes;
|
||||||
|
for (const auto &child : getChildren()) {
|
||||||
|
if (auto node = dynamic_cast<PhysicsNode *>(child.get())) {
|
||||||
|
nodes.push_back(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 添加节点
|
* @brief 添加节点
|
||||||
*/
|
*/
|
||||||
void addNodes(size_t count) {
|
void addNodes(size_t count) {
|
||||||
size_t currentCount = nodes_.size();
|
size_t currentCount = getPhysicsNodeCount();
|
||||||
if (currentCount + count > 5000) {
|
if (currentCount + count > 5000) {
|
||||||
E2D_LOG_WARN("节点数量已达上限(5000)");
|
E2D_LOG_WARN("节点数量已达上限(5000)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
createNodes(count);
|
createPhysicsNodes(count);
|
||||||
E2D_LOG_INFO("添加 {} 个节点,当前总数: {}", count, nodes_.size());
|
E2D_LOG_INFO("添加 {} 个节点,当前总数: {}", count, getPhysicsNodeCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 移除节点
|
* @brief 移除节点
|
||||||
*/
|
*/
|
||||||
void removeNodes(size_t count) {
|
void removeNodes(size_t count) {
|
||||||
if (count >= nodes_.size()) {
|
auto physicsNodes = getPhysicsNodes();
|
||||||
count = nodes_.size();
|
if (count >= physicsNodes.size()) {
|
||||||
|
count = physicsNodes.size();
|
||||||
}
|
}
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// 从后往前移除指定数量的节点
|
||||||
for (size_t i = 0; i < count; ++i) {
|
for (size_t i = 0; i < count; ++i) {
|
||||||
removeChild(nodes_.back());
|
// 找到最后一个物理节点对应的子节点并移除
|
||||||
nodes_.pop_back();
|
for (auto it = getChildren().rbegin(); it != getChildren().rend(); ++it) {
|
||||||
|
if (dynamic_cast<PhysicsNode *>(it->get())) {
|
||||||
|
removeChild(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
E2D_LOG_INFO("移除 {} 个节点,当前总数: {}", count, nodes_.size());
|
E2D_LOG_INFO("移除 {} 个节点,当前总数: {}", count, getPhysicsNodeCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -385,8 +413,10 @@ private:
|
||||||
*/
|
*/
|
||||||
void performCollisionDetection() {
|
void performCollisionDetection() {
|
||||||
// 清除之前的碰撞状态
|
// 清除之前的碰撞状态
|
||||||
for (auto &node : nodes_) {
|
for (const auto &child : getChildren()) {
|
||||||
node->setColliding(false);
|
if (auto node = dynamic_cast<PhysicsNode *>(child.get())) {
|
||||||
|
node->setColliding(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用引擎自带的空间索引进行碰撞检测
|
// 使用引擎自带的空间索引进行碰撞检测
|
||||||
|
|
@ -442,7 +472,6 @@ private:
|
||||||
Color(1.0f, 0.2f, 0.2f, 0.9f));
|
Color(1.0f, 0.2f, 0.2f, 0.9f));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Ptr<PhysicsNode>> nodes_;
|
|
||||||
PerformanceStats stats_;
|
PerformanceStats stats_;
|
||||||
float screenWidth_ = 1280.0f;
|
float screenWidth_ = 1280.0f;
|
||||||
float screenHeight_ = 720.0f;
|
float screenHeight_ = 720.0f;
|
||||||
|
|
@ -473,8 +502,7 @@ private:
|
||||||
// 程序入口
|
// 程序入口
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv) {
|
||||||
{
|
|
||||||
Logger::init();
|
Logger::init();
|
||||||
Logger::setLevel(LogLevel::Debug);
|
Logger::setLevel(LogLevel::Debug);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,20 +72,5 @@ target("spatial_index_demo")
|
||||||
print("Warning: romfs directory not found at " .. romfs)
|
print("Warning: romfs directory not found at " .. romfs)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 打包时将资源复制到 package 目录
|
|
||||||
after_package(function (target)
|
|
||||||
local target_dir = path.directory(target:targetfile())
|
|
||||||
local assets_dir = path.join(target_dir, "assets")
|
|
||||||
local package_dir = target:packagedir()
|
|
||||||
if os.isdir(assets_dir) and package_dir then
|
|
||||||
local package_assets = path.join(package_dir, "assets")
|
|
||||||
if not os.isdir(package_assets) then
|
|
||||||
os.mkdir(package_assets)
|
|
||||||
end
|
|
||||||
os.cp(path.join(assets_dir, "**"), package_assets)
|
|
||||||
print("Copied assets to package: " .. package_assets)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
target_end()
|
target_end()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue