玩家点击一个图标的背后都发生了些什么

简介: 在之前的两篇文章中,我们首先打开了自己的“创作者之眼”,看到了消除游戏背后那张看不见的网格,想象一下你所玩过的消除游戏,是不是其中的每一个图标都遵循着网格布局在排布?接着我们继续做了进一步的修炼,将“创作者之眼”继续升级,除了那张网格,我们也看到了一些数字,这些数字就是每一个图标的标识。今天,我们继续修炼一些基本功。是的,在正式开始制作具体类型的消除游戏之前,我们需要把基本功练扎实。这样在你真正制作游戏的时候,才能够知其所以然。

嗨!大家好,我是小蚂蚁,这是消除游戏系列教程的第 3 篇。


在之前的两篇文章中,我们首先打开了自己的“创作者之眼”,看到了消除游戏背后那张看不见的网格,想象一下你所玩过的消除游戏,是不是其中的每一个图标都遵循着网格布局在排布?接着我们继续做了进一步的修炼,将“创作者之眼”继续升级,除了那张网格,我们也看到了一些数字,这些数字就是每一个图标的标识。


今天,我们继续修炼一些基本功。是的,在正式开始制作具体类型的消除游戏之前,我们需要把基本功练扎实。这样在你真正制作游戏的时候,才能够知其所以然。


在网格的那一节中,我们讲了一些基础的数学知识,再次回顾一下这张图片。


640.png


根据网格的中点,行列数以及边长,我们首先计算出了左下角的起点位置。有了起点位置,就可以根据当前的行号列号计算出每个格子的位置。


依靠着这些简单的数学知识,我们描绘出了一个网格,并且让每一个元素出现在该出现的位置。这是一个消除游戏的基础,有了这样的基础布局,才能够进行下一步的操作。


在消除游戏中,通常你需要先选中某一个图标,然后再进行后续的操作。对于玩家来讲,只需要用手指点住想要选择的那个图标即可,但是对于游戏制作者来讲,我们就需要做一些处理来确保玩家点住的就是他想点的那个图标。


两个坐标系



想要了解其中的原理,需要先了解两个不同的坐标系。


  • 屏幕坐标系

640.png

如图,中间的蓝色网格区域是消除游戏的操作区域,外围的绿色边框表示的屏幕区域,可以理解为你的手机屏幕,在屏幕区域中存在着一个坐标系,即屏幕坐标系,以屏幕的左下角为原点,假设当前的设备屏幕是 400 x 800 的尺寸,那么屏幕坐标系就如图中红色箭头标注的一样,屏幕的最右侧为 400,屏幕的最上侧为 800。

不同的游戏引擎中屏幕坐标系的原点是不一样的,有的以左下方为原点,向右向上为正方向;有的以左上方为圆点,向右向下为正方向;还有的以屏幕中心为原点;不论原点在哪里,道理其实都一样,无非是计算会稍有差异。本文以左下方为原点举例,在不同的游戏引擎中实现时需要根据具体情况做出相应的调整。


  • 网格坐标系

640.png

网格坐标系指的是针对于整个消除布局网格的坐标系,它以整个消除网格中左下角的第一个元素位置为原点,如图中紫色箭头标注的坐标系。还记得我们是如何计算出左下角第一个元素的位置的吗?忘记了的话,请回顾上方带有计算公式的图片或者回顾之前的文章。

很显然对于网格坐标系来讲,它的原点位置并不是(0,0),没有硬性的规定,坐标系的原点必须是(0,0),这一点需要清楚。


坐标系的转换



请注意,接下来我们又要涉及一点儿数学知识了,不用担心,并不难理解。

640.png

如图,网格布局左下角起点(绿色圆点)的位置我们之前已经算出来了,是(x0,y0),现在假设玩家点击了红色点的位置 (x1,y1),这个点的位置是可以知道的(不同的游戏开发工具都有提供获取屏幕点击位置的功能),这个点的位置其实是针对于屏幕坐标系的位置。


现在我们有了这样两个已知条件:

  • 当前点击的屏幕坐标的位置(x1,y1)
  • 网格坐标系左下角起点的位置(x0,y0)

根据当前的已知条件,可以计算出当前点击位置在网格坐标系中的位置,也就是图中橙色线所标注的(x2,y2)。

x2 = x1 - x0

y2 = y1 - y0

到这里为止其实我们完成了这样的一件事:将当前点击位置的坐标由屏幕坐标系转换到了网格坐标系。


为什么要去做这样的坐标转换呢?因为只有在网格坐标系中,我们才能够将位置坐标转换成对应的“行号”和“列号”,进而找到玩家到底点击的是哪个图标。


行列号的计算



接着再加入一个已知的条件,即元素的边长 n,我们就可以通过下方的计算得到当前元素在网格中的行号列号

行号 = (y1 - y0)/n + 1

列号 = (x1 - x0)/n + 1

是不是又迷糊了?我们看看下图中举出的例子,然后再对照着看这个公式。


640.png

如图,现在我们假设左下角起点的位置为(50,200),然后玩家当前所点击的屏幕的位置为(100,250),当前每个元素的边长是50。将这些已知的数值带入计算行号列号的公式:

行号 = (250-200)/50 + 1 = 2

列号 = (100-50)/50 + 1 = 2

由此可知,当前点击的是第 2 行第 2 列的图标。

根据这个例子,再回顾一个上方的计算行列号的公式,很不是就比较容易理解了呢!


容错处理



这里举的一些数值例子很方便计算,因为主要目的是帮助理解计算公式。但是在真实的游戏中,不可能总是恰到好处的得到能够整除的数字,但是很明显行列号最后又都必须是整数,此时该如何处理呢?



640.png


如图,任何一个红点的位置都是玩家可能点击的位置,有些红点的位置甚至都没有位于图标之上,对于玩家来讲这些点击应该都是有效的,因为我就是想要点第 2  行第 2 列的那个图标,我的手指可能不是很精准,但是我不管,我点的就是那个,如果图标没有被选中,不是我的问题,一定是游戏出了问题。


作为游戏创作者的我们又需要做一些事情了,来容许玩家的操作有一定的误差,我们要尽可能的保证玩家当前点击的位置就是他想要选择的图标。听起来是不是有些玄妙?怎样才能确保一定的容错率呢?怎样才能确定玩家想要选的到底是哪个图标呢?


答案就是利用“四舍五入”。又是一个在你知道真相之前感觉无比玄妙的东西,在捅破了一层窗户纸之后变得不过如此的例子。


我们利用四舍五入把计算行列数的公式改造一下,就变成了这样:

行号 = 四舍五入((y1 - y0)/n + 1)

列号 = 四舍五入((x1 - x0)/n + 1)


640.png


这里又举出了一些位置坐标,拿出计算器带入上方的计算公式,算算吧!看看是不是通过“四舍五入”之后,得到的行列号都是 2 。


是不是没想到你学过的四舍五入在游戏中竟然可以有这样的应用?竟然能够用于改善玩家的操作体验,增加游戏的操作容错率。


通过这样一个小小的改善,我们的游戏就能更具“人性化”一点,仿佛在告诉玩家:不论你的眼神儿好不好,手指点击的精不精准,都没关系,你尽管点,我知道你想点的是哪里。


元素的标识



到此为止,我们已经能够通过玩家点击屏幕的位置,经过一系列的计算,知道玩家当前要点击的元素的“行号”和“列号”了,通过行列号就能够在布局网格中找到那个对应的元素。我们可以把这个行列号叫做“元素的标识”


标识有什么作用呢?当你有很多的元素时,如果想要在其中进行精确查找的话,最好的方式就是为每一个元素分配一个唯一的标识(就像是我们的身份证号),当想要找到某一个元素时,只需要知道它的标识,就能够把它精确的找出来。


640.png

如图,我们使用行号列号作为元素的标识时,其实就是这个样子,每一个元素都有一个唯一的[行,列]号,我们也可以通过这个[行,列]号找到那个确定的元素。


使用行列号作为标识同时需要两个数字(行号和列号),通常我们还会使用另一种方式,通过行列号计算出一个“数字索引”来作为标识,这样使用一个数字就可以标识出一个元素了。

640.png

数字索引的计算公式是这样的:

索引 = (行号-1) * 总列数 + 列号


假设有 3 行 3 列元素,当前元素位于第 2 行第 1 列,那么:

索引 = (2-1) * 3 + 1 = 4

反过来根据这个数字索引,我们也能够倒推出行列号:

行号 = 向上取整(索引/总列数)

列号 = 索引 - (行号-1) * 总列数


假设有 3 行 3 列元素,当前元素的数字索引是 8 ,那么:

行号 = 向上取整(8/3) = 3

列号 = 8 - (3-1) * 3 = 2

得到它位于第 3 行第 2 列的位置。


有了上方的这两个行列号数字索引的互推公式,其实我们就可以做这样的一件事,就是把二维的数组或者表格转换成一维的数组或者列表。

640.png


只要愿意的话,你完全可以使用一个一维的数组列表实现一个消除游戏,因为它其实就是一个“压扁”了的表格。当然你没有必要这么做,除非你所使用的游戏开发工具或者编程语言对于二维数组或者表格缺乏支持。否则,你应该优先选用更直观的表格或者二维数组。举这个例子是想说明,即使是在一个处处受限的开发条件下,你仍然能够找到其他的解决方案,只要善于利用已有的资源,学会变通,其实有很多的选择。


今天的内容就到这里了,觉得不错的话,请 点赞 在看 转发鼓励我一下吧!你的鼓励对我来说价值巨大。


想学习做游戏的话,关注我的公众号就对啦!

相关文章
|
2月前
|
计算机视觉 索引
扫雷-包含空白展开,标记功能,游戏界面优化-控制台全力复刻
扫雷-包含空白展开,标记功能,游戏界面优化-控制台全力复刻
|
2月前
|
定位技术
Pyglet综合应用|推箱子游戏地图编辑器之图片跟随鼠标
Pyglet综合应用|推箱子游戏地图编辑器之图片跟随鼠标
28 0
|
2月前
|
开发工具 索引
点击一个消除游戏图标时,背后都发生了什么
点击一个消除游戏图标时,背后都发生了什么
41 1
|
小程序 开发工具 索引
玩家点击一个图标的背后都发生了些什么
在之前的两篇文章中,我们首先打开了自己的“创作者之眼”,看到了消除游戏背后那张看不见的网格,想象一下你所玩过的消除游戏,是不是其中的每一个图标都遵循着网格布局在排布?接着我们继续做了进一步的修炼,将“创作者之眼”继续升级,除了那张网格,我们也看到了一些数字,这些数字就是每一个图标的标识。
93 0
|
Java
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏03全屏显示游戏窗口
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏03全屏显示游戏窗口
133 0
|
数据可视化
搭建完菜单后运行不显示菜单的原因及其解决方法(拼图小游戏)
在搭建完菜单以后,程序不报错也能运行,但是运行结果就是一个框,就跟没有搭建过菜单一样,如下图所示,没有我们想象中的菜单栏,更别说有下拉菜单了,但是如果将搭建菜单的代码单独放到一个测试类中去测试一下的话,会显示出来菜单,也就是说我们搭建菜单的核心代码是没有问题的
133 0
搭建完菜单后运行不显示菜单的原因及其解决方法(拼图小游戏)
如何实现一个丝滑的点击水波效果
本文为Varlet组件库源码主题阅读系列第九篇,读完本篇,可以了解到如何使用一个`div`创建一个点击的水波效果。
75 0
|
缓存 运维 前端开发
从零开始实现放置游戏(十四)——实现战斗挂机(5)地图移动和聊天
上一节添加了websocket组件,实现了前后端通信。后面我们只需要根据游戏的业务逻辑,逐步实现各种功能即可。   另外,在实现具体业务逻辑时,发现上一章设计的消息对象有些不合理,由于粒度过粗,导致可以复用的部分很少,且这里的通信模型并不是一个请求对应一个响应的模式。比如:玩家a从地图A移动到地图B。此时,a发送移动请求。服务器返回B地图的信息和在线列表给A。同时还要发送最新的在线列表给地图B的其他玩家b,c,d....这里其他玩家并没有发送请求,但收到了响应消息。因此,将消息类型重构成由客户端发出的消息和由服务端发出的消息两类,分别以"3000"和"6000"开头。
从零开始实现放置游戏(十四)——实现战斗挂机(5)地图移动和聊天
|
SQL 缓存 前端开发
从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面
 本章主要实现注册登陆功能和游戏的主界面。有了游戏的界面,大家能有更直观的认识。   本章我们主要开发的是idlewow-game模块,其实就是游戏的客户端展示层。因为是放置游戏,为了方便,主要使用spring-mvc来开发,整个游戏形式是类似web端的文字mud游戏,会稍带一些图形图片。当然,游戏的客户端可以是多种多样的,也可以使用U3D开发成移动端或者C++/flash/silver light,开发成PC端、网页端、微端等等形式,但需要更多的美术资源。
从零开始实现放置游戏(十一)——实现战斗挂机(2)注册登陆和游戏主界面
C++ 使得窗口置顶(终极方案)
C++ 使得窗口置顶(终极方案)
649 0