上一篇:Xcode与C++之游戏开发:创建环境

2D 图形

今天电视、电脑显示屏、手机、平板电脑用的显示图形基本都是光栅图形,我们常称之为位图。这些屏幕由像素点构成,每个像素点代表了不同颜色。分辨率就是像素点方格的宽度和高度。例如,1920 × 1080,即1080p,意味着有1080行的像素点,每行由1920个像素点组成。类似的,3840 × 2160,即4K,意味着每行有3840个像素点,总共由2160行。

每个像素的色调最常见的就是将红色®、绿(G)、蓝(B)三种颜色混合在一起。三种颜色不同强度的组合,形成了色域。要使显示器显示 RGB 图像,显示器必须知道每个位置上像素的颜色。除了 GRB 之外,很多游戏内部都会用 alpha 值来控制透明度。

颜色缓冲区

在计算机图形中,颜色缓冲区是内存中包含整个屏幕颜色信息的内存区域。显示屏可以使用颜色缓冲区在屏幕上绘制内容。将颜色缓冲区视为二维数组,其中每个 (x, y) 索引对应于屏幕上相应位置的像素。在游戏循环“生成输出”阶段的每个帧中,游戏都会将图形输出写入到颜色缓冲区。

颜色缓冲区的内存使用率取决于色彩深度(color depth),即储存1像素的颜色所用的位数,它也称为位/像素(bpp)。举个例子,一个24比特的颜色深度,红、绿、蓝每个使用8个bit。意味着有 2242^{24}224 或者说 16,777,216 种独一无二的颜色。如果游戏还要另外使用8位来存储 alpha 值,每个像素总共需要32位来存储。

一个1080p(1920 × 1080)的图像,每个像素点32位,那么大概需要的内存空间就是1920 × 1080 × 4 bytes,大概是 7.9 MB。一些现代游戏使用16位来表示 RGB 的每个组成,这可以增加颜色的数量。当然,这将导致内存的使用量是原来的两倍,一张1080p的图像就接近16MB。不过现在显卡的显存基本都有几千MB,这个使用量还是显得微不足道。

色彩的表示

要在代码中表示颜色,通常有两种方法。假如给定一个8bit的颜色值,一种方法是简单的使用非负整数值去代表每个颜色(通道,channel)。8bit色彩深度的通道,值就介于0到255之间。另外一种方法就是将这个值规范化到0.0到1.0之间。

使用浮点数的一个好处是可以不用过分地关注色彩深度。举个例子,RGB 颜色(1.0, 0.0, 0.0)是一个纯粹的红色。在8bit色彩深度下表示成非负整数是(255, 0, 0),但是如果是在16bit的色彩深度下,它不再是纯红色,而接近黑色。

在这两种表示之间转换是很简单的。给定一个非负整数值,除以非负整数的最大值就可以获得规范化的浮点数。给定一个颜色的浮点数表示,乘以非负整数的最大值,就可以获得非负整数的表示形式。

SDL 接受的是非负整数的表示形式

双缓冲

屏幕刷新的频率可能不同于游戏刷新的频率。有的显示屏刷新的频率是 59.94 Hz,这就意味着它比每秒60次的刷新频率要低。有的显示屏刷新频率支持 144Hz 的刷新频率,这比游戏的刷新频率的2倍还多。

此外, 目前的任何显示技术都不能立即更新整个屏幕。总是有一些更新顺序——是逐行、逐列等等。假设游戏写入颜色缓冲区,同时从相同的颜色缓冲区中读取颜色的来显示。由于游戏帧速率的计时可能与显示器的刷新率不匹配,因此有可能还在游戏正在写入缓冲区时同时在读取颜色缓冲区。这是有问题的。

很容易想到的一个问题就是游戏正在写入 b 帧,用来覆盖颜色缓冲区中的 a 帧。然而,还没等 b 帧写入结束,该画面就被读取,造成只显示部分的 a 帧和部分的 b 帧。这种现象称为画面撕裂(screen tearing)。

要解决画面撕裂的问题,可以采用双缓冲区。将游戏写入的颜色缓冲区和屏幕读取的颜色缓冲区分开,交替的读取和写入这两个缓冲区。一般游戏写入的缓冲区叫后缓冲区(back buffer),而屏幕读取的是前缓冲区(front buffer)。可是,双缓冲区本身并不能解决画面撕裂的问题。如果要显示 x 缓冲区的时候,游戏要写入该缓冲区。这种情况通常发生在游戏更新过快的时候,一样会导致画面撕裂。

解决这个问题的方法是同步,交换缓冲区的时候必须等到显示完成。换句话说,游戏必须等到屏幕显示完成才能开始写入。这被称为垂直同步(vertical synchronization, vsync),由显示屏发送刷新的信号。

在垂直同步的情况下,有可能游戏刷新需要等待更长的时间。这就意味着游戏循环可能达不到 30 或 60 FPS。这可能是有的玩家无法接受的帧速。因此,是否启用垂直同步不同游戏、不同用户的选择可能不同。一个好主意是在引擎中提供 vsync 作为一个选项,这样就可以在偶尔的屏幕撕裂或偶尔屏幕卡壳之间做出选择。

现在,一些高端的显示屏采用了新的显示技术,可以做到自适应刷新频率(adaptive refresh rate),保持和游戏的刷新率一样以避免同步问题。当然,这种屏幕很贵。iPad Pro 现在就支持这种显示技术,根据浏览的内容自动调整刷新率,既可以保证流畅的体验,又节约能源。

实现基本的 2D 图形

SDL 有一组简单的函数可以实现 2D 图形的绘制。为了使用 SDL 的图形代码,需要通过 SDL_CreateRenderer 来构造 SDL_Renderer渲染器(renderer)支持绘制 2D 和 3D。在这之前,先在 Game 类中添加 mRenderer 作为成员变量,同时在构造函数中增加 nullptr 的默认初始化:

  // 渲染器SDL_Renderer* mRenderer;

Game.cpp 中:

Game::Game()
:mWindow(nullptr)
,mRenderer(nullptr)
,mIsRunning(true)
{}

下一步,在初始化 Game::Initialize() 时,同时初始化渲染器。

  // 创建渲染器mRenderer = SDL_CreateRenderer(mWindow,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);if (!mRenderer){SDL_Log("创建渲染器失败: %s", SDL_GetError());return false;}

第一个参数是显示的窗口。第二的参数是用来指定驱动程序的索引,如果游戏有多个窗口,这可能是需要考虑的。不然的话采用 -1 由 SDL 来决定。SDL_RENDERER_ACCELERATED 是采用硬件加速,SDL_RENDERER_PRESENTVSYNC 就是用来保持刷新率一致的。

还有另外两个标志:SDL_RENDERER_SOFTWARESDL_RENDERER_TARGETTEXTURE,见 API 文档

检验创建是否成功的手法和前面创建窗口时是一样的。最后,我们需要在离开的时候手动销毁渲染器。通常析构(销毁)顺序和构造顺序相反,因此先销毁渲染器,再销毁窗口。

void Game::Shutdown()
{SDL_DestroyRenderer(mRenderer);SDL_DestroyWindow(mWindow);SDL_Quit();
}

渲染 Tiffany 蓝

有一种蓝,代表着一种浪漫与幸福。有一种蓝,它每的一个细节和理念,都始终只诠释两种东西,这两种东西,一种叫爱,而另一种叫美。这种蓝,就叫做Tiffany(蒂芙尼)蓝。

任何游戏图形库绘制图形时都包含这三个步骤:

  1. 清空后缓冲区的颜色(当前游戏的缓冲区)
  2. 写入整个游戏的场景
  3. 交换前后缓冲区

渲染图形属于最终的输出,我们把这部分代码放到 Game::GenerateOutput 之中。要清除后缓冲区,需要用 SDL_SetRenderDrawColor 先指定一种颜色。这个函数接受一个渲染器的指针,和RGB色值(0到255)外带一个 Alpha 透明度。Tiffany 蓝的 RGB 色值是(129, 216, 209)。

void Game::GenerateOutput()
{// 设置 Tiffany 蓝SDL_SetRenderDrawColor(mRenderer,129,           // R216,            // G209,            // B255             // A);
}

接着,调用 SDL_RenderClear 清理后缓冲区,最终用 SDL_RenderPresent 交换前后缓冲区:

  // 清理后缓冲区SDL_RenderClear(mRenderer);// 交换前后缓冲区SDL_RenderPresent(mRenderer);

最终

现在,编译运行项目,就可以看到这浪漫幸福的蒂芙尼蓝了:

下一篇:Xcode与C++之游戏开发:Pong游戏

Xcode与C++之游戏开发: 2D图形相关推荐

  1. Xcode与C++之游戏开发:精灵(Sprite)

    上一篇:Xcode与C++之游戏开发:游戏对象 预备动作:请按照第一篇,搭好一个黑框窗口,然后按照第二篇完成基本渲染器,按第三篇完成增量时间.本篇有大量代码,请有一定的耐心. 精灵 精灵是2D游戏中的 ...

  2. Xcode与C++之游戏开发:Pong游戏

    上一篇:Xcode与C++之游戏开发:2D图形 接下来在前两天游戏骨架的基础上实现一个经典的乒乓球(Pong)游戏.游戏是这样的,一个球在屏幕上移动,玩家控制球拍来击打球.可以说乒乓球游戏是游戏开发者 ...

  3. Xcode与C++之游戏开发: 游戏对象

    上一篇:Xcode与C++之游戏开发:Pong游戏 游戏对象 在前面的 Pong 游戏中,没有用不同的类去代表墙,球拍和球,仅仅使用了一个 Game 类.像 Pong 这种简单游戏当然没问题,但它不是 ...

  4. 【269期门诊集锦】iOS游戏开发—2D游戏编程之我见

    技术门诊是51CTO社区品牌栏目,每周邀请一位客座专家,为广大技术网友解答疑问.从热门技术到前沿知识,从技术答疑到职业规划.每期一个主题,站在最新最热的技术前沿为你引航! 本期门诊特邀iOS游戏开发专 ...

  5. iPhone游戏开发:使用到的工具和技术

    本文从开发过程中使用到的工具和技术的角度,介绍了iPhone游戏开发主要用到这些技术和工具:Objective-C或C/C++, Xcode, UIKit, Quartz 2D, Core Anima ...

  6. Android 游戏开发入门

    Android 游戏开发入门 图书描述: Android系统已经红遍了大江南北,持有Android设备的人也在不断增长.看着大街上用手指划着手机玩游戏的人,你有没有一种自己做一个游戏的想法呢?然而,入 ...

  7. 第1章 高瞻远瞩一一游戏开发面面观

    1.1 逐梦--梦想让我们不孤单 1.2 游戏产业的黎明 在1993 年的冬天,大名鼎鼎的Id 游戏公司发行了作为<德军司令部3D >(最早的3 D 共享游戏软件之一,也是出自Id 公司之 ...

  8. 游戏开发主要学哪些课程?

    当盗墓笔记从小说走上影视屏幕,有一个行业也火热起来--网页游戏.从盗墓笔记到如今大热的司马懿之军师联盟,几乎每大火一部影视剧,就会有相应的网页游戏问世.由此可见游戏开发行业也成热门职业. 游戏开发需要 ...

  9. Unity和Cocos2D在2D游戏开发上的对比

    游戏开发的最好技术是什么:Unity还是Cocos? 在网上你可以找到很多这两种技术的对比.在我们开发游戏之前,我们要了解相关数据和信息并决定使用那种技术.但是人们对这两种技术的对比大多都比较主观.擅 ...

最新文章

  1. Go 语言编程 — defer 关键字
  2. 【PP操作手册】创建和下达返修生产订单
  3. 在内部局域网(无外网)使用阿里云短信
  4. docker镜像内容如何查看_如何快速打通 Docker 镜像发布流程?
  5. 解决pycharm安装包过程出现的问题:module 'pip' has no attribute 'main'
  6. Codeforces Round #670 (Div. 2)
  7. Linux OS共享文件
  8. C语言scanf中%%,C语言scanf()和gets()及printf()和puts()的区别
  9. asp.net oracle odbc,ADO.NET 连接数据库字符串小结(Oracle、SqlServer、Access、ODBC)
  10. 计算机考试系统客户端网址,[中学]计算机基础测评系统考试客户端操作步骤.doc...
  11. onenote打开闪退平板_oppo r11s安装Onenote后打开会闪退怎么弄?
  12. 如何确定今天是星期几
  13. linux OOM killer分析
  14. 联通光猫TEWA-800E设置桥接模式
  15. 煲汤C语言,煲汤秘诀,附9款排骨汤做法,总有一款适合你!
  16. Rust 从入门到精通01-简介
  17. 字符串类型的数字的加减乘除运算
  18. SQL的高级教程(一)
  19. sql数据库如何读取数据
  20. 台式计算机开始不显示,台式机连接投影仪不显示怎么办

热门文章

  1. IDEA官网进不去解决方法
  2. VTK-vtkCutter及其实现逻辑(接口讲解)
  3. mysql图片添加水印_OSS 图片添加水印 image/watermark,image_
  4. python中argsort_(学习笔记)numpy中argsort函数用法
  5. 基于VC++的记分板调度方法仿真
  6. 适合计算机科学系毕业季的话,毕业季 | 用你的专业,说最美的情话......
  7. 2. Transformer相关的原理(2.2. 图解transformer)
  8. 300元差价选谁好 魅蓝note对比魅蓝手机
  9. WIN10中使用WIN7的照片查看器
  10. 【自学Python】Python缩进规则