百度SEO

百度SEO

Products

当前位置:首页 > 百度SEO >

游戏开发新手如何规划自己的13天开发之旅?

96SEO 2026-02-19 10:50 0


上一章节中,我们完成了物理引擎和物理组件的构建,但是我们的物体似乎直接从地面上掉下去了,我们希望的物体应该停在地面上的,不应该穿过去,这章我们会完成如何教会引擎进行

游戏开发新手如何规划自己的13天开发之旅?

哪两个物体在当前帧发生了重叠

data-src="https://img2024.cnblogs.com/blog/2727651/202602/2727651-20260218205730544-858675974.png"

id="1碰撞形状collider">1.碰撞形状(Collider)

物理边界,在2D游戏中,最常用的碰撞形状是矩形(AABB)

圆形(Circle)

我们将创建一个Collider基类和及规格派生类来代表这些形状。

id="enginephysicscolliderh">engine/physics/collider.h

为什么圆形也要使用AABB?

我们可以先使用AABB检测过滤大部分不碰撞的情况,只对AABB重叠的情况再进行精确的圆形检测。

id="2collidercomponent为gameobject添加碰撞体">2.ColliderComponent:为GameObject添加碰撞体

PhysicsComponent类似,需要一个ColliderComponent来将一个Collider形状附加到GameObject上。

  • 持有Collider

    ---

    通过std::unique_ptr管理Collider的生命周期

  • ---

    通过offset_alignment_确定碰撞体相对于Transform的位置

    ---

    提供getWorldAABB()方法,计算碰撞体在世界坐标系中的精确包围盒

    ---

    支持is_trigger_标志,用于不产生物理响应的区域

    id="enginecomponentcollider_componenth">engine/component/collider_component.h

    缓存的TransformComponent指针(非拥有)std::unique_ptr<physics::Collider>

    collider_;

    碰撞器相对于TransformComponent的偏移量,碰撞器左上角相对变换原点的偏移量utils::Alignment

    alignment_

    ColliderComponent(std::unique_ptr<physics::Collider>

    alignment

    可以根据当前的对齐方式和collider_的尺寸计算偏移量offset_*

    @note

    需要使用到transform_中的scale,所以在更新scale时,这力需要进行调用更新,*

    updateOffset();//

    id="enginecomponentcollider_componentcpp">engine/component/collider_component.cpp

    <spdlog/spdlog.h>namespace

    engine

    component{ColliderComponent::ColliderComponent(std::unique_ptr<physics::Collider>

    collider,

    collider_(std::move(collider)),

    isActive_(isActive){if(!collider_){spdlog::error("传入的是个空的collider");}}void

    ColliderComponent::init(){if(!owner_){spdlog::error("collider组件的游戏对象为空");}transform_

    owner_->getComponent<component::TransformComponent>();if(!transform_){spdlog::error("collider组件的游戏对象没有transform组件");return;}updateOffset();}void

    ColliderComponent::updateOffset(){if(!collider_)

    return;glm::vec2

    collider_->getAABBSize();if(collider_size.x

    <=

    transform_->getScale();switch(alignment_){case

    offset_

    utils::Alignment::CENTER_RIGHT:

    offset_

    utils::Alignment::BOTTOM_CENTER:

    offset_

    utils::Alignment::BOTTOM_RIGHT:

    offset_

    ColliderComponent::getWorldAABB()

    const{if(!transform_

    collider_->getAABBSize();const

    glm::vec2

    transform_->getScale();const

    glm::vec2

    ColliderComponent::setAlignment(utils::Alignment

    &&

  • updateOffset()

    ---

    根据对齐方式计算碰撞器相对于Transform的偏移量

  • getWorldAABB()

    ---

    关键方法:计算碰撞体在世界坐标系中的精确包围盒,为碰撞检测提供数据

  • 这个组件持有Collider(通过std::unique_ptr管理其生命周期),并像SpriteComponent一样,通过offset_alignment_来确定碰撞体相对于TransformComponent的位置。

    id="3碰撞检测算法collisionhcpp">3.碰撞检测算法(collision.h/cpp)

    我们将所有纯粹的数学碰撞检测函数放到一个独立的collision命名空间下,这让我们的代码更加清晰

    Collider是抽象基类,定义了所有碰撞器的共有接口,如getType()
    AABB尺寸包含一个aabb_size_,代表能完全包围这个碰撞器的最小矩形尺寸,这在后续的优化中非常有用
    AABBColliderCircleCollider是具体的碰撞形状实现

    id="enginephysicscollisionh">engine/physics/collision.h

    component::ColliderComponent&

    const

    component::ColliderComponent&

    b);/***

    id="enginephysicscollisioncpp">engine/physics/collision.cpp

    "../component/collider_component.h"

    #include

    "../component/transform_component.h"namespace

    checkCollision(const

    a_transform->getScale();auto

    b_size

    b_transform->getScale();auto

    a_pos

    a位置的碰撞盒的左上角位置,a的碰撞盒的尺寸if(!checkAABBOverlap(a_pos,

    a_size,

    精确碰撞检测--具体形状的碰撞检测if(a_collider->getType()

    &&

    physics::ColliderType::AABB){return

    true;}

    physics::ColliderType::CIRCLE){auto

    a_center

    physics::ColliderType::AABB){auto

    a_center

    checkPointInCircle(nearest_point,

    a_center,

    physics::ColliderType::CIRCLE){auto

    b_center

    checkPointInCircle(nearest_point,

    b_center,

    checkCollision函数采用两阶段检测

    • 粗略检测(AABB过滤)---

      如果AABB都不重叠的话那么就直接返回false,该方式可以过滤大部分不碰撞的情况,节省了昂贵的计算资源

    • ---

      最近点检测,找到AABB上离圆心最近的点,检查是否在圆内

      最邻近点可以通过clamp函数获取,在检查这个点是否在AABB内(glm::clamp(邻近点,AABB左上角,AABB右下角)

      id="4在physicsengine中集成碰撞检测">4.在PhysicsEngine中集成碰撞检测

      现在,PhysicsEngine不仅要更新物体位置,还要负责在更新后进行物体间的碰撞检测

      id="enginephysicsphysics_engineh新增">engine/physics/physics_engine.h(新增)

      private:std::vector<std::pair<engine::object::GameObject*,

      engine::object::GameObject*>>

      collision_pairs_;

      id="enginephysicsphysics_enginecpp新增">engine/physics/physics_engine.cpp(新增)

      每帧开始时清空上一帧的碰撞记录collision_pairs_.clear();//

      (auto*

      PhysicsEngine::checkObjectCollisions(){//

      --->

      obj_a->getComponent<engine::component::ColliderComponent>();if(!cc_a

      continue;

      obj_b->getComponent<engine::component::ColliderComponent>();if(!cc_b

      continue;

      检查碰撞if(collision::checkCollision(*cc_a,

      *cc_b))

      记录碰撞对collision_pairs_.emplace_back(std::make_pair(obj_a,

      obj_b));}}}

      collision_pairs_.clear(),每帧开始时清空上一帧的碰撞记录

      ---

      遍历所有PhysicsComponent,应用物理规则更新位置

      ---

      checkObjectCollisions(),执行碰撞检测

      id="checkobjectcollisions优化">checkObjectCollisions优化

      class="language-cpp">for(size_t

      <

      性能考虑:对于对象层物体不多的情况,O(n$^2$)暴力求解是可以接受的。

      class="language-cpp">collision_pairs_.emplace_back(obj_a,obj_b);

      如果collision::checkCollision返回true,就将这对发生碰撞的GameObject指针存入collision_pairs_

      我们在GameScene中创建两个物体:一个受重力影响的箱子(AABB碰撞体)和一个静止的箱子(圆形碰撞体),并给其加上ColliderComponent

      id="gamescenegame_scenecpp">game/scene/game_scene.cpp

      {std::unique_ptr<engine::object::GameObject>

      gameobj

      std::make_unique<engine::object::GameObject>("test1");//

      添加组件进行测试gameobj->addComponent<engine::component::TransformComponent>(glm::vec2(200.0f,100.0f));gameobj->addComponent<engine::component::SpriteComponent>("assets/textures/Props/big-crate.png",context_.getResourceManager(),engine::utils::Alignment::CENTER);gameobj->addComponent<engine::component::PhysicsComponent>(&context_.getPhysicsEngine(),1.0f);gameobj->addComponent<engine::component::ColliderComponent>(std::make_unique<engine::physics::AABBCollider>((glm::vec2(32))));addGameObject(std::move(gameobj));auto

      gameobj1

      std::make_unique<engine::object::GameObject>("test2");gameobj1->addComponent<engine::component::TransformComponent>(glm::vec2(200.0f,200.0f));gameobj1->addComponent<engine::component::SpriteComponent>("assets/textures/Props/big-crate.png",context_.getResourceManager(),engine::utils::Alignment::CENTER);gameobj1->addComponent<engine::component::PhysicsComponent>(&context_.getPhysicsEngine(),1.0f,false);gameobj1->addComponent<engine::component::ColliderComponent>(std::make_unique<engine::physics::AABBCollider>((glm::vec2(32))));addGameObject(std::move(gameobj1));

      }void

      {Scene::update(delta_time);TestCollisionPairs();

      每帧检查并打印碰撞对

      context_.getPhysicsEngine().getCollisionPairs()){spdlog::info("{}和{}发生碰撞",pair.first->getName(),pair.second->getName());}

      data-src="https://img2024.cnblogs.com/blog/2727651/202602/2727651-20260218211059417-1569890633.png"

      可以看到两个箱子发生了碰撞,这证明我们的碰撞检测系统已经成功运行了

      collision::checkCollision()(检测算法)

      ---调用--->

      PhysicsEngine::checkObjectCollisions()

      --->

    • 创建碰撞组件:ColliderComponent管理碰撞器
    • 集成到物理引擎PhysicsEngine统一管理碰撞检测
    • ,限定返回的引用是只读的,调用方不能通过这个引用修改force_;

      函数后的const,限定这个成员函数是只读的,函数内部不能修改类的任何非mutable成员,(force_不能改),这会让force_变成const属性。

      const成员函数中,类的成员变量(比如force_)会被编译器视为const类型

      force_的实际类型是const

      glm::vec2,这是后续所有写法是否合法的核心前提。

      //编译报错,返回是非const引用,相当于把const对象绑定到非const上,违法

      const

      //合法,返回的是值拷贝,把const的force_拷贝一份返回,类型匹配,调用方拿到的是拷贝,不会影响原force_

      glm::vec2

      //合法,将const对象拷贝到非const的对象是合法的,调用方也是无法修改原值的

      总结:函数后的const使函数内不能改成员,且force_变为const;返回glm::vec2&(非const引用)无法绑定const对象;去掉引用(返回值拷贝)会有拷贝开销;const

      glm::vec2&合法高效安全

      2.加深理解值传递和const引用两种参数传递方式的差异

      glm::vec2&是引用绑定,形参size直接绑定到传入的实参,不拷贝,不移动实参,只是"借用"实参的内存地址。

      成员初始化size_(size)拷贝构造,因为sizeconst引用,不能通过std::move转移其资源(const对象移动会破坏原对象的只读语义),所以只能把size指向的glm::vec2内容完整拷贝到成员变量size_中。

      (1次拷贝构造)

      size是值接收,调用构造函数时,实参会先拷贝/移动到局部形参size中,传入左值,形参size是拷贝构造;传入右值,移动构造,转移资源,几乎无开销;成员初始化:size_(std::move(size))移动构造,把局部形参size资源直接转移到size_中;通过

      减少拷贝开销,形参

      状态(但因为是局部变量,出了构造函数就销毁,无副作用)(左值:1次拷贝构造,1次移动构造;右值:2次移动构造(1次形参size移动临时对象,成员初始化时1次std::move()移动形参size))

      3.对于计算碰撞检测时对于Transform组件中scale的疑问

      这里我在自己编写的时候老是容易忘记这个细节部分,在碰撞器组件ColliderComponent中更新偏移的部分、Collision.cpp中checkCollision部分也是,这是个遗留的细节问题,当然也出现在SpriteComponent中的更新偏移部分,不然这样设想一下,比如我们加载一张图片,这张图片有点大,比如64×64px,我想要调整一下,那么就需要通过Transform进行调整,这个GameObject会使用到如下组件:

        那么这个图片原大小64×64px会存在SpriteComponent组件类中的成员变量sprite_size_=glm::vec2(64,64)中,我们建立的TransformComponent组件中scale默认都是(1.0,1.0);我想要调整,我想将图片缩小一半,那么我需要将scale设置成(0.5,0.5);但是调整后会牵扯到对齐方式,这是肯定的,如果原本是以中心对齐方式CENTER,那么SpriteComponent中的offset_就是offset_

        glm::vec2(-sprite_size_.x/2,-sprite_size_.y/2)

        scale

        (-32,-32);我们的SpriteComponent中的offset_偏移是始终和TransformComponent中的scale挂钩的,这得注意,如果图片缩小一半,会导致scale缩小一半,那么牵扯到的偏移也应该缩小一半变成(-16,-16)

        同样的,类比于碰撞组件ColliderComponent中的偏移offset_,这里的collider_size类似于sprite_size_原始图片的大小,也同样需要scale进行位移偏移计算。

        ColliderComponent::updateOffset()

        {if(!collider_)

        collider_->getAABBSize();if(collider_size.x

        <=

        transform_->getScale();switch(alignment_){case

        offset_

        utils::Alignment::CENTER_RIGHT:

        offset_

        utils::Alignment::BOTTOM_CENTER:

        offset_

        utils::Alignment::BOTTOM_RIGHT:

        offset_

        4.对于AABB和Circle,也就是矩形和圆之间的碰撞检测不太理解。

        这个点其实很简单,我们会计算圆心和矩形之间的最邻近点,只要这个点到圆心的距离小于圆的半径,那么就重叠了,发生碰撞。

        这个点可能在边上,可能在角上,也可能在内部,那如何计算呢?

        通过clamp钳制的方法将圆心这个点限制在AABB矩形区域。

        因为AABB是轴对齐,所以边都是平行于x/y轴的,那么对圆心坐标钳制后得到的点就是AABB上

        唯一、离圆心最近的点

        class="post-meta-container">



        SEO优化服务概述

        作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。

        百度官方合作伙伴 白帽SEO技术 数据驱动优化 效果长期稳定

        SEO优化核心服务

        网站技术SEO

        • 网站结构优化 - 提升网站爬虫可访问性
        • 页面速度优化 - 缩短加载时间,提高用户体验
        • 移动端适配 - 确保移动设备友好性
        • HTTPS安全协议 - 提升网站安全性与信任度
        • 结构化数据标记 - 增强搜索结果显示效果

        内容优化服务

        • 关键词研究与布局 - 精准定位目标关键词
        • 高质量内容创作 - 原创、专业、有价值的内容
        • Meta标签优化 - 提升点击率和相关性
        • 内容更新策略 - 保持网站内容新鲜度
        • 多媒体内容优化 - 图片、视频SEO优化

        外链建设策略

        • 高质量外链获取 - 权威网站链接建设
        • 品牌提及监控 - 追踪品牌在线曝光
        • 行业目录提交 - 提升网站基础权威
        • 社交媒体整合 - 增强内容传播力
        • 链接质量分析 - 避免低质量链接风险

        SEO服务方案对比

        服务项目 基础套餐 标准套餐 高级定制
        关键词优化数量 10-20个核心词 30-50个核心词+长尾词 80-150个全方位覆盖
        内容优化 基础页面优化 全站内容优化+每月5篇原创 个性化内容策略+每月15篇原创
        技术SEO 基本技术检查 全面技术优化+移动适配 深度技术重构+性能优化
        外链建设 每月5-10条 每月20-30条高质量外链 每月50+条多渠道外链
        数据报告 月度基础报告 双周详细报告+分析 每周深度报告+策略调整
        效果保障 3-6个月见效 2-4个月见效 1-3个月快速见效

        SEO优化实施流程

        我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:

        1

        网站诊断分析

        全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。

        2

        关键词策略制定

        基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。

        3

        技术优化实施

        解决网站技术问题,优化网站结构,提升页面速度和移动端体验。

        4

        内容优化建设

        创作高质量原创内容,优化现有页面,建立内容更新机制。

        5

        外链建设推广

        获取高质量外部链接,建立品牌在线影响力,提升网站权威度。

        6

        数据监控调整

        持续监控排名、流量和转化数据,根据效果调整优化策略。

        SEO优化常见问题

        SEO优化一般需要多长时间才能看到效果?
        SEO是一个渐进的过程,通常需要3-6个月才能看到明显效果。具体时间取决于网站现状、竞争程度和优化强度。我们的标准套餐一般在2-4个月内开始显现效果,高级定制方案可能在1-3个月内就能看到初步成果。
        你们使用白帽SEO技术还是黑帽技术?
        我们始终坚持使用白帽SEO技术,遵循搜索引擎的官方指南。我们的优化策略注重长期效果和可持续性,绝不使用任何可能导致网站被惩罚的违规手段。作为百度官方合作伙伴,我们承诺提供安全、合规的SEO服务。
        SEO优化后效果能持续多久?
        通过我们的白帽SEO策略获得的排名和流量具有长期稳定性。一旦网站达到理想排名,只需适当的维护和更新,效果可以持续数年。我们提供优化后维护服务,确保您的网站长期保持竞争优势。
        你们提供SEO优化效果保障吗?
        我们提供基于数据的SEO效果承诺。根据服务套餐不同,我们承诺在约定时间内将核心关键词优化到指定排名位置,或实现约定的自然流量增长目标。所有承诺都会在服务合同中明确约定,并提供详细的KPI衡量标准。

        SEO优化效果数据

        基于我们服务的客户数据统计,平均优化效果如下:

        +85%
        自然搜索流量提升
        +120%
        关键词排名数量
        +60%
        网站转化率提升
        3-6月
        平均见效周期

        行业案例 - 制造业

        • 优化前:日均自然流量120,核心词无排名
        • 优化6个月后:日均自然流量950,15个核心词首页排名
        • 效果提升:流量增长692%,询盘量增加320%

        行业案例 - 电商

        • 优化前:月均自然订单50单,转化率1.2%
        • 优化4个月后:月均自然订单210单,转化率2.8%
        • 效果提升:订单增长320%,转化率提升133%

        行业案例 - 教育

        • 优化前:月均咨询量35个,主要依赖付费广告
        • 优化5个月后:月均咨询量180个,自然流量占比65%
        • 效果提升:咨询量增长414%,营销成本降低57%

        为什么选择我们的SEO服务

        专业团队

        • 10年以上SEO经验专家带队
        • 百度、Google认证工程师
        • 内容创作、技术开发、数据分析多领域团队
        • 持续培训保持技术领先

        数据驱动

        • 自主研发SEO分析工具
        • 实时排名监控系统
        • 竞争对手深度分析
        • 效果可视化报告

        透明合作

        • 清晰的服务内容和价格
        • 定期进展汇报和沟通
        • 效果数据实时可查
        • 灵活的合同条款

        我们的SEO服务理念

        我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。

        提交需求或反馈

        Demand feedback