基于C++和SDL的2D双人塔防游戏的开发与实现

基于C++和SDL的2D双人塔防游戏的开发与实现
WMY-WX基于C++和SDL的2D双人塔防游戏的开发与实现
摘要:
本课题旨在探索以C++和SDL为核心技术框架,开发一款支持本地双人协作的2D塔防游戏,具有重要的理论与实践意义。项目基于C++编程语言和SDL库,重点实现了以下功能模块:基于瓦片地图的分层渲染系统、防御塔动态部署与升级机制、基于洋流图算法的动态路径规划模型,以及双玩家实时资源协同分配策略。最主要的工作涵盖了图形渲染优化、游戏逻辑与交互设计、以及音效与界面集成,确保了游戏的流畅性和趣味性。在研究过程中,我们得出重要结论:采用模块化设计思想和面向对象编程技术,能有效提高游戏开发的效率与质量;同时,双人合作模式通过任务分工,显著提升了游戏的策略深度与玩家互动性。本设计独到之处在于创新性地融合了双人协作元素与塔防玩法,为塔防类游戏带来了新的体验。从理论和技术层面看,本研究不仅验证了C++与SDL在游戏开发中的跨平台优势,更探索出基于C++11特性的高效游戏框架构建方法,为同类项目的开发提供了可复用的技术方案。
关键词:C++;SDL;塔防游戏;游戏开发与实现
Development and Implementation of 2D Double - Player Tower Defense Game Based on C++ and SDL
Abstract:
This topic aims to explore the core technical framework of C++and SDL, and develop a 2D tower defense game that supports local two person collaboration, which has important theoretical and practical significance. Based on C++programming language and SDL library, the project focuses on the realization of the following functional modules: tile map based layered rendering system, dynamic deployment and upgrade mechanism of defense tower, dynamic path planning model based on current graph algorithm, and real-time resource collaborative allocation strategy of two players. The most important work covers graphic rendering optimization, game logic and interaction design, as well as sound effects and interface integration, ensuring the smoothness and fun of the game. In the process of research, we draw important conclusions: using modular design ideas and object-oriented programming technology can effectively improve the efficiency and quality of game development; At the same time, the two person cooperation mode significantly improves the game’s strategic depth and player interaction through task division. The unique feature of this design is that it innovatively integrates the elements of two person cooperation and tower defense play, bringing new experience to tower defense games. In terms of theory and technology, this study not only verified the cross platform advantages of C++and SDL in game development, but also explored an efficient game framework construction method based on C++11 features, providing a reusable technical solution for the development of similar projects.
Key words: C++; SDL; Tower Defense Game; Game Development and Design
目录
1绪论**
基于C++和SDL的2D双人塔防游戏的开发与实现
1绪论
1.1研究背景
根据第55次《中国互联网络发展状况统计报告》显示,截至2024年12月,我国网民规模达11.08亿人,互联网普及率提升至78.6%,其中农村网民规模突破3.13亿人,占网民总量的28.2%。在基础设施层面,IPv6地址数量达69148块/32,5G基站总数突破419.1万个,为数字经济发展构建起全球最大的网络基础设施体系[1]。游戏产业作为数字经济重要组成部分,2024年用户规模达6.74亿人,移动游戏收入占比73.01%,PC端游戏市场同比增长4%,形成多端协同发展格局。
游戏用户规模的增长使得全球电脑游戏市场持续增长,为塔防游戏提供了广阔的发展空间。根据市场调研公司Newzoo的数据报告2023年全球玩家将达30亿。根据共研产业研究院的数据,2023年全球电脑游戏市场的收入约为802.7亿美元,预计到2032年市场规模将达到2135.6亿美元[2]。尽管主机和手机游戏类型不断增长,但电脑游戏市场仍然保持着强劲的增长势头。
在当前游戏市场上,塔防游戏作为休闲策略类游戏的重要分支,2023年全球市场规模达120亿元人民币,预计2025年突破150亿[3]。其发展呈现三大趋势:一是玩法融合加速,38%头部产品引入RPG元素;二是技术驱动体验升级,AR/VR技术渗透率达10%;三是社交功能强化,多人协作模式用户留存率提升15%。
在当前流行的传统塔防游戏市场上,游戏的核心玩法较为固定,大多数依然是以单一的玩家防守为基础。本次开发的2D双人塔防小游戏则对传统塔防游戏进行了进一步创新,针对传统塔防游戏单机体验的局限性,创新性引入实时协作机制。通过SDL库实现跨平台支持,结合C++11特性优化内存管理效率,在保证运行流畅的同时,构建动态攻防平衡模型,为休闲游戏社交化提供新选择。同时,2D的像素风画面,简单有趣的操作,更能带给玩家新奇的体验。
1.2研究现状
1.2.1国内外塔防游戏发展现状
塔防是炮塔防御(Tower Defence)的简称,是以炮塔为核心,地图为舞台,在敌人从地图的起点移动至终点的过程中让玩家操纵炮塔攻击敌人,以阻止敌人到达终点的一种休闲益智类游戏[4]。该类型凭借策略深度与休闲娱乐的平衡性,在全球游戏市场形成了稳定受众群体。本节将从国内外发展路径、差异化特征及用户吸引力维度展开系统分析。
(1)国外发展现状
国外塔防游戏市场已形成成熟的产业链条。例如:以“PopCap Games”开发《植物大战僵尸》为代表的经典作品,开创了”防御设施拟人化+多线作战”的创新模式,通过植物特性组合与僵尸进攻路径的博弈设计,将策略深度融入休闲玩法。而“Ironhide Game Studio”研发的《王国保卫战》系列则通过”英雄单位+技能树”的复合系统,构建了RPG化的成长体系,其防御塔升级路线与地形互动机制提升了战术维度。还有“Ninja Kiwi”开发的《气球塔防6》,注重市场推广和玩家互动,通过发布更新、提供互动体验、创意工坊等方式,吸引更多玩家的关注和参与。这些做法使得这些游戏在市场上保持了较高的竞争力。
(2)国内发展现状
国内塔防游戏,本土化创新成为突破市场的关键。国内塔防游戏在丰富的文化元素与题材融合、创新与策略性并重、社交与竞技性融合、精美的画面与音效以及本土化的运营与推广等方面都形成了独特的优势。以《保卫萝卜》系列为代表,采用萌系画风,适合各年龄段的玩家,将单局时长压缩至3-5分钟,精准契合移动端用户需求,验证了”轻量化操作”的可行性。这些优势使得国内塔防游戏在市场上更具竞争力,也会吸引越来越多的玩家关注和喜爱。
总的来说,无论国内还是国外,塔防游戏作为一个典型的人机对战游戏,都是玩家作为防守方拥有一定的资源,消耗资源在系统预设的位置建造、升级或者拆除防御塔,通过防御塔来阻击分批次按照规划好的路径进入游戏场景的敌人。玩家需要快速判断场上的局势,合理地利用有限的资源消灭敌人,保护保卫目标[5]。
1.2.2游戏开发技术现状
当前,基于C++和SDL的游戏开发已经成为2D游戏开发领域的一个重要方向。SDL作为一个跨平台的多媒体开发库,支持Windows、Linux、macOS等多种操作系统,提供了丰富的API接口,使得开发者能够轻松创建和运行2D游戏。同时,C++作为一种高效的编程语言,为游戏开发提供了强大的性能和灵活性。
(1)C++的应用
C++作为游戏开发语言的常客,许多大型游戏中都有他的身影,许多大型游戏公司和引擎使用都使用C++,例如国外的《英雄联盟》和《魔兽世界》,国内的《王者荣耀》、《阴阳师》和《绝地求生》等都广泛的使用C++进行构建。在游戏开发中,C++能够直接与硬件交互,优化性能,处理复杂的计算和实时渲染。同时,C++提供了对内存的精细控制,开发者可以手动管理内存分配和释放,提高资源利用效率,尤其在大型项目中至关重要。并且,C++有着丰富的库和框架,有很多强大的游戏开发库和引擎(如Unreal Engine、SDL、SFML等),可以加快开发进程。最后,C++支持多种操作系统,可以方便地移植游戏到不同的平台,增加潜在的用户群体。
(2)SDL的应用
SDL是许多独立游戏和小型项目的热门选择,尤其是在2D游戏开发中。例如游戏《破碎大陆》、《小小勇者》、《像素大冒险》和《文明:权利的召唤》等,都使用了SDL进行图形和音频处理。因为SDL不仅拥有丰富的社区资源,具有跨平台支持、简单易用的特点,而且还能够进行高效的2D图形处理和音频支持,最重要的是他完全开源免费,大大减轻了独立开发者和小型工作室的开发负担。
随着科技的飞速发展和市场竞争的日益激烈,塔防游戏面临着前所未有的变革压力。为了应对这些挑战,需要制定并实施新战略,通过引入先进的技术、优化游戏加强研发创新等多方面的举措,实现游戏质量的跨越式提升,为塔防游戏的可持续发展注入强大动力。
而在本次开发中使用的C++和SDL的组合就是个人开发制作塔防游戏的最佳选择之一,C++和SDL多媒体库的结合可以充分地发挥两者的优势,不仅能实现高效的游戏逻辑处理和流畅的图形渲染,还可以进一步地简化游戏开发的流程。同时,个人游戏开发者可以在开发过程中,更清楚地了解游戏引擎整体的运作机制和更底层的程序设计思想。
1.3研究意义
1.3.1对用户的意义
本项目所开发的2D双人塔防游戏,是一个休闲策略塔防类游戏,玩家通过这个游戏不仅可以和朋友一起放松心情,还能够培养玩家逻辑能力,锻炼玩家的思维能力和团队协作能力。
1.3.2对于技术推广的意义
本项目所开发的2D双人塔防游戏验证了C++和SDL在轻量级游戏开发中的技术适配性,在现实轻量级开发过程中C++和SDL是完全值得推广的。SDL库的跨平台特性(支持Windows、Linux、macOS)与模块化架构,显著降低了多端部署的复杂度。
例如,通过SDL_Renderer的硬件加速功能,能够实现1080P分辨率下游戏60帧的渲染稳定性能;而C++11的指针与STL容器则是优化了内存的管理效率,能够避免游戏运行中的资源泄漏问题。此外,本项目中所采用的“分层渲染+瓦片地图”方案(详见5.3.1节),为同类2D游戏的地图系统设计提供了可复用的技术模板。
1.3.3对于个人技术的意义
在开发过程中,本人系统掌握了游戏引擎底层架构的设计方法。例如,通过可继承单例模板类(6.2.1节)实现全局资源管理器的动态扩展,解决了多模块间的数据耦合问题;利用FFmpeg与SDL的协同解码机制(5.2.1节),攻克了视频流播放中的音画同步难题。
此外,项目实践深化了对面向对象编程原则的理解:通过封装Enemy、Bullet、Tower等实体类(5.3.4节),构建高内聚低耦合的代码结构;采用状态机模式管理游戏流程(5.1.3节),增强了系统的可维护性。这些经验为个人后续复杂项目的开发奠定了技术基础,同时培养了个人程序开发过程中需求分析、性能调优与跨平台调试的综合能力。
1.4论文结构安排
本文的主要内容一共分为七章,具体的章节内容组织如下:
第一章绪论,本章阐述了本项目的研究背景、现状及意义。通过分析中国互联网基础设施发展现状与塔防游戏市场趋势,阐明本课题的研究背景。同时,结合国内外研究现状对比,论证双人协作模式在塔防类游戏中的创新性,并明确本文的研究目标与技术路线。最后通过研究意义的总结,阐明了本课题的理论价值和实际价值。
第二章关键技术介绍,本章重点剖析C++语言在游戏开发中的性能优势与SDL库的跨平台特性,论证C++和SDL在轻量化开发中的适用性。同时介绍了本项目开发过程中所用到的硬件和软件环境。
第三章游戏概要设计,本章对游戏整体架构进行了设计,明确游戏的基本玩法、功能模块、数据结构及交互逻辑。同时,分析游戏的主要流程,包括关卡数据加载、玩家操作逻辑、敌人生成与路径规划等核心功能的实现方式。
第四章游戏策划与设计细节,本章详细介绍了游戏的策划方案,包括故事背景、核心玩法、金币系统、关卡设计、场景设计及角色设定等内容,为游戏的具体实现提供方案。
第五章游戏实现,本章基于C++和SDL库、FFmpeg库,具体介绍了游戏的实现过程。内容涵盖窗口管理、资源加载、场景切换、角色控制、战斗逻辑、音视频处理等核心技术的具体应用与实现效果。
第六章游戏测试,本章对游戏的基本功能、用户体验、性能优化等方面进行了测试分析,验证游戏的稳定性和可玩性。同时,针对测试中发现的问题进行优化改进,确保游戏的运行效率和流畅度。
第七章总结与展望,本章对本文的研究内容进行总结,概括本项目的主要成果,并分析目前仍存在的不足之处。最后,展望未来的优化方向和可能的扩展应用。
2关键技术介绍
2.1C++语言介绍
C++是C语言的继承,具有独特的跨范式编程能力,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计[6]。其技术特性可概括为以下三个维度:
首先,C++继承C语言的过程化程序设计思想,支持底层操作;其次,通过抽象数据类型C++可以实现基于对象的程序设计;最后,C++以继承和多态为核心能够构建完整的面向对象编程体系。这种多范式融合的设计理念,让C++既能保障系统级开发的执行效率,又能通过面向对象机制大大提升大型项目的可维护性,能够在计算机高效运行与编程质量提升之间实现了战略性的平衡。
而这些优势表现在游戏开发领域,就大体地体现在下面的三个关键层面:
(1)精准内存控制能力
C++可以通过对系统内存直接操作,进行内存的分配与释放。这个特性赋予了开发者对硬件资源的精确控制权,可以让开发者在需要处理大量动态游戏资源的场景中,既能确保内存使用的极致优化,又可以建立可靠的内存泄漏防护体系,提高游戏的运行性能。
(2)跨平台编译特性
C++基于标准的编译体系支持Windows、Linux、macOS等主流操作系统的无缝移植,可适配从PC、移动设备到游戏主机的多样化硬件架构。这种跨平台兼容性大幅降低了多终端版本开发的边际成本,使”一次开发,多端部署”的现代游戏发布策略成为可能。
(3)丰富的开发支持
在基础架构层面,C++的标准模板库(STL)提供了丰富的通用数据结构和算法组件。在项目工程实践层面,C++经过多年的发展已经有了丰富的生态支持,以虚幻引擎为代表的商业引擎和SDL/OpenGL等开源框架为C++构建了完整的工具链生态,通过高度封装的API接口显著降低图形渲染、物理模拟等核心模块的实现复杂度。
综上所述,通过上述这些技术特性的共同发力,使得C++持续保持着在游戏引擎开发、实时渲染系统构建等高性能计算场景中的不可替代地位,成为了游戏工业的核心技术语言。
2.2SDL技术栈简介
SDL是“Simple DirectMedia Layer”的缩写,它是一个开源的跨平台的多媒体库,广泛应用于游戏开发、多媒体应用等领域。如图2-1所示,SDL是个跨平台多支持的渲染框架,完成在硬件驱动层之上的抽离,提供了对音频、键盘、鼠标、操纵杆以及图形硬件的底层访问,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。
图2-1 SDL框架结构图
SDL同时为游戏开发提供了一个相当完善的媒体库,SDL库分为Video、Audio、CD-ROM、Joystick和Timer等若干子系统,除此之外,还有一些单独的官方扩充函数库,例如SDL_image、SDL_mixer、SDL_net、SDL_ttf、SDL_rtf等。这些库由官方网站提供,并包含在官方文档中,共同组成了SDL的“标准库”,能够帮助开发者更加容易的进行软件开发。
SDL自带的渲染器SDL Renderer作为SDL的核心组件之一,同样具备出色的跨平台兼容性。同时还支持硬件加速渲染,这对于处理多路视频或复杂图形渲染任务尤为重要。并且SDL Renderer还提供了丰富的渲染设置选项,允许开发者根据实际需求进行定制。
最后,SDL同时是一个完全免费的媒体库,SDL在GNU LGPL 2(一个国际上的开源组织)下发布,这个版本允许你将SDL以动态链接库(dynamic link library)的形式免费地用于商业游戏软件的开发。
本次塔防游戏的硬件开发环境采用的是联想拯救者2021年款,其具体配置信息如下表2-1所示。
表2-1 游戏硬件开发环境
类别 | 型号/规格 | 性能参数 |
---|---|---|
电脑型号 | Lenovo Legion R70002021 | - |
操作系统 | Windows 11 专业版 | 64位 |
处理器 | AMD Ryzen 5 5600H | 6核12线程 3.30GHz |
主板 | LENOVO LNVNB161216 | AM4芯片组 |
内存 | Samsung DDR4 | 16G 3200MHz |
主硬盘 | SAMSUNG MZVLB512HBJQ-000L2 | 512GB PCI-E3.0 |
显卡 | NVIDIA GeForce RTX 3050 Laptop GPU | 4GB GDDR6 |
微软推出的Visual Studio 2022(下称VS)作为主流的集成开发工具,在保持传统优势的基础上进行了多项功能升级。该开发环境采用64位架构设计,通过对系统架构的优化显著提升了处理大型项目时的编译速度和资源管理效率。其界面布局采用可自定义的模块化方案,用户可根据项目需求灵活调整工作区配置,这种设计有效降低了操作复杂度,使开发人员能够将注意力集中在核心业务逻辑的实现上。
在跨平台开发领域,VS不仅支持Windows系统的本地化开发,还能通过各种集成框架,例如:MAUI、Xamarin等,实现在Linux等多平台应用的构建。其智能化编码辅助系统有着代码预测生成与质量检测功能,能够在提升开发者编码效率的同时辅助开发者规避常见的开发错误。
对于C++语言的支持方面,VS不仅完整兼容了C++的标准规范,并且还可以在配备的动态调试工具的支持下,在不中断程序运行的情况下实时验证代码修改,这对于在需要频繁迭代的游戏开发场景具有重要实用价值。
在团队协作方面,VS内置的版本控制系统与云端部署模块形成完整的开发运维体系。可以通过可视化Git管理界面简化代码的版本控制流程,配合性能诊断工具链,能够实现从编码调试到部署监控的全流程支持。
(1)多媒体开发框架
SDL2作为跨平台底层交互框架,通过C语言接口提供对音频设备、图形硬件等系统资源的标准化访问方案,其模块化架构包含多个功能扩展组件:SDL_ttf实现矢量字体渲染功能,SDL_image支持多格式图像解码,SDL_mixer集成多声道音频混合引擎,配合SDL2_gfx的几何图形绘制及动态特效接口,共同构成完整的二维多媒体开发解决方案。该框架通过硬件抽象层设计,有效平衡了跨平台适配需求与运行性能表现。
(2)多媒体处理库FFmpeg
因为SDL2本身可能不直接处理视频解码,而为了在本项目中实现对视频流的解码处理,引进了FFmpeg库作为SDL2的补充。开发人员可通过FFmpeg的命令行工具快速完成媒体格式转换,也可直接调用API接口与SDL2的视频渲染模块配合,实现音视频解码数据到图形硬件的直接传输,形成从媒体解析到屏幕输出的完整处理链路。
FFmpeg作为一款在音视频领域应用十分流行的多媒体处理框架,能够非常方便快捷地实现采集录制,转换音视频格式和流编码标准等核心功能,为音视频编解码和流媒体处理提供了专业级的解决方案。其核心组件libavcodec支持H.264、VP9等主流编码协议的编解码操作,libavformat模块处理包括MP4、FLV在内的百余种媒体封装格式[7]。除此之外,FFmpeg还支持开发者直接引入第三方编解码器,集成到开发项目中进行使用。这使得,FFmpeg和SDL2一样,都能够在Windows、Android等不同系统环境中实现高效的视频帧解码与音频采样处理。
(3)数据交互组件
cJSON作为轻量级JSON解析器,采用内存优化策略实现高效数据序列化/反序列化功能。其基于C语言实现的树形结构访问接口,既满足游戏场景中角色属性数据的结构化存储需求,也可作为不同技术栈之间的标准化数据交换中间件。
本项目所设计的游戏的名字是《魔法巨龙与守护之塔》,是一款双人塔防策略游戏,归类为塔防游戏中的实时战略塔防品类(RTTD)。在塔防游戏历经多年发展的今天,已经有了一套成熟的设计体系。
根据Exploring the Attractive Factors of Mobile Tower Defense Games的量化分析表明,塔防游戏中对玩家的吸引力因素主要有四个:控制感、挑战感、紧迫感和娱乐感。游戏设计师在开发TD游戏时应重点关注这些吸引力因素,并根据这些因素的权重关系进行设计优化[8]。依据该理念,在本次游戏的开发设计过程中,项目充分考虑到了控制感、挑战感、紧迫感和娱乐感四者的平衡。
在具体的游戏世界观念设计上,本游戏通过非对称对抗体系。讲述了在一个充满魔法与奇幻生物的古老大陆上,面对日益壮大的黑暗势力,两名玩家将扮演守护者和巨龙,密切配合,击退来势汹汹的敌人,携手保护家园的故事。
在本次塔防游戏设计过程中,充分遵循了玩家的主观感受,将游戏的玩法进行多样化设计,将合作与策略规划深度融合,着重加强了防御塔功能的多样化、敌人类型的多样化,以及防御塔和敌人在交互上的设计,能够让玩家在每一局的游戏中都有不同的体验[9]。
基于市场调研与用户行为数据分析,本研究确定目标用户群体主要包含以下三类核心人群:
(1)休闲策略游戏爱好者
该群体呈现显著的双重需求特征:既追求策略深度又重视情感体验。Newzoo(2023)调查报告显示,全球休闲策略游戏用户规模已达1.2亿,同比增长15%[12]。其核心诉求表现为:偏好中等时长(30-50分钟/局)的游戏机制,要求具备完善的策略系统(包含塔防单位协同、地形利用等要素),同时对美术风格呈现明显的治愈系偏好(卡通渲染风格接受度达78%)。值得注意的是,该群体对合作模式表现出强烈兴趣,双人协同玩法可提升28%的用户留存率[13]。
(2)社交导向型玩家
社交玩家的核心特征体现在互动需求与情感联结两方面。根据Statista(2022)数据,全球社交游戏市场规模已达248亿美元,其中合作类玩法占据43%市场份额[14]。该群体日均社交游戏时长达到2.3小时,显著高于单机游戏用户(1.1小时)。其行为模式呈现两种典型场景:线上场景中,语音沟通功能使用率达91%;线下场景中,本地联机模式可提升65%的复玩率。游戏内社交系统的设计需平衡策略协作(资源分配效率)与情感互动(成就共享机制)的双重需求。
(3)年轻玩家
15-24岁用户构成核心消费群体,占比达62%[13]。其行为特征表现为:偏好高沉浸式世界观(奇幻/科幻题材点击转化率高出均值37%),追求玩法创新度(新颖机制可使下载量提升42%),同时呈现学习型游戏倾向(83%用户认可游戏对策略思维的提升作用)。值得注意的是,该群体对成就系统敏感度较高,完善的成长体系可提升54%的付费转化率。
表3-1 用户群体特征对比[13]
对比维度 | 休闲策略玩家 | 社交导向型玩家 | 年轻玩家 |
---|---|---|---|
日均游戏时长 | 1.8h | 2.3h | 2.1h |
付费转化率 | 22% | 18% | 35% |
社交功能依赖度 | 中等 | 高 | 较高 |
内容更新期待周期 | 8~10周 | 6~8周 | 4~6周 |
本次塔防游戏设计主要页面有六个,分别为:启动动画界面、主菜单界面、操作介绍界面、背景介绍界面、游戏关卡选择界面、游戏界面[10]。
启动动画界面为零级界面,负责进入时播放简短的logo动画然后跳转到主菜单界面。
开始界面为一级界面,包括:“开始游戏”、“按键操作”、“背景介绍”和“退出游戏”四个按键。
关卡选择界面为二级界面,在此界面可以选择不同的关卡加载进入游戏。
操作介绍界面和背景介绍界面同为二级界面,在这两个界面中可观看游戏玩法以及了解游戏的世界背景。
游戏界面则为三级界面,在此界面中可进行游戏的具体游玩操作。
他们之间的具体交互关系可以通过下方游戏界面交互层级结构图(图3-1)进行了解。
图3-1 游戏界面交互层级结构图
在玩家进入游戏后,游戏首先播放零级界面(启动动画界面)的动画视频,动画播放结束后进入一级界面(主界面)。主界面包含“开始游戏”、“操作介绍”、“背景介绍”和“退出游戏”四个按键。
玩家点击“开始游戏”后,就进入了二级界面(关卡选择界面)。玩家点击“操作介绍”可以进入二级界面(操作介绍界面),能够在此界面查看游戏的按键操作。玩家点击“背景介绍”按钮则可进入二级界面(背景介绍界面),可以在此界面观看游戏背景介绍视频,玩家点击“退出游戏”即关闭游戏程序退出到桌面。
玩家在二级界面(关卡选择界面)选择自己想要挑战的关卡,然后点击“进入游戏”按钮,则可以进入游戏的三级界面(游戏界面)。若游戏失败即可选择重新开始游戏、返回主菜单或者回到关卡选择界面,若该关卡过关即可选择返回关卡选择页或者返回主菜单。
游戏的功能层次可以清晰的划分为几个核心的部分,每个部分都承担着不同的职责,共同构成了游戏的完整体验。游戏分为用户交互层、游戏逻辑层、资源管理层和个人信息管理层,具体层次如PC端游戏功能层次图所示。
图3-2 PC端游戏功能层次图
本次塔防游戏项目的关卡数据主要由三部分组成,分别是:保存游戏各种角色属性的(config.json),保存关卡地图数据的(map.csv),保存敌人生成数据的(level.json)。这些文件都被保存在路径(..\TD\leveldata)中,当玩家在关卡选择界面选择关卡进入时,就会产生一个(level_index)值传入游戏场景页面,游戏场景页面就会根据对应的level_index值,加载对应的关卡数据,然后通过游戏配置管理器(configmanager)解析这些数据传入到游戏场景中,游戏场景会根据关卡数据渲染画面,生成敌人,各种角色也可以通过关卡数据获得他的属性。数据的具体流程如下图所示。
图3-3 游戏关卡数据加载流程图
关卡数据通过这样的处理就可以减轻数据的加载负担,同时也能够很轻松的完成对不同游戏关卡数据的修改而不影响到其他游戏关卡和页面的功能。
玩家1所操纵的巨龙角色是本游戏的特色之一,巨龙除了可以在场景中进行自由移动外,还有着两种攻击方式,分别是普通攻击(闪电)和技能攻击(冲击波)。这两种攻击效果不能够同时存在,即不能够在发动普通攻击的同时又发动技能攻击,并且两种攻击方式都有各自的CD,普通攻击的CD较短,技能攻击的CD较长,通过控制攻击的释放频率来防止数据挤压导致程序出错,同时也跟符合正常游戏的设计逻辑。
图3-5 巨龙攻击流程图
所以,总的来说就是对玩家1的攻击流程添加了两个状态判定,通过状态判定来处理巨龙的攻击行为。
防御塔攻击是防御塔功能的重中之重,同时也是整个游戏的关键所在。对防御塔的设计,要从以下几个方面思考,一是如何才能在茫茫的敌人中选择合适的攻击目标,敌人在不停移动;二是选中敌人之后如何锁定攻击,为了使游戏更真实,攻击之前如何使防御塔调转炮口;三是如何知道是否击中敌人,击中以后如何处理[15]。为解决这一技术难点,把整个防御塔的攻击流程分成了三大主要步骤,三大步骤的具体流程如防御塔攻击流程图所示。
图3-6 防御塔攻击流程图
通过这样不断检测防御塔攻击范围内的目标状态,就可以实现基础的防御塔攻击逻辑。
敌人作为塔防游戏项目中的重要一环,对游戏来说是不可缺失的,不同类型的敌人的存在为游戏添加了更多的对抗性和趣味性。而如何处理好敌人的生成逻辑、行走逻辑和攻击逻辑才是创造好敌人类别的关键。敌人的生成逻辑还是通过游戏场景接收的关卡数据(level.json)和配置数据(config.json)实现的,这两个json数据文件决定了这一关卡中究竟有多少个波次,每个波次中的敌人类别是什么,每个敌人的属性是什么。敌人具体的生成与攻击流程如下所示:
图3-7 敌人生成与攻击流程图
通过这样不断检测敌人目前的状态,就可以实现敌人的生成移动和攻击逻辑了。
一局正常的游戏总是拥有结局的,而游戏的结局五分有两种,胜利或者失败。在本次塔防游戏项目中,游戏结局的判定逻辑如下:由于敌人一旦碰到防御水晶便会对其造成伤害,所以如果在所有敌人生成完毕并被消灭后,防御水晶依然有残余血量,则判定游戏胜利,游戏会根据剩余血量的多少进行游戏评级。而如果在所有敌人生成完毕并被消灭之前,防御水晶的血量达到了0,那么就判定游戏失败。游戏结算流程图如下所示。
图3-8 游戏结算流程图
通过这样在游戏对局中不断检测防御水晶和敌人的状态,就可以实现游戏结算的判定逻辑。
结合上面的游戏相关流程,对本次塔防具体流程规则进行了总结,其游戏整体流程如图3-9所示:
图3-9 游戏整体流程图
通过游戏整体流程图,可以得知本次塔防游戏的基本规则如下所示:
(1)玩家1可以使用普攻和技能攻击敌人,玩家2可以使用金币在建筑方块上建造并升级防御塔,但是每升级一次,金币的消耗便会随之增加;
(2)敌人会随着游戏波次从不同方向生成,然后通过不同的路径走向玩家的防御水晶;
(3)玩家每击杀一个敌人则会获得金币奖励;
(4)敌人一旦碰到防御水晶便会对其造成伤害,防御水晶血量达到0或者敌人全部都被消灭,那么游戏结束。
在洛瑟兰大陆的中央腹地,永恒之城如同嵌在大地脉络中的璀璨宝石。这座由古代矮人工匠与精灵法师共同铸造的奇迹之城——永恒之城。其城墙采用星陨岩与秘银合金锻造,表面蚀刻的古代符文并非简单的装饰,当黑暗气息逼近时,这些符文会汲取地脉能量,形成笼罩全城的虹光屏障。城市核心的水晶塔实为古代龙族遗留的”元素枢纽”,其周期性释放的净化波动是抑制黑暗侵蚀的关键力量。
黑暗势力的源头是堕落的古代炼金产物”腐化之源”,这个失控的混沌能量体不断喷涌出污秽物质。被污染的土地会滋生出紫黑色结晶簇,其释放的瘴气能使生物逐渐异化为扭曲的魔物。监测法阵显示,黑暗潮汐的强度呈现月相周期性波动,这解释了敌军攻势为何总在血月之夜达到顶峰。
守护者艾德温是最后一位掌握”筑城者秘术”的符文大师,其战袍上的符印分别对应不同类别的防御工事构筑术式。巨龙作为上古雷霆龙族的末裔,其鳞甲呈现深邃的紫晶色泽,战斗时会释放雷霆和吐息将敌人化为灰烬。二者作为亲密无间的伙伴,是守护这片大陆最后的希望,他们义无反顾地站在城池前,准备与黑暗军团展开一场惊心动魄、关乎生死存亡的惨烈战斗,用自己的生命和力量捍卫着这片大陆。
图4-1 游戏场景图
玩家1负责在敌人前进道路的地块上点击鼠标右键,唤出放置轮盘放置不同类型的防御塔来抵御敌人的进攻,并通过获取的金币对防御塔进行升级。而玩家2则要操控一只巨龙,使用键盘的wasd键在地图上灵活游走,通过普通攻击键[ j ]和技能键[ k ],攻击那些靠近水晶塔的敌人,阻止它们破坏水晶塔。玩家1和玩家2两人必须紧密合作,才能在敌人的猛攻下保卫住水晶塔,拯救这个世界。
图4-2 游戏水晶生命值图
金币系统是游戏中的重要组成部分,防御塔的建造和升级都离不开它,同时对金币获取难度的大小也直接影响到游戏的游玩难度和乐趣。所以,在游戏开发过程中,对金币的获取要进行仔细的把关。
图4-3 金币ui图
游戏关卡中获得金币的途径主要有以下几个方面:
(1)初始金币:100;
(2)击杀不同敌人获得不同数额金币,同时还有可能掉落金币道具,拾取后也会增加金币;
(3)摧毁已建造的防御塔可以返还一定数量的金币;
(4)每一波次结束后奖励一定数量的金币。
关卡描述:场景为平和的公园,敌人从一条曲折的小路进攻。玩家需要利用初始金币在道路两旁放置防御塔,抵挡小敌人和少量敌人战士的进攻。
图4-4 游戏场景图1
通过条件:成功抵御5波敌人进攻,保护水晶塔存活。
关卡描述:场景切换至一个荒漠小镇,敌人从两个通道同时出现,且新增敌人哥布林和骷髅兵。场地中还要许多房屋,限制了防御塔的放置位置。
图4-5 游戏场景图2
通过条件:抵御7波敌人攻击,其中第5波会有一大波敌人骷髅兵突袭,保护水晶塔存活。
关卡描述:场景类似一个夏日沙滩的聚集地,场景中可放置防御塔的位置再次减少,敌人涌入的通道和敌人数量大幅增加,还有敌人领主哥布林大祭司首次登场。
图4-6 游戏场景图3
通过条件:抵挡住10波敌人,特别是在第8波和第10波分别遭遇敌人领主带领的进攻,保护水晶塔存活。
在本次的塔防游戏项目中一共设置了六个场景,分别是:启动动画场景、主菜单场景、关卡选择场景、按键操作介绍场景、背景介绍场景和游戏关卡场景。
启动动画场景主要由SDL配合FFmpeg解析MP4视频文件完成,该场景负责的是游戏启动动画的播放,这个游戏动画的主要内容是游戏logo配合一些简短的动画。
图4-7 启动动画场景图
主菜单场景主要由SDL渲染完成,该场景主要负责的是游戏主菜单页面的绘制,主菜单页面是游戏的中枢,其内包含着进入游戏、按键操作、背景介绍、退出游戏四个游戏按键,玩家可以通过点击这几个按键跳转到不同的场景页面。
图4-8 主菜单场景图
操作介绍场景因为没有视频需要处理,同样是由SDL渲染完成,该场景负责的是通过页面对游戏的各种信息进行介绍,主要包括玩家1和玩家2各自的操作方式、敌人的各种基础介绍、以及游戏中的道具物品的介绍。
图4-9 操作介绍场景图
背景介绍场景由于要渲染一个长视频文件,还是由SDL配合FFmpeg解析MP4视频文件完成,该场景负责的是游戏背景介绍动画的播放,帮助玩家了解该游戏世界的故事背景,更好的融入游戏。
图4-10 背景介绍场景图
关卡选择场景同样主要由SDL渲染完成,该场景主要负责的是游戏关卡的切换,每一个关卡都有着不同的关卡编号(level_index),通过关卡选择其选择不同的关卡,点击开始游戏后,就会将对应的关卡编号传入游戏关卡场景,然后游戏关卡场景就会根据关卡编号加载对应关卡的游戏数据进行渲染。
图4-11 关卡选择场景图
游戏场景是游戏核心,大部分的游戏逻辑的运行效果都是在这里呈现的,玩家游玩的每一个关卡都是在该场景渲染处理的,角色的每一次移动、防御塔的每一个建造删除、敌人的每一波刷新等,都和这个场景息息相关,这个场景也是本次塔防游戏的成果展示的主阵地。
图4-12 游戏场景图
玩家1(巨龙):拥有敏捷的攻击速度和强力的技能。可以喷出闪电进行范围攻击,对成群的敌人造成巨大伤害。移动速度较快,能迅速穿梭在战场中支援各个防御薄弱的区域。
图4-13 巨龙角色图
普攻攻击力:每次攻击造成10点伤害。
速度:每秒移动5格。
血量:400。
技能:火焰吐息:对前方区域内的敌人造成20点伤害,冷却时间5秒。
玩家2(守护者):作为防御塔的放置者,是幕后的战略指挥者。不需要在战场上直接作战,但需要有敏锐的局势洞察力和快速的反应能力,根据敌人的进攻路线和类型,使用鼠标合理选择防御塔放置的位置。
图4-14 防御塔建与升级摧毁造轮盘图
玩家1可放置的防御塔类型如下:
(1)弓箭塔:
技能:发射弓箭,对单个目标造成伤害,初始攻击造成10点伤害。
进化效果:升级后攻击速度和伤害提升。
花费:50金币。
(2)斧头塔:
技能:发射斧头,对直线上的敌人造成25点伤害。
特殊效果:使被攻击目标减速30%,持续2秒。
进化效果:伤害增加,减速效果提升至50%。
花费:70金币。
(3)枪手塔:
技能:向敌人发射子弹,对区域敌人造成20点伤害。
特殊效果:爆炸范围为以子弹为中心的半径1.2格区域,对区域内敌人造成爆炸伤害。
进化效果:伤害提升,攻击速度加快。
花费:70金币。
种类繁多,除了基础的史莱姆和哥布林外,还包括行动敏捷的骷髅兵,,能迅速冲向水晶塔;有体型巨大的史莱姆王,防御力高,能承受较多攻击,为其他敌人开辟道路;还有哥布林大祭司,可以释放技能为范围内的友军回血,直接威胁水晶塔和巨龙。
图4-15 敌人类型图
(1)史莱姆
速度:慢,每秒移动0.8格。
伤害:1。
血量:100。
出现频率:较高,每波敌人中有约30%是小敌人。
(2)史莱姆王
速度:更慢,每秒移动0.6格。
伤害:2。
血量:200。
出现频率:中等,每波敌人中占20%。
(3)骷髅兵
速度:每秒移动1.5格。
伤害:1。
血量:200。
出现频率:较低,每波敌人中占10%。
(4)哥布林
速度:每秒移动1.5格。
伤害:1。
血量:400。
出现频率:较低,每波敌人中占15%。
(5)哥布林祭司
速度:每秒移动0.6格。
伤害:2。
血量:500。
特殊效果:每隔5秒能召恢复4格半径内敌人的20点血量。
出现频率:极低,游戏后期每隔几波才出现一次。
窗口创建与图形绘制是游戏开发的基础环节,游戏中所有的一切都要在这个游戏窗口中完成。在基于C++和SDL的2D双人塔防游戏的项目开发中,首先要利用SDL来创建游戏窗口,这是游戏开发过程中一切的起源。这一操作的实现涉及到了一系列关键步骤,首先调用SDL_Init函数进行SDL库的初始化,包含初始化音频和视频功能,使用TTF_Init进行字体功能初始化,并根据配置创建全局窗口绘制表面以及渲染器[16]。
在图形的绘制方面,通过SDL为开发者提供的绘图函数,就可以实现各种基本图形(如线条、矩形、圆形等)的绘制。游戏开发者通过了解这些基础函数的使用,就能够更好的熟悉和掌握SDL的渲染逻辑和使用技巧。
以下是一个简单的代码示例,展示了如何创建一个窗口并在该窗口中绘制一个矩形:
这段代码首先初始化了SDL库,然后通过SDL_Window* window和SDL_Renderer* renderer创建了一个1280x720的窗口和一个渲染器,最后通过渲染器renderer绘制了一个红色的矩形,并将其显示在窗口中。
在一个游戏中,良好的用户交互体验对游戏的发展至关重要。SDL为游戏开发者提供了简单便捷的事件处理机制,能够有效地捕捉和处理用户的各种输入操作,如鼠标点击、键盘按键等。
当用户在游戏窗口中进行操作时,系统就会产生相应的事件。SDL可以在程序运行时,可以通过SDL_PollEvent函数不断轮询事件队列,获取最新的事件信息。例如,当玩家点击鼠标左键时,系统就会产生一个SDL_MOUSEBUTTONDOWN的点击事件。然后,开发者就可以通过判断事件的类型和相关参数,针对性的开发相关事件的执行逻辑,来实现玩家的具体操作意图。
对于键盘输入的处理,开发者同样可以利用SDL自带的事件处理机制来实现玩家操作。例如,当玩家按下或释放某个键盘按键时,会产生相应的SDL_KEYDOWN或SDL_KEYUP事件。通过检测这些事件,可以实现玩家对游戏角色的精细控制,如移动角色,释放角色技能等。
以下是一个简单的示例代码,用于处理鼠标点击事件:
SDL_Event event; while (SDL_PollEvent(&event)) {
} |
---|
这段代码通过循环轮询事件队列,当检测到鼠标点击事件时,获取鼠标的坐标,并可以根据坐标进行相应的逻辑处理。
(1)游戏循环
游戏循环是实现游戏运行的核心架构,它负责在程序运行时不断地更新游戏状态、渲染游戏画面以及处理用户的输入信息,从而保证游戏的持续平稳的运行。
一个游戏的游戏循环通常包含着三个主要部分,分别是:更新(Update)、渲染(Render)和事件处理(Event)。在更新阶段,程序可以根据游戏的逻辑和规则,更新游戏中的各种元素的状态,如敌人的移动、防御塔的攻击等。在渲染阶段,程序负责将更新后的游戏画面绘制到屏幕上,使玩家能够看到游戏界面的各种变化响应。而在最后的事件处理阶段,程序则是通过接收用户的各种输入操作,从而触发相应的游戏逻辑,如鼠标点击、键盘按键等。
(2)状态管理
状态管理是游戏编程中的又一个重要思想,游戏开发者通过在程序中定义不同的状态标识,可以便捷地管理游戏运行时的不同状态。例如,在本次项目的塔防游戏中,包括的游戏状态就有着战斗开始、暂停、结束等。通过在程序中定义不同的状态类,然后在游戏循环中根据当前状态来执行相对应的逻辑,可以使游戏的运行逻辑更加清晰和易于维护。
以下是一个简单的游戏循环和状态管理结合的示例代码:
bool running = true; while (running) {
} |
---|
在这个示例中,游戏在running = true时不断循环执行,直到用户关闭窗口使running = false时,才能使游戏跳出循环。而在每次具体的游戏循环中,程序总是先处理事件,然后更新游戏状态,最后渲染游戏画面。
在跨平台2D游戏开发中,资源管理架构的设计直接影响运行时性能与可维护性。苏雄等(2021)提出的CSimpleEngine框架通过C语言实现SDL封装,其模块化设计虽在Android平台达成30FPS基础渲染性能,但采用编译期静态注册机制(全局数组+枚举索引)[16],导致运行时动态扩展能力受限,更适合轻量级C语言教学项目。
本研究在此资源管理方案上进行了进行架构升级,提出基于现代C++特性的泛化资源池方案(unordered_map<ResID, T*>),使用哈希表替代静态数组,来解耦资源标识符(ResID)与底层存储逻辑。同时,方案引入强类型资源标识符(enum class)定义资源ID。这大大提升了编译期的扩展灵活性和类型安全性,更适合中等规模C++游戏开发。
在本次塔防游戏的项目开发中,为了避免因为频繁地加载和释放文件而导致不必要的内存开销,游戏在初始化阶段就一次性加载了全部图像材质和音效文件,存储于统一资源池中,消除运行时频繁I/O操作引发的卡顿问题。
同时,在运行期间,游戏对象是通过ResID从池中直接获取资源实例的,资源释放时标记为「可复用」状态,而非立即销毁,减少内存碎片化与重复加载开销,通过这样的方法可以显著的提高资源利用率,以免造成不必要的内存浪费。
以下是一个简单的游戏资源加载示例代码:
#include <SDL.h>//多媒体库 #include <SDL_ttf.h>//字体库 #include <SDL_mixer.h>//音频库 #include <SDL_image.h>//图片库 #include <unordered_map>//引入哈希表帮助快速查找 //枚举了游戏中使用的各种资源标识符 enum class ResID {Tex_Tileset, Music_BGM, Font_Main} class ResourcesManager : public Manager {
public:
//提供从磁盘加载资源的方法 bool load_from_file(SDL_Renderer* renderer) {
} //提供对外方法获取不同资源池 const FontPool& get_font_pool(){return font_pool;} const MusicPool& get_music_pool(){return music_pool;} const TexturePool& get_texture_pool(){return texture_pool;} protected:
private:
} |
---|
本游戏通过FFmpeg库实现视频流的解码与音频同步播放功能,结合SDL的硬件加速渲染机制,构建了高效的音视频处理管线。视频播放器播放一个本地视频文件,通常需要经过以下几个步骤:打开音视频,解码音视频,音视频同步,音视频渲染[11]。本项目采用分层架构设计,其逻辑结构如下图5-1所示。通过FFmpeg完成媒体解析与帧解码,由SDL负责窗口的绘制与视频渲染输出与音频播放,二者通过双缓冲机制实现数据交互。
图5-1 音视频解码流程图
本次塔防游戏的视频解码流程基于FFmpeg的解复用(Demuxing)、解码(Decoding)与格式转换(SwScale)三级流水线机制设计。首先,通过avformat_open_input打开视频文件并解析媒体流信息,分离音视频流,并利用硬件加速解码(H.264)降低CPU负载。初始化解码器上下文(AVCodecContext),并优先启用硬件加速(如DXVA2)以降低CPU负载。然后,解码后的YUV420P帧通过sws_scale转换为SDL兼容的RGB24格式。最终,通过SDL_CreateTextureFromSurface将RGB数据映射为GPU纹理,避免内存拷贝开销。视频解码与渲染实现核心代码如下:
// 初始化FFmpeg解码器(VideoPlayer::init) avformat_open_input(&pFormatCtx, filename.c_str(), nullptr, nullptr); // 打开媒体文件 avformat_find_stream_info(pFormatCtx, nullptr); // 解析流信息 // 初始化解码器上下文 AVCodecParameters* codecPar = pFormatCtx->streams[videoStreamIndex]->codecpar; const AVCodec* codec = avcodec_find_decoder(codecPar->codec_id); avcodec_parameters_to_context(pCodecCtx, codecPar); avcodec_open2(pCodecCtx, codec, nullptr); // 帧解码与RGB转换(VideoPlayer::decodeNextFrame) avcodec_send_packet(pCodecCtx, packet); // 发送数据包 avcodec_receive_frame(pCodecCtx, pFrame); // 接收解码帧 sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); // YUV转RGB // 生成SDL纹理并渲染(GameIntroScene::on_render) SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, SDL_CreateRGBSurfaceFrom(pFrameRGB->data[0], pCodecCtx->width, pCodecCtx->height,24, pFrameRGB->linesize[0], 0x000000FF, 0x0000FF00, 0x00FF0000, 0)); SDL_RenderCopy(renderer, texture, nullptr, &dstRect); // 渲染到屏幕 |
---|
该方案通过硬件加速解码与零拷贝纹理映射,显著降低CPU负载。
音频处理通过独立线程管理,结合重采样与时钟同步机制保障音画一致性。在进行音频处理时,将多声道或高采样率音频统一转换为16位立体声格式(S16),适配SDL音频设备。
然后,实现音画同步主要利用了主时钟(Master Clock)机制,以音频时钟为基准,动态计算视频帧显示时间戳(PTS)与音频播放时间的差值,若视频超前超过100ms则插入延迟,反之触发丢帧策略。音频同步与处理的核心代码示例如下:
// 音频重采样配置(VideoPlayer::init) av_channel_layout_from_mask(&out_layout, AV_CH_LAYOUT_STEREO); // 输出立体声 swr_alloc_set_opts2(&swr_ctx, &out_layout, AV_SAMPLE_FMT_S16,
// 音画同步逻辑(GameIntroScene::on_render) double audio_time = videoplayer->getAudioClock(); // 获取音频时钟 double video_time = last_frame_pts; // 当前视频帧时间戳 if (fabs(video_time - audio_time) > 0.1) { // 同步阈值100ms
} |
---|
通过该同步机制可以将音频延迟控制在±20ms内,实现音视频的同步播放,带来更好的视听体验。
在游戏的开发过程中,游戏主函数(main.cpp)作为程序入口,扮演着至关重要的角色。它负责初始化游戏的基本环境、加载所需资源、以及循环处理游戏场景的切换、事件管理、更新和渲染。
首先,在正式进行C++和SDL的双人塔防游戏开发时,要在主函数调用SDL_Init()来初始化SDL库,来支持图形渲染、音频播放等基本功能。在成功初始化SDL后,在主函数中通过SDL_CreateWindow创建游戏窗口,配置窗口数据。接下来,要通过SDL_CreateRenderer创建渲染器,用于管理和呈现游戏图形内容。该部分功能实现的具体代码可参考5.1.1窗口创建与图形绘制。
在本次开发项目的主函数中,通过使用资源管理器(ResourcesManager)类一次性加载了所有的游戏资源,该类负责从文件中读取游戏所需的图像、音频等资源。然后,通过场景管理器(SceneManager)单例类,将游戏场景(如背景介绍场景、主菜单场景、游戏场景等)添加到对应的场景管理器中。这里加载游戏资源的代码示例如下所示:
ResourcesManager::instance()->load_from_file(renderer); SceneManager& sceneManager = SceneManager::GetInstance(); sceneManager.AddScene(SceneType::VIDEO_INTRO_SCENE, new VideotitleScene(renderer, window)); sceneManager.AddScene(SceneType::MENU_SCENE, new MenuScene(renderer , window)); sceneManager.SwitchScene(SceneType::VIDEO_INTRO_SCENE); |
---|
主循环部分是主函数中最重要的一部分,他负责游戏的整体运行。它通过SDL_PollEvent获取用户的输入事件,并交给当前对应活动的场景进行处理。随后,程序会调用对应场景的Update()方法对游戏状态进行更新,最后通过Render()方法绘制对应场景的画面。该部分的核心代码示例如下:
while (running) {
} |
---|
游戏的数据解析是确保游戏逻辑和资源能被正确加载和显示的关键。在本次塔防游戏项目中,游戏数据的解析主要依赖ConfigManager类,该类负责解析并加载各类配置文件,包括关卡数据、角色属性、塔的配置以及敌人的数据等。
ConfigManager类使用cJSON库解析JSON格式的配置文件。游戏中通过load_game_config函数加载基础配置文件,解析窗口设置、巨龙属性、防御塔属性和敌人属性等数据。该函数首先通过std::ifstream打开配置文件,然后将其内容读取到字符串流中,并通过cJSON_Parse函数解析成JSON对象。
核心代码示例如下:
|
bool load_game_config(const std::string& path) {
std::ifstream file(path);
if (!file.good()) return false;
std::stringstream str_stream;
str_stream << file.rdbuf(); file.close();
cJSON* json_root = cJSON_Parse(str_stream.str().c_str());
if (!json_root || json_root->type != cJSON_Object) return false;
// 解析窗口、巨龙、防御塔和敌人的属性
parse_basic_template(basic_template, cJSON_GetObjectItem(json_root, “basic”));
parse_player_template(player_template, cJSON_GetObjectItem(json_root, “player”));
parse_tower_template(archer_template, cJSON_GetObjectItem(json_root, “tower”));
parse_enemy_template(slim_template, cJSON_GetObjectItem(json_root, “enemy”));
cJSON_Delete(json_root);
return true;
}
|| :- |
具体的解析过程会根据不同的配置项分别调用对应的解析函数。例如,parse_basic_template函数会解析窗口标题、大小等设置;parse_player_template函数会解析巨龙的移动速度、攻击间隔等属性;parse_tower_template和parse_enemy_template函数分别用于解析防御塔和敌人的属性数据。
核心代码示例如下:
|
void parse_player_template(PlayerTemplate& tpl, cJSON* json_root) {
if (!json_root || json_root->type != cJSON_Object) return;
cJSON* json_speed = cJSON_GetObjectItem(json_root, “speed”);
if (json_speed && json_speed->type == cJSON_Number)
tpl.speed = json_speed->valuedouble;
// 解析其他属性…
}
|| :- |
5.4.3储存解析数据
此外,ConfigManager还通过load_level_config函数加载关卡的波次数据。该函数解析关卡文件,将每一波敌人的生成时间、生成位置及敌人类型等信息存储在wave_list中,供后续的游戏场景中使用。
核心代码示例如下:
|
bool load_level_config(const std::string& path) {
wave_list.clear();
std::ifstream file(path);
if (!file.good()) return false;
std::stringstream str_stream;
str_stream << file.rdbuf(); file.close();
cJSON* json_root = cJSON_Parse(str_stream.str().c_str());
if (!json_root || json_root->type != cJSON_Array) return false;
// 解析波次数据
cJSON* json_wave = nullptr;
cJSON_ArrayForEach(json_wave, json_root) {
// 解析波次内部内容…
}
cJSON_Delete(json_root);
return true;
}
|| :- |
总之通过以上三个步骤的方法,游戏的各项数据(如玩家、塔、防御塔、敌人、波次等)都能通过配置文件动态加载,从而实现灵活的游戏设计与数据管理。
在游戏开发过程中,资源管理类(ResourcesManager)负责处理游戏中的各种资源,包括图像、音效、背景音乐以及字体,都通过该类进行集中管理和加载,从而确保游戏运行时能够高效、稳定地访问和使用这些资源。
首先,资源管理器通过load_from_file方法负责将所有资源从磁盘加载到内存中。然后再通过内存将所有的资源都存储在相应的资源池中,如纹理资源池texture_pool、音效资源池sound_pool、背景音乐资源池music_pool和字体资源池FontPool。加载完资源后,ResourcesManager会检查每个资源是否成功加载。如果加载失败,函数会返回false,表示资源加载出现问题。这里具体的加载纹理资源的方法可以借鉴5.1.4基础的资源管理的示例代码。
通过枚举ResID,资源管理器能够高效地管理和访问不同类型的资源。每当需要使用某种资源时,开发者可以通过资源标识符直接从对应的资源池中获取。例如,在游戏场景中,开发者可以通过ResID::Tex_Player获取巨龙的纹理,示例代码如下:
const ResourcesManager::TexturePool& tex_pool
SDL_Texture* tex_player = tex_pool.find(ResID::Tex_Player)->second; |
---|
总之,本项目通过资源管理器实现了集中管理所有游戏资源,确保了资源的高效加载和快速访问。利用单例模式,游戏的任何部分都可以方便地获取和使用资源,无需重复加载。这种方式不仅提升了性能,还减少了内存的浪费,同时通过合理的资源卸载机制,确保了内存的有效管理。
此外,ResourcesManager 使得游戏的资源配置更加灵活。例如,如果需要更换某个资源,只需要修改资源文件路径,而不需要修改代码中的其他部分,从而提高了开发效率和维护性。
在本塔防游戏项目中,使用场景管理器(Scene Manager)来处理游戏中的各种场景,如主菜单、游戏关卡、以及这些场景之间的切换。它确保游戏的各个部分能够独立运行,同时维持整体游戏流程的顺畅,保障用户体验。
场景管理器还是采用了单例模式,确保游戏中只有一个实例。这种设计方式简化了场景管理,也使得场景切换变得更加一致和高效。然后在场景管理器通过SceneType枚举类型将不同的场景进行标识,并使用unordered_map来存储和管理这些场景。场景管理器的示例代码如下:
|
---|
通过应用场景管理器可以有效地组织游戏中的各个场景,保证场景的切换和事件处理。通过这种设计,游戏的逻辑更加模块化,容易扩展和维护。同时,场景管理器提供了集中式的更新与渲染机制,使得游戏的运行更为高效。
启动动画场景是玩家进入游戏后的首个交互界面,其核心功能是播放游戏LOGO动画并支持快速跳过。本场景通过VideotitleScene类实现视频流的轻量化解码与交互控制,具体技术实现如下:
(1)视频解码与渲染流程
采用FFmpeg进行MP4文件解码,通过avformat_open_input解析视频封装格式,分离音视频流并初始化硬件加速解码器(H.264)。解码后的YUV帧通过sws_scale转换为RGB格式,最终调用SDL_CreateTextureFromSurface生成GPU纹理。其核心代码如下所示:
// 初始化视频解码上下文 avformat_open_input(&pFormatCtx, filename, nullptr, nullptr); avcodec_parameters_to_context(codecCtx, codecPar); avcodec_open2(codecCtx, codec, nullptr); // 帧解码与纹理映射 avcodec_send_packet(codecCtx, packet); avcodec_receive_frame(codecCtx, frame); sws_scale(swsCtx, frame->data, frame->linesize, 0, height, rgbFrame->data, rgbFrame->linesize); SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); |
---|
(2)跳过交互功能
场景右下角设置80×80像素跳过按钮(坐标1180×620),通过坐标检测实现点击响应。用户点击后触发音效播放(Mix_PlayChannel)并立即跳转至主菜单场景,核心逻辑如下:
if (e.type == SDL_MOUSEBUTTONDOWN) {
} |
---|
(3)基础音视频同步
采用阈值丢帧策略:当视频落后音频超过100ms时,允许连续丢弃最多2帧以追赶进度。同步过程通过frame_drop_counter计数器实现,代码片段如下:
double audio_time = videoplayer.getAudioClock(); double video_time = last_frame_pts; if (fabs(video_time - audio_time) > 0.1 && video_time < audio_time) {
} |
---|
最后实现的启动动画场景的效果图大体上如下所示:
图5-2 启动动画场景效果图
主菜单场景(MenuScene)是玩家进入游戏后的首个交互界面,它提供了四个主要功能按钮:“开始游戏”、“按键操作”、“背景介绍”和“退出游戏”。每个按钮都具有独特的视觉效果和响应逻辑,确保了用户能够顺畅地导航到其他场景。其核心功能包括:按钮的布局交互响应、退出确认弹窗机制。
(1)按钮的布局交互响应
实现按钮的交互响应,首先要在初始化过程中加载按钮纹理,以下方的“开始游戏”按钮为例,按钮通过std::bind绑定到相应的回调函数std::bind(&MenuScene::OnEnterGameClicked, this)中,实现场景的跳转。
然后,按钮的具体布局是通过InitializeButtons函数计算按钮总高度与屏幕垂直中心位置,动态调整按钮间距。采用SDL_QueryTexture获取纹理原始尺寸,实现自适应布局。采用render_scaled_button函数,实现按钮中心点保持的缩放效果,通过缩放因子参数控制不同状态(悬停/常态)的显示比例。
最后,通过on_input(SDL_Event& e),接收点击“开始游戏”按钮触发的事件,执行OnEnterGameClicked方法,进入游戏选择界面。其布局交互响应核心代码如下:
class MenuScene : public Scene {
} //动态按钮布局算法 int startY = (720 - totalHeight) / 2; // 垂直居中计算 buttons_[i].rect.x = (1280 - buttonWidth) / 2; // 水平居中 //动态按钮缩放渲染 void render_scaled_button(…, float scale) {
} //按钮事件处理机制 void on_input(SDL_Event& e) override { int x, y; SDL_GetMouseState(&x, &y); // 处理鼠标事件 for (auto& button : buttons_){ if (e.type == SDL_MOUSEBUTTONDOWN && button.isHovered){ } if (e.type == SDL_MOUSEBUTTONUP){ } } } //按钮回调函数 void OnEnterGameClicked() {
} |
---|
(2)退出确认弹窗系统
通过showExitModal_状态标志控制弹窗显示逻辑,区分主菜单与弹窗的输入事件,弹窗激活时,主菜单按钮事件被屏蔽,通过独立循环处理弹窗内按钮状态。弹窗包含确认与取消按钮,点击”退出游戏”按钮后触发弹窗显示,通过独立的事件处理管道隔离主菜单与弹窗的输入响应。弹窗按钮采用动态缩放策略,确认退出时调用SDL_Quit终止进程。其核心代码如下:
// 退出确认逻辑 void OnExitGameClicked() { showExitModal_ = true; } // 显示弹窗 void OnConfirmExitClicked() { SDL_Quit(); exit(0); } // 实际退出 //复合事件处理机制 if (showExitModal_) {
} |
---|
最后主菜单实现的效果图如下图5-3和图5-4所示:
图5-3 主菜单场景效果图
图5-4 主菜单弹窗效果图
综上所述,通过使用SDL的纹理加载、事件处理以及回调机制,主菜单场景能够灵活响应用户操作。按钮的交互效果和弹窗的设计都使得界面更加直观和富有层次感,为玩家提供了良好的操作体验。
操作介绍场景(DescribeScene)通过分页式设计展示游戏操作指南,其页面内容和按钮的渲染方式与主菜单场景大体相同。不一样的是,由于需要介绍的游戏内容较多,操作介绍场景的内容需要进行翻页处理才能完成,这就需要实现一个双页切换机制。可以通过设计一个current_page_状态变量(取值为1或2)控制当前显示页面。左右箭头按钮点击时触发页数增减操作,并限制边界值。其中的关键代码如下:
if (check_hover(x, y, 110, 330, 68, 68) && current_page_ > 1)
else if (check_hover(x, y, 1100, 330, 68, 68) && current_page_ < 2)
|
---|
最后操作介绍场景的实现效果图如下所示:
图5-5 操作介绍场景效果图
背景介绍场景用于展示游戏世界观与剧情动画,通过GameIntroScene类实现长视频播放、精细控制与多模态交互。由于背景介绍场景的主要功能和启动动画场景相同,都是播放视频动画,所以背景介绍场景的视频解码与渲染流程和音视频同步的功能实现大体上还是与启动动画场景的代码逻辑相同。只是由于背景介绍场景的视频长度稍长,所以在该场景添加了进度条功能和视频暂停功能。关键技术细节如下:
(1)视频播放控制体系
支持进度条拖拽(区域0×680×1280×40)、键盘左右箭头±10秒定位及空格键暂停功能。进度时间戳通过TTF_RenderText_Blended实时渲染,格式化为”MM:SS / MM:SS “,核心代码:
// 进度跳转逻辑 double newTime = ((double)(x - progressBarBgRect.x) / progressBarBgRect.w) * totalDuration; videoplayer->seek(newTime); // 时间文本渲染 sprintf_s(timeText, “%02d:%02d / %02d:%02d”,
SDL_Surface* textSurface = TTF_RenderText_Blended(progressFont, timeText, textColor); |
---|
(2)主时钟同步策略
以音频时钟为基准,当视频超前时插入动态延迟(计算公式:delay_ms = (diff - 0.1) * 1000),落后时启动连续丢帧机制。同步精度控制在±20ms内,显著提升视听一致性:
if (fabs(diff) > 0.1) {
} |
---|
最后实现的背景介绍场景的效果图大体上如下所示:
图5-6 背景介绍场景效果图
游戏的关卡选择场景(SelectorScene)需要在实现关卡动态切换功能的同时,还要实现游戏关键参数关卡序号(current_level)的传递。其中,关卡的动态切换负责的是场景的视觉表现效果,需要通过定义视差滑动动画和动态视觉焦点系统实现。视差滑动动画通过采用animation_progress_参数(0.0-1.0)控制关卡缩略图的视差位移。然后计算中心关卡与相邻关卡的相对位置偏移量,实现平滑过渡。动态视觉焦点系统则是使中心关卡与其他关卡采用不同的亮度与缩放比例,强化视觉层级。
而游戏关键参数的传递是负责游戏逻辑的处理,只有关卡选择场景能够正确的生成关卡序号并传递到游戏场景中,游戏场景才能通过关卡序号实现各个关卡数据的正常的加载。
关卡选择场景的核心代码如下:
//视差滑动动画 float offset = i - animation_progress_; // i=[-1,0,1] int x_pos = center_x + static_cast //动态视觉焦点系统 float scale = (i==0 && !animating_) ? 1.0f : 0.8f; int brightness = (i==0 && !animating_) ? 255 : 100; SDL_SetTextureColorMod(…, brightness, brightness, brightness); //参数传递机制 SceneManager::SwitchScene(SceneType::GAME_SCENE, (void*)(current_level_ + 1)); |
---|
实现的关卡选择场景的效果图大体上如下所示:
图5-7 关卡选择场景效果图
本次塔防游戏的游戏场景(game_scene)的地图设计采用了基于瓦片图层的分层渲染方法,在游戏中,将一张地图分为一个个大小相同的单元格Tile(瓦片),每个单元格都储存着该单元格的地图数据信息,其内部记录了地形(terrian)、装饰(decoration)、方向(direction)和特殊标识(special_flag)等信息。这些数据被存储在一个二维数组TileMap中,便于后续在不同层级上进行渲染和逻辑处理。图5-1展示了该分层系统的编辑器界面结构。
游戏地图的数据信息被按功能划分为四类独立层,分别是:
地形瓦片层,用于构建基础的地貌;
装饰瓦片层,用于填充环境细节;
行进路线层,主要用于记录敌人的移动路径;
特殊标识层,用于标记交互节点或关键位置(如防守核心与敌人刷新点)。
这些独立层的前两者负责视觉呈现,后两者承担逻辑运算。开发者通过这种分层设计,可以在渲染时将绘制的负担分散到不同层级,这样既降低了单帧绘制的压力,又为后续的色彩调整或局部优化提供了便利。例如,在修改某一层的视觉效果时,无需重新渲染整个场景,从而提高了开发效率和系统响应速度。
游戏地图数据的构建依托于Map类(参见 map.h),该类负责从外部CSV文件中读取并解析瓦片数据。读取过程中,每一行字符串经过预处理后,根据预定的分隔符拆分为若干数值,这些数值依次映射到 Tile 对象的各个属性。具体而言,若读取到的数据不足四项,则会采用默认值对缺失部分进行补全,确保每个Tile都具备完整的数据信息。
图5-9 CSV瓦片地图数据图
在地图加载完成后,Map类进一步调用generate_map_cache()函数对整个TileMap进行遍历。该函数不仅查找并记录了特殊标识为“0”的单元格(代表防守核心的位置),还将其他特殊标志的瓦片作为敌人生成点,通过构建路径信息(参照Route类)为后续的敌军路径规划提供支持。核心代码示例如下:
void generate_map_cache() {
} |
---|
这种游戏场景的实现方式不仅确保了地图数据的准确加载和解析,还通过对特殊瓦片的快速定位,有效地支持了游戏中动态场景的逻辑计算。并且,在游戏关卡加载时,还可以借助config_manager.h中统一配置数据的管理方式,在后续的调试和关卡设计中灵活调整各个层级的数据,从而实现对游戏场景的精细控制。
图5-10 关卡选择场景效果图
综上所述,游戏开发者在场景设计中,可以通过对场景进行分层渲染和瓦片数据的高效读取,来保证游戏的渲染性能,同时也能够为后续的功能扩展和效果优化打下坚实的基础。
通过数组在config.json对游戏窗口和各种角色的属性进行配置,包括窗口的大小、名字,以及各种角色(玩家,防御塔,敌人)的攻击力、生命值等等。这样可以统一更改各个角色的数值信息。核心代码如下:
{
“enemy”: {…} } |
---|
(1)防御塔放置功能的实现
定义了一个名为PlacePanel的类,实现了通过一个游戏面板,用于在游戏界面上显示和选择不同类型的塔(Axeman、Archer、Gunner),并允许玩家在选定的地图上放置这些塔。根据玩家选择的塔类型和当前金币数量,通过TowerManager在地图上放置塔,并通过CoinManager扣除相应的金币。
其放置防御塔的核心代码如下:
void on_click_top_area() override {
} |
---|
(2)防御塔升级功能的实现
通过定义UpgradePanel类提供一个游戏内的升级面板,用于显示和处理不同类型塔(如斧头兵、弓箭手和枪手)的升级操作。这个面板显示每种塔的升级费用,并在玩家点击相应的区域时,如果玩家有足够的金币,则执行升级操作并扣除相应的金币。其核心代码如下:
其升级防御塔的核心代码如下:
void on_click_top_area() override {
} |
---|
在PlayerManager类中定义两个主要函数:on_input和on_update,它们共同控制了巨龙的输入响应、移动、动画更新、攻击释放以及与游戏世界中其他元素(如敌人、金币)的交互。
通过on_input输入,处理监听键盘事件,根据按下的键(A、D、W、S、J、K)设置角色的移动方向或触发既能动作,当相应键被释放时,停止对应的移动。
通过on_update更新巨龙移动方向和位置,更新角色的魔力值自动回复计时器和其他技能的冷却时间计时器。如果角色,若拾取到金币,则增加玩家的金币数量并播放拾取音效。
巨龙移动的核心代码如下:
} |
---|
定义了一个名为Enemy的类,通过Animation类实现动画状态机管理,依据敌人当前行为状态(移动方向、受击标识、攻击状态)动态调整对应的动画序列。基于Vector2类的二维坐标系运算,建立包含位置坐标、速度矢量、朝向角度的运动系统,使敌人能够在游戏世界中移动,并根据预设的Route更新其目标位置。
在属性管理维度,通过config.json封装了不同类型敌人的生命值、移速系数、伤害值等核心参数,在enemy.h中封装了受到伤害、生命恢复、技能释放等交互行为的协议接口。通过on_render方法集成双图层渲染管线:上层基于当前动画帧序列生成敌人图像,下层通过动态血条方法实时映射生命值状态。其核心代码如下:
Enemy() {
} void on_update(double delta) {
} void on_render(SDL_Renderer* renderer) {
|
---|
定义了一个名为Bullet的类,通过set_position和set_velocity方法,可以分别设置子弹的位置和速度。使用set_damage方法允许设置子弹对敌人造成的伤害值。用can_collide方法用于检查子弹是否可以进行碰撞检测,并通过从ResourcesManager获取音效池,发生碰撞后并播放与ResID::Sound_ShellHit相关联的音效。
子弹碰撞音效的核心代码如下:
void on_collide(Enemy* enemy) override {
} |
---|
定义一个名为CoinManager的类,用于管理游戏中的硬币属性。通过increase_coin和decrease_coin方法来增加或减少硬币数量,并确保硬币数量不会小于0。同时在on_update方法中,遍历所有硬币属性,调用它们的on_update方法进行更新,并移除标记为可删除的硬币属性对象。在on_render方法中,对硬币进行渲染。
硬币数量的更新渲染的 核心代码如下:
void increase_coin(double val) { num_coin += val; }
|
---|
定义了一个名为WaveManager的游戏管理器类,它是用于管理游戏中的 “波次”的,包括控制游戏中波次的开始、进行和结束。每个波次包含一系列敌人的生成事件。同时,根据配置在特定的时间间隔内生成敌人。这些生成事件由EnemyManager处理。当玩家清除一个波次中的所有敌人时,根据波次的配置,通过CoinManager增加玩家的金币。最后,跟踪游戏是否结束(is_game_over)和玩家是否赢得游戏(is_game_win)。在游戏中主要通过定时器使用,利用Timer类来控制波次的开始和敌人的生成。
波次生成核心代码如下:
WaveManager() { timer_start_wave.set_one_shot(true);
|
---|
敌人寻路算法是塔防游戏中的核心功能之一,它决定了敌人如何从生成点穿越复杂的地图到达目标点,直接影响了游戏的策略性与性能表现。
现有的寻路方法大体上有两种,一种是基于A*算法的动态寻路算法,例如:在Unity3D的2D塔防游戏开发中,通过Unity3D实现了分层寻路机制:普通敌人依赖路径点(Waypoints)数组沿固定路线移动,而高优先级敌人采用APathFind插件动态规划路径[17]。该方案虽能提升路径多样性,但A算法的实时计算开销限制了大规模敌人场景下的流畅性。
另一种就是基于洋流图实现的预烘焙洋流图寻路算法,他是通过静态预生成的路径,由地图设计者预先定义了敌人的移动方向,不支持实时更新路径,但是算法复杂度低,占用资源少。
考虑到本次塔防游戏的项目特性,由于游戏地图的路径是在地图渲染时就已经确认了的,不需要实时更新路径,所以采用了算法负杂度更低,占用内存资源更少的预烘焙寻路算法,从而更好的节约资源,提高游戏性能。
在项目中通过地图编辑器标记瓦片方向属性(Tile::Direction),预生成路径索引列表(idx_list)。敌人运行时仅需按预存方向推进坐标,无需实时计算路径。具体设计逻辑如下:
(1)路径生成算法
Route类通过构造函数接收地图数据(TileMap)与起始点索引(idx_origin),遍历瓦片的方向标记生成完整路径。生成路径的具体流程如下:
首先,初始化路径索引列表(idx_list),并将起始点加入列表;
然后,根据当前瓦片的direction属性(上/下/左/右)更新下一个目标索引(idx_next);
其次,检测目标索引是否超出地图边界或与已有路径重复,若满足条件则终止路径生成;
最后,循环推进直至遇到特殊标记为0的防御水晶瓦片或无效方向标记。
敌人路径生成的核心代码如下:
|
Route(const TileMap& map, const SDL_Point& idx_origin) {
size_t width_map = map[0].size();
size_t height_map = map.size();
SDL_Point idx_next = idx_origin;
while (true) {
if (idx_next.x >= width_map || idx_next.y >= height_map) break;
if (check_duplicate_idx(idx_next)) break;
else idx_list.push_back(idx_next);
const Tile& tile = map[idx_next.y][idx_next.x];
if (tile.special_flag == 0) break;
switch (tile.direction) {
case Tile::Direction::Up: idx_next.y–; break;
case Tile::Direction::Down: idx_next.y++; break;
case Tile::Direction::Left: idx_next.x–; break;
case Tile::Direction::Right: idx_next.x++; break;
default: break;
}
}
}
|| :- |
(2)防重复与边界检测
为了防止路径出现死循环,还在Route类中实现了路径去重复功能。在游戏中通过check_duplicate_idx方法遍历idx_list检测目标索引是否已存在。若存在重复,则终止路径生成,确保敌人行进路径的唯一性。其实现代码如下:
bool check_duplicate_idx(const SDL_Point& target_idx)//检测是否有 重复的点防止路径重合 {
} |
---|
通过Route类的设计,敌人能够根据动态生成的路径在地图上智能地移动。该功能不仅增强了游戏的策略性,还使得敌人能够在复杂的地图中避开障碍,调整玩家的防守布局。通过路径去重和方向控制,游戏中的敌人行为更加多样化,增加了游戏的可玩性和趣味性。
防御水晶作为游戏的核心防守目标,其生命值管理由HomeManager类实现。该类同样通过单例模式确保全局唯一访问,主要功能包括生命值扣减、状态同步与音效触发。
(1)生命值管理机制
初始化时HomeManager类会加载初始生命值。当敌人接触防御水晶时,调用decrease_hp方法扣减生命值。若生命值≤0,设置游戏状态为失败,在受到攻击时会播放音效。实现其功能的核心代码如下:
void decrease_hp(double val) {
} |
---|
(2)状态重置功能
游戏重启或关卡重载时,调用reset方法将生命值恢复至初始值,确保状态一致性:
reset() {
} |
---|
(3)数据封装与访问
通过get_current_hp_num方法对外暴露当前生命值,供UI模块实时渲染血条状态,增强玩家对防守压力的感知。
double get_current_hp_num() {
} |
---|
总之,通过HomeManager实现了防御水晶的受击功能的全局状态管理,带来了更好的游戏攻防互动体验,增添了游戏的游玩乐趣。
定义了一个名为Banner的类,用于在游戏结束时显示一个包含背景和前景文本的横幅。在on_update方法中,根据游戏是否胜利(通过ConfigManager获取),选择胜利还是失败的相应的前景纹理,并始终使用相同的背景纹理。同时,更新计时器的状态。
图5-3 游戏结算画面图
游戏结算banner图的核心代码如下:
|
---|
由于游戏为自主研发,功能模块多,逻辑复杂,所以需要较长的开发周期,在开发过程中不可避免的产生一些bug,为了保证游戏质量,确保游戏正常运行,要需要对游戏所有功能进行详细的测试,并根据测试结果,进行优化。
游戏测试工作可以从两方面进行测试,一方面为游戏总体功能测试,根据游戏最初设计方案,对设计方案预期功能进行测试,以确保游戏可以按预期设计方案所设计功能相同,达到预期效果。另一方面为游戏性能测试,选择不同性能,不同配置,不同操作系统进行测试,在根据测试结果,进行性能优化,确保游戏的正常运行[18]。本章将从功能测试和性能测试两个方面展开叙述。
游戏功能测试主要针对游戏不同模块的具体功能进行测试,测试主要从游戏启动,加载游戏,角色载入功能等进行测试,并对每一部分功能进行详细测试,观察是否符合预期要求,表6-1记录需测试的UI功能与实际输出结果。
表6-1 游戏UI测试
功能点 | 输入或操作 | 期望输出 | 实际输出 |
---|---|---|---|
启动游戏 | 在PC端启动 | 顺利启动 | 游戏成功启动 |
启动动画 | 在PC端启动 | 动画顺利播放 | 动画播放成功 |
UI界面载入 | UI界面显示 | UI界面显示成功 | UI界面正常显示 |
按钮交互 | 点击游戏各个按钮 | 执行按钮逻辑 | 按钮逻辑执行成功 |
玩家载入 | 进入游戏关卡 | 玩家角色显示 | 游戏玩家正常显示 |
敌人载入 | 进入游戏关卡 | 敌人成功生成 | 敌人生成成功 |
游戏通关界面展示 | 游戏通关 | 播放通关动图 | Banner图正确显示 |
游戏失败界面展示 | 游戏失败 | 播放失败动图 | Banner图正确显示 |
结束游戏 | 点击退出 | 游戏场景关闭 | 游戏场景正常关闭 |
为了测试游戏功能的具体实现与人物攻击效果、交互效果的实现,观察游戏输出逻辑是否符合预期要求,表6-2对游戏的总体功能进行了测试,确保测试中游戏运行流畅稳定,没有卡顿现象以及异常退出情况。
表6-2 游戏其他功能测试
游戏开发要尽力做到小巧强悍,应当尽量避免字符串操作,所以采用将必要字符串设置为枚举值,同时通过可继承单例模板类的方法,尽量减少了字符串的处理操作,减少内存的浪费。
该方案通过模板技术实现可继承的单例模式,其核心目标是将单例特性从具体类中解耦,使子类在继承时能自动获得单例能力。相较于传统单例模式仅适用于特定类型,该模板类支持派生出多个具有独立单例特性的子类,同时保留继承体系的扩展性。
在实际的游戏开发中,这种设计常常用于管理需要保持全局唯一性的系统模块。例如本次塔防游戏项目中的防御塔管理器、子弹管理器、敌人管理器、场景管理器等,这些组件通常需要严格保证运行时仅存在单一实例。通过设计单例模板基类,然后通过具体子类对模板进行继承,开发人员无需为了每个模块的实现而重新单独构建逻辑,既可确保实例唯一性,又能通过模板参数约束实现类型安全的访问接口。
在本次塔防游戏的项目开发中,通过最终的项目验证,可以发现可继承单例模板方案能有效降低重复代码量,让开发人员能够在很大程度上避免因重复功能的手动实现差异,而导致破坏线程安全的问题。并且,在项目开发中使用可继承单例模板也可以减少内存的占用,单例模板类可以确保同一个类型的对象只会被创建一次,减少了内存的浪费,避免了多次创建同一对象所产生的额外开销。
其中,实现可继承单例模板类的核心代码如下:
template class Manager { public:
private:
protected:
}; template T* Manager |
---|
在游戏的测试和调试环节,为了确保游戏在各种硬件环境下都能够流畅地运行,需要对游戏进行整体的性能优化和调试。这涉及到多个方面,例如启用硬件加速、进行资源的重复利用、优化渲染算法、合理分配内存等。
在本次塔防项目使用FFmpeg库的音视频处理功能时,就通过使用启用硬件加速、优化渲染算法的方法来进行了性能优化,通过多线程架构与资源复用策略提升系统效率。
首先,在启用硬件加速方面,通过DXVA2硬解后,大大降低了1080P视频解码CPU占用率。然后,是游戏对于纹理池的重复利用,通过预生成纹理对象池减少内存碎片,同时缓存中间结果和避免重复计算,确保每一帧都能尽量减轻处理负担,提升渲染帧率。最后,是渲染的动态降级,当系统识别到是低端设备时,会自动降低分辨率至720P渲染,保障30fps流畅播放。以下是音视频处理进行性能优化的部分核心代码:
// 多线程解码与渲染(GameIntroScene::on_update) std::thread decode_thread([&]{
}); // 动态分辨率适配(VideotitleScene::on_render) if (system_perf_score < threshold) {
} |
---|
此外,内存的分配与管理也是游戏优化工作中的重点。内存合理的分配和及时释放能够有效防止内存泄漏和碎片化而产生的各种问题。在开发过程中,可以利用析构函数来管理各类动态分配的资源(如纹理、模型和音频等),确保当资源对象不再需要时,将其妥善释放,从而避免资源耗尽,提升系统整体的稳定性。
其中,析构函数的核心代码如下:
|
---|
通过这些措施,游戏开发者能够在各个环节上进行针对性的优化和调试,从而有效提升游戏的运行效率和稳定性。
在本次基于C++和SDL的2D双人塔防游戏开发与实现过程中,在游戏架构设计、核心玩法实现、性能优化等方面取得了较好的效果。本文的主要工作包括:
(1)游戏架构设计与实现
本项目成功构建了游戏的基础架构,通过模块化设计方法完成了地图生成、防御塔的建造升级与销毁、敌人的生成与行进路径规划等塔防游戏的核心功能。同时,精心设计了双人协作与对抗的交互模式,实现了双方资源管理、防御策略协同或对抗的功能。采用状态机模式管理游戏流程,使得场景切换更加高效且便于扩展。并设计了基于cJSON的配置管理系统,实现关卡数据、角色属性、塔防升级机制的灵活调整。
(2)核心玩法机制与优化
在本次项目开发的过程中,对游戏的玩法机制进行了优化。游戏的玩法机制采用双人协作的模式,让两名玩家分别操控巨龙与防御塔,增强了游戏策略性和互动性。同时,在游戏中对防御塔的攻击模式上进行了创新,设计了多样化的防御塔类型和伤害计算方式,增强了游戏的趣味性和策略性,完善了玩家与游戏之间的交互体验。
在游戏优化上,结合项目实际,运用了合适的矩形碰撞检测算法处理防御塔、敌人和地图元素之间的碰撞关系,保障游戏场景的合理性和真实性。并且,通过预烘焙洋流图算法实现敌人的智能寻路,确保它们能沿着预定路径向目标行进。
(3)性能优化与稳定性保障
在本项目的游戏资源加载方面,通过纹理复用与资源池管理减少了游戏的内存占用,提高了游戏的运行效率。在游戏的渲染处理中,采用SDL的硬件加速策略,确保了1080P分辨率下,游戏能够稳定运行在60FPS。在音视频处理中,项目结合了FFmpeg与SDL,实现了音视频的音画同步,提高了音效与画面渲染的协调性。
经过本次的开发与实践,尽管取得了一定的成果,但仍存在一些可优化的地方,例如:
人工智能的增强
随着AI的发展,可以进一步优化敌人的行为模式,使其更加智能化。本项目的敌人的行为方式和属性变化都相对固定,玩家玩到到后期容易产生重复感,失去兴趣。
多人联机功能
当前游戏支持本地双人模式,未来可扩展为在线多人协作模式。
用户体验方面
仍有提升空间,未来可以在UI方面加强设计,也可以进一步优化界面交互和画面的渲染效果,加入更多的游戏特效,特别是防御塔攻击时的光效和敌人被击败的动画,现在虽然有了一些击败音效,但是看起来仍不够流畅美观。
综上所述,本研究探索了C++与SDL在2D塔防游戏开发中的应用,并提供了一种双人协作的创新玩法。希望本研究的成果能为未来的塔防游戏开发或其他游戏的模块化开发提供一定的参考,为双人合作类游戏的设计提供新的思路。
- 第55次《中国互联网络发展状况统计报告》发布[J].传媒论坛,2025,9(02):121.
- 张越,陶俊,徐迅.基于Unity3D的塔防类游戏的设计与实现[J].现代信息科技,2021,5(1):84-87.
- 博研咨询.中国塔防手机游戏行业市场规模及预测分析报告[R].北京:博研,2024.
- 王异帆.基于Cocos2d-x游戏引擎的塔防类手机游戏框架设计与实现[D].华中师范大学,2015.
- 柏操.基于深度强化学习的塔防游戏防御模型的设计与实现[D].大连理工大学,2021.DOI:10.26991/d.cnki.gdllu.2021.003303.
- 王梓嘉琪,孙炼.基于C++的回合制战斗系统Combat的设计与实现[J].电脑知识与技术,2022,18(16):95-96+102.
- 缑通旺.基于FFmpeg的Web音视频处理系统的设计与实现[D].东南大学,2023.
- Angkoso V C ,Very C A ,Ari K , et al.Optimising the tower-defense games with advanced local cultural content and a greedy algorithm[J].Journal of Physics: Conference Series,2020,1569(2):022067-.
- 付梦远,刘青峰.基于unity3D塔防类手机游戏的设计与制作[J].中外企业家,2020,(09):240.
- 刘骏尧.基于Unity3D的策略养成类游戏设计与实现[D].吉林大学,2017.
- 王林语.基于FFmpeg和SDL的嵌入式多媒体终端实现[D].武汉工程大学,2017.
- Newzoo.Global Games Market Report [R].Newzoo,2023.
- Entertainment Software Association.Essential Facts About the Video Game Industry[R].Entertainment Software Association,2022.
- Statista.Global Social Gaming Market Analysis[R].Statista,2022.
- 董全立.基于IOS平台塔防游戏系统的设计与实现[D].华中科技大学,2013.
- 苏雄,张宏桥,段凌飞,等.基于C语言的跨平台2D游戏框架设计[J].现代计算机,2021,(21):152-157.
- 张宝宝.基于Unity3D的2D塔防游戏设计与实现[J].现代信息科技,2021,5(07):71-73
- 路宜松.基于Unity引擎的2D角色扮演游戏的设计与实现[D].沈阳理工大学,2021.DOI:10.27323/d.cnki.gsgyc.2021.000043.