一个基于组合模式的游戏地图系统

Cocos2d-x 4.0实战:复刻经典泡泡堂游戏,详解2D游戏核心模块开发 游戏开发的核心在于理解其底层逻辑与架构。从基础的游戏循环与状态机原理出发,开发者可以构建出流畅的游戏体验。在2D游戏开发中,碰撞检测、对象池和渲染优化是提升性能的关键技术。碰撞检测确保游戏世界的物理交互真实可信,而对象池技术则通过复用对象来避免频繁的内存分配与回收,显著优化性能。这些技术共同支撑起丰富的游戏玩法,例如在经典炸弹人玩法中,它们被用于实现角色移动、炸弹爆炸与道具系统。本文以Cocos2d-x 4.0引擎为例,通过复刻经典泡泡堂游戏,详细拆解了包括地图系统、AI寻路、事件驱动在内的完整实现方案,为 阅读详情

-潘宏

-2012年12月

-本人水平有限,疏忽错误在所难免,还请各位高手不吝赐教

-email: popyy@netease.com

-weibo.com/panhong101


地图系统

地图系统是游戏开发永恒不变的一个主题。在大多数游戏开发中,我们都需要和地图打交道。不同的游戏可能采用不同的地图系统,比如对于2D游戏来说,可能的地图类型包括:

1)Rectangular tile,即矩形tile。

2)Isometric,即等测地图。

3)Hexagonal tile,即六边形tile。


等等。




而对于3D游戏来说,一般包括两种主要类型:


1)基于3D空间的2D地图

2)完全3D空间地图


对于第一种类型,实际上是2D地图系统的一种3D推广,游戏中的地图还是在一个2D平面上,但是在3D空间的一个平面上。场景中的游戏对象可以都是3D模型。但地图本身仍然通过2D地图的方式进行处理。


第二种一般在3D图形学中叫做场景管理(Scene Management)。这是对真3D场景的一种处理方式:地图信息不再处于某个平面上,而是具有任意的3D几何信息。对于处理这种非规则的3D几何地图系统,我们一般采用分类的方式进行单独处理,比如:


1)室外地形系统

2)室内地图系统

3)基于portal的系统


等等。针对不同的类型,3D场景系统一般采用不同的管理方法,比如quadtree、octree、bsp、portal等等场景管理方式。可以说这个领域很广泛、也很复杂。

我们当然不可能具体地讨论所有这些地图系统。那么我们讨论什么呢?我们将讨论一种思想,这种思想贯穿于所有的这些地图管理方法之中,以提供一种健壮、合理、便利的代码结构。而这种结构不论是在游戏产品还是在开发工具中,都扮演着举足轻重的作用。这就是层次体结构。



层次体结构


对于复杂的问题以及结构,我们都倾向于一种称为“分治法”的方式进行处理。层次体结构实际上就是一种分治法,它通过一种树形结构来表示“整体-部分”的层次概念。基于这种方法,开发者可以很容易地对系统进行不同等级的灵活控制,同时获得一种复用性优势。


我们来举一个简单例子,来让大家更好地理解这些抽象概念。对于最简单的2D矩形tile引擎来说,开发者们经常会把场景分成多个层(layer)和一个根(root),如下图所示:



这就是一个最简单的层次体结构。它表明了一种整体和局部的从属关系:root可以看作这个地图本身,它代表整体。而它的子结点,则看作是这个地图的每个层,他们代表局部,属于整体。我们再具体一点,假设我们把地图分成了3层:


Layer 1 - 地面层

Layer 2 - 中间层

Layer 3 - 天空层


地面层是永远处于”最下面“的层,地图上的任何东西都会处于它的上面,这一层包括普通土地、草坪、沙土地、公路等类型的tile。中间层就是地图上的对象层,它永远处于地面层之上,这一层包括:房子、树木、玩家角色、NPC等活动对象,这些对象之间的位置关系会随时变化,因此互相遮挡的关系也会变化,需要实时进行排序。天空层包括天上飞的鸟、飘浮的云朵等对象,它们永远处于地面层之上。


更进一步地,我们可以在每个layer上再增加子layer——这可以根据具体游戏对象的类型,比如把所有沙土地对象,都放到一个layer上,当玩家走到上面的时候,会减慢速度。如下图所示:




如我们所看到的,对这些对象进行3个layer分类,我们获得了很多好处:


1)分区渲染-渲染的顺序可以通过layer自然的处理:地面、中间、天空,这样的顺序保证了渲染结果的可视关系的正确。

2)分区更新-只有中间层的对象需要实时排序,这避免了对无需排序对象进行排序的无效计算。另外,可以直接用沙土层和玩家做碰撞检测——避免了不必要的计算。

3)总体控制-在对地图进行编辑的时候,我们可以非常方便地显示、隐藏、移动、删除不同的层。被操作的每个层上的对象都得到统一的处理。


而这些好处也不仅仅局限于矩形2D tile地图,任何地图系统都可以从中得到这样的好处。比如在3D的场景管理中,quadtree、octree、bsp本身就是一种层次体结构。它们通过树形结构对场景进行划分,从而以一定的规则将场景中的多边形安排到树中。另外,对于3D的所谓保留模式(Retained Mode)渲染,实际上就是通过把场景安排成一颗场景树来进行处理。系统一般会提供一个类似这样的接口:


void GraphicsEngine::render( SceneNode& sceneTreeRoot );


sceneTreeRoot就是场景树的根结点,从该结点向下就可以遍历整个树形结构,并进行任何你希望的操作——这当然以渲染为主。


在一些支持保留模式渲染的引擎中,一般设计师或美工会通过一些所见即所得的工具进行场景编辑,放置模型,虚拟物体,架设相机等等。最后导出一个文件,供引擎使用。而导出的往往就是一颗场景树,连相机都会作为一个结点存在于该结构中。


复用性


层次体结构的另一个巨大优势在于复用性,而这往往体现在设计和实现两个层面上。想象我们在地图里面将几块石头摆放成了一种特殊形状,这种形状暗示了某种游戏中的宗教意义。而根据设计需求,该形状可能会摆在地图中的很多位置。由于整个地图通过组合模式被建立成了一棵场景树,我们则可以把这个形状的几个石头,单独的做成一个子layer。然后在不同的地方(结点)放置这些子layer。而在代码级别上,这些layer中的石头实际上是通过类对象指针保存的,因此存放开销完全可以接受。所以,我们每次给一个结点增加一个这样的layer,就添加了这些石头所组成的一个形状——我们实际上是通过一种组合的方式进行特定结构的复用。请注意,这些复用是可以嵌套的!这意味着你可以用这些子layer再组合更复杂的层,然后服用这些更复杂的layer。这种复用带来的威力是巨大的,在两方面提供优势:


1)设计开销 -通过定义一个子layer,我们可以反复使用该layer,还可以嵌套!

2)内存开销 -只通过指针存储对象,实际对象内存只有一份。




这种复用性带来的利益驱使我们开发了一套2D动画系统——用场景树的方式组织动画。允许对不同复杂组件(可以看作这里的layer)的嵌套。以后如果条件允许,我会写一篇关于该系统的文章,帮助一下初学游戏开发的朋友理解2D动画系统。




层次体的简单实现


层次体结构实际上是一种组合(Composite)模式。根据GoF的著作《设计模式》所描述:组合模式通过一种树形结构来体现一种“整体和部分”的观念,从而让处理单一对象和对象聚合存在一种统一的形式。下图所示即组合模式:




Leaf是单一对象,composite是组合对象,也就是一个对象聚合体。它们都继承自component类,拥有相同的操作方式Operation——这是关键,也是组合模式的核心思想:在客户(client)看来,操作一个leaf和一个composite没什么区别,都调用它的Operation,但composite是个聚合体,它会在自己的Operation中调用每一个聚合对象的Operation。


这里单一对象就可以理解为地图中的一个具体对象(树木、房子、NPC等等),而组合对象则可以看成是地图的一个layer——它聚合其它对象(树木、房子、NPC,或者是另一个layer)。


下面我们实现一个简单的层次体结构,从代码级别来深入认识该系统:

    class MapNode  
    {  
    public:  
        virtual ~MapNode() {}  
      
        virtual void cycle() = 0;  
        virtual void draw( GraphicsContext& g ) = 0;  
    };  
      
    class Node_Layer : public MapNode  
    {  
    public:  
      
        void addChild( SceneNode* child )  
        {  
            m_children.push_back( child );  
        }  
      
        void removeChild( SceneNode* child )  
        {  
            for( std::vector< SceneNode* >::iterator it = m_children.begin();  
                it != m_children.end(); ++it )  
            {  
                if( *it == child )  
                {  
                    m_children.erase( it );  
                    break;  
                }  
            }  
        }  
      
        virtual void cycle()  
        {  
            for( int i = 0; i < m_children.size(); ++i )  
            {  
                m_children[i]->cycle();  
            }  
        }  
      
        virtual void draw( GraphicsContext& g )  
        {  
            for( int i = 0; i < m_children.size(); ++i )  
            {  
                m_children[i]->draw( g );  
            }  
        }  
      
      
    protected:  
        std::vector< SceneNode* > m_children;  
    };  
      
    class Node_Tree : public MapNode  
    {  
    public:  
      
        virtual void cycle()  
        {  
            Update the state of the tree...  
        }  
      
        virtual void draw( GraphicsContext& g )  
        {  
            Draw the tree via g...  
        }  
    };  


以上是一个非常简单的组合代码结构。 MapNode是地图结点基类,我们用它的指针或引用来操作整个系统。它提供两个抽象方法

void MapNode::cycle
void MapNode::draw

分别用来进行帧更新和渲染,具体实现由子类决定。Node_Layer就是地图层类,它就是所谓的聚合体。Node_Tree是一个单一对象,它表示地图上的树这种对象。可以看到它们对具体操作的实现清晰地表达了整体-部分的思路:Node_Layer把操作分散到各个子对象中,而Node_Tree则是老老实实作自己的事情。这便是一个最简单的层次体结构实现。一个简单的游戏和可能会如此使用上述代码:


    class Node_Root : public Node_Layer {};  
      
    class Node_Player : public MapNode  
    {  
    public:  
      
        virtual void cycle()  
        {  
            Update the state of the player...  
        }  
      
        virtual void draw( GraphicsContext& g )  
        {  
            Draw the player via g...  
        }  
    };  
      
    Node_Root root;  
    Node_Player player;  
    Node_Tree tree;  
      
    root.addChild( &player );  
    root.addChild( &tree );  
      
    for(;;)  
    {  
        root.cycle();  
        root.draw( g );  
    }  

我们建立了一个root类作为世界的根结点。然后生成了一个玩家和一棵树,都放进了场景里,接着进入了我们的游戏循环。还有比这更简单的么?


以该结构作为一个开始,开发者可以进行扩展。包括加入MapNode的共性成员:


位置

可见性标志


等等。对于非聚合类型的MapNode子类的设计,那就和你的游戏相关了。比如对于Node_Player来说,可以增加移动控制、生命、动画等等。这里提供的只是一种设计上的思路,而经过开发者的细节设计和扩展,该系统将发挥实际功效。


总结

上面我们介绍了层次体概念以及该结构的简单实现。它是一种优秀的地图系统、场景管理方法。不论是在2D还是3D中,都可以发挥巨大的威力。不论对于游戏开发初学者还是专家,在实际的游戏代码中你都会看到它的影子。因此,独立地考察和分析该系统对于开发者来说都是有很必要的。

原文地址:http://blog.youkuaiyun.com/popy007/article/details/8301133

Unity主程进阶:2个月系统构建架构、性能与工程化核心能力 在游戏开发领域,技术架构是支撑大型项目的骨架,它决定了系统的可维护性、扩展性和团队协作效率。其核心原理在于通过合理的模块划分、设计模式应用和通信机制,降低系统复杂度与耦合度。掌握宏观架构能力,对于提升项目长期健康度、应对技术债务具有关键价值,尤其在Unity游戏开发中,这直接关系到资源管理、热更新策略和团队工作流的顺畅运行。性能优化则是保障游戏体验的基石,涉及从CPU端的GC管理与算法效率,到GPU端的渲染管线与Draw Call优化全链路。本文将围绕Unity主程的核心职责,系统阐述如何通过架构设计、性能 阅读详情

相关推荐

电子地图管理系统(完全版)

电子地图管理系统 主目录: 1、打开 2、排序 3、检索 4、更新 5、退出

推导正交投影变换

-潘宏-2009.4.20-本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教-email: popyy@netease.com 之前我们在《深入探索透视投影变换》以及《深入探索透视投影变换(续)》中研究了OpenGL、D3D以及M3G的透视投影变换的原理以及生成方法。这些方法在当前的主流图形API中得到了普遍使用。但关于投影应用,还有一类经常使用的投

Popy007(Twinsen)的专栏 2万+

手把手教你用Synopsys AHB VIP搭建验证环境:从SINGLE到WRAP16的完整波形分析与避坑指南

本文详细介绍了如何使用Synopsys AHB VIP搭建验证环境,从基础配置到复杂波形调试实战。重点解析了AHB协议中各种Burst类型的地址计算机制,包括INCR和WRAP类型,并提供了实际案例和避坑指南,帮助工程师快速掌握验证技巧。

weixin_42552716的博客 414

Java设计模式之从[魔兽世界包裹系统]分析组合(Composite)模式

RPG游戏中的包裹(或者称为背包)是玩家携带物品的地方,它的大小决定着玩家能够携带物品数量。如在魔兽世界中,玩家起初的物品栏(将物品栏视为玩家的唯一一个包裹)的格子很少,但是玩家可以将新的包裹放在物品栏中,达到扩充物品栏的效果。也就是说,物品栏可以放消耗品、武器等零散的物品,当然也可以放包裹。   假定魔兽世界有如下设定:玩家一开始拥有一个默认的包裹(物品栏),玩家可以获得新的包裹放在物品栏上。

于益偲 2757

STM32单片机远程升级

stm32远程升级

fang_yang_wa的博客 1万+

视频预处理--经典方法卷积3D

在三维卷积操作中,卷积核不仅在空间维度上滑动,还在时间维度上滑动,从而同时捕捉时间和空间上的特征。通过合理设置步长和填充,可以灵活控制输出特征图的大小和特征提取的效果。你的理解非常准确:三维卷积核就像是一个长度为 3 的滑动窗口,每次选取 3 个连续的帧进行卷积操作,而步长和填充则进一步优化了这一过程。

m0_73359068的博客 1649

从零开始入门创作游戏——2D沙盘类随机地图的生成

如果零基础(例如我)想使用unity引擎做类似于泰拉瑞亚的2d沙盘游戏,首先需要生成随机的地图。

dwe147的博客 4907

ArcGISPro小白必看:5分钟搞定3D地形图制作(附免费数据源)

本文为ArcGISPro初学者提供5步制作专业3D地形图的完整指南,涵盖免费数据获取、项目初始化、数据预处理、3D场景构建和成果输出等关键步骤。特别推荐使用NASA的SRTM高程数据和吉林一号卫星影像,帮助用户快速掌握3D地形图制作技巧,适用于教学演示和科研分析。

weixin_28314575的博客 239

QT、C++实现地图导航系统(mapSystem)

地图导航系统,解析osm.xml数据,Floyd求最短路径,可免费下载资源文件

m0_63743577的博客 1万+

ABAP Secure Storage 在事务码 SM59 中的应用

系统管理人员在进行维护时,应关注相关日志信息,及时发现可能出现的安全异常,并针对不同安全等级的操作制定相应的备份与恢复策略,以降低潜在风险。该区域在设计上具备高度隔离性,仅允许经过授权的组件访问。保存后,系统会将密码存储在 Secure Storage 中,这种处理方式充分体现了 SAP 标准程序在安全设计上的考量。对于系统管理员而言,这种机制在日常维护与审计中提供了有力的支持,可以通过比对存储数据的哈希值或其他完整性校验手段,及时发现异常变动,保障系统长期稳定运行。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 670

2024阅读AOSP源码的正确打开姿势

在Android系统开发中,阅读AOSP(Android Open Source Project)源码是非常重要的环节。然而,如何构建一个优雅的阅读环境却是一个不容忽视的问题。本文将介绍不同工具和方法下阅读AOSP源码的正确姿势,并对比其优缺点。

虎哥LoveDroid 2706

设计模式每日硬核训练 Day 15:享元模式(Flyweight Pattern)完整讲解与实战应用

我们在文本渲染模块中使用了享元模式来复用字符对象,字符本身作为内部状态共享,坐标作为外部状态传入。通过 GlyphFactory 管理共享对象池,节省了内存占用并提升渲染性能,特别适合大量字符的 UI 场景。我们模拟一个文本渲染系统,文字中的每个字符都是一个对象,但字符本身可共享,坐标位置不可共享。在系统中,如果存在大量“内容相同或相似”的对象,重复创建将造成资源浪费。如果这些对象的“大部分状态相同”,我们就可以将它们。而今天的主角“享元模式”,是极致优化资源的代表。

Interview_TC的博客 1046

uniapp - 鸿蒙真机运行报错hvigor ERROR: Failed :entry:default@CompileArkTS...,hvigor ERROR: default@CompileAr

uniapp鸿蒙报错> hvigor ERROR: Failed :entry:default@CompileArkTS... hvigor ERROR: default@CompileArkTS watch work[0] failed. 【HarmonyOS】工程编译后报错hvigor ERROR: Failed :entry:default@CompileArkTS,uniAPP鸿蒙开发无法编译运行启动报错,工程编译后报错,运行不起来,删除掉项目entry下的build和.preview缓存文件后重新

🏆 前端领域优质创作者 4790

如何在Godot 4.5中快速构建完整的回合制RPG游戏:开源项目实战指南

你是否梦想着创建自己的角色扮演游戏,却被复杂的战斗系统和对话设计难住了?Godot Open RPG开源项目正是为你量身打造的终极解决方案!这个基于Godot 4.5引擎的开源RPG项目展示了如何构建包含完整回合制战斗系统、丰富对话系统和网格化地图探索的经典RPG游戏。 ## 🚀 为什么选择这个开源RPG项目? **Godot Open RPG**不仅仅是一个代码库,更是一个精心设计的教学示

gitblog_00170的博客 828

RK3568平台开发系列讲解:内核启动流程

第 493 行的 ENTRY 指明了了 Linux 内核入口,入口为stext,stext 定义在文件arch/arm/kernel/head.S 中 , 因此要分析Linux 内核的启动流程,就得先从文件arch/arm/kernel/head.S 的 stext 处开始分析。_mmap_switched 定义在文件 arch/arm/kernel/head-common.S,__mmap_switched 最终会调用 start_kernel 函数。⑥、r2=atags 或者设备树(dtb)首地址。

内核笔记 217

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

一口气学会发布自己的地图查询系统

进入首页,重点关注左侧数据模块的四个菜单。这块主要用于查看自己发布的地图服务信息,这块的地图浏览主要基于openlayers引擎实现。

WSYYCCY的博客 2813

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

游戏开发设计模式 —— 组合模式

在游戏开发过程中,通过一套完整功能的设计模板,来解决一些常见的问题组合模式,又叫部分整体-模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分和整体.组合模式作为一种基本的设计模式,在很多方面都会有所使用它最大的好处就是对代码进行了解耦,让脚本模块化,并且当游戏物体的创建多起来的时候,组合模式能很好的代替原本的子类继承父类的做法。

sercic的博客 546

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

深入探索透视投影变换

深入探索透视投影变换-Twinsen编写-本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教-email: popyy@netease.com透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和

Popy007(Twinsen)的专栏 11万+

2D随机地图的生成

ps:记得当初大三上学期时候,曾经被问过一次,steam上一款地图如何生成,当时对这些东西不太了解,卒。这次一起补回来。。 以下很多实现均为猜测!!只是个人实现的方式 以几款游戏为例 •1. steam一款策略类游戏 •2.元气骑士 •3.火炬之光2与暗黑破坏神2   1.Kingdoms and castles  大体是一个随机的格子形地图,可以上面策略经营,并且有塔防元素。 ...

GameRoad 4万+

什么是图形加速卡(一)

原文:http://www.azillionmonkeys.com/qed/accelerator.html 作者:Paul Hsieh -潘宏 译 -2013年1月 -email: popyy@netease.com -weibo.com/panhong101 (译注:本文写于2000年左右,很多内容稍显过时。但作为理解GPU发展的历史性、技术性材料,

Popy007(Twinsen)的专栏 1万+

开放世界游戏中的大地图的实现——内容制作篇

二、内容制作篇:设计和创造(Content Design & Creation)聊完了程序方面的内容,我们来简单讲讲超大规模世界在设计和制作方面的一些情况。这方面因为我不是专家,只是做一下简单的介绍,不足之处,还请专业人士指正。1. 随机地图类游戏 (Diabloz II) 中地图的拼接在暗黑二,暗黑三和类似的游戏“火炬之光”等游戏中,通过巧妙的拼接,理论上可以通过组合,生成近乎无限大的地图。这是暗黑三第二章里所有地图的可能的部件形状: 这是拼接之后的样子: 除了拓扑结构..

august5291的博客 3015

Unity 组合模式(实例详解)

在Unity中,组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表现“整体-部分”的层次结构,并且用户可以一致地处理单个对象和组合对象。以上每个示例都展示了如何使用组合模式来表示一个树形结构,其中抽象基类定义了对组件进行添加、移除以及执行通用操作的方法,而叶子节点和组合节点分别实现这些方法以适应各自的具体功能。这种设计模式在游戏开发中非常有用,比如构建角色技能树系统,玩家可以根据自己的策略自由组合不同的技能来形成独特的连招或战术。

qqrrjj2011的博客 2073

什么是图形加速卡(四)

原文:http://www.azillionmonkeys.com/qed/accelerator.html作者:Paul Hsieh-潘宏 译-2013年2月-email: popyy@netease.com-weibo.com/panhong101(译注:本文写于2000年左右,很多内容稍显过时。但作为理解GPU发展的历史性、技术性材料,本文真是不可多得)显示器刷新最后一个瓶颈,是关于显示器刷

Popy007(Twinsen)的专栏 6455

地图坐标系统(各种坐标系详解)

互联网电子地图坐标系详解

倚栏听风 6879
上一篇: 一个基于observer模式的游戏事件分发系统
下一篇: 一个多态性的游戏状态机系统
cbbbc
博客等级 码龄15年 609粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值