单机斗地主项目总结

news/2024/11/23 9:26:27/

好久没写博客,最近也是闲来无事,在工作业余时间写了一个斗地主的游戏,时间好像是从4月份到8月份吧,现在在来想一想,里面涉及到的一些细节好像忘的差不多了,还是写个总结吧,以祭奠我的第一款上线的手机游戏(没啥下载量的说- -#)。

 

进入正题,要总结的知识点如下:

1、屏幕适配

2、洗牌算法

3、牌面正面翻转效果所涉及的投影相关问题(参考资料http://tonybai.com/2014/05/13/sprite-draw-principles-of-cocos2dx-screen-adaptation/)

一、屏幕适配

涉及到两个分辨率的问题,一个是开发者使用的分辨率(一般背景资源的大小和此分辨率匹配),这里定义为sizeDesignResolution,还有一个就是屏幕分辨率sizeScreenResolution(就是各种不同手机的实际屏幕分辨率),这里的适配就是要用你开发的分辨率适配用户不同手机的实际屏幕分辨率。

一般产品要上线的话,你的图片是不能变形的,采取的方法可以是:

(1)等比缩放图片

(2)在充满屏幕的前提下,尽可能的减小要被截取的图片范围

等比缩放图片,要先知道用户屏幕和开发屏幕分辨率的比例因子:

float fScale_x = sizeScreenResolution.width / sizeDesignResolution.width;
float fScale_y = sizeScreenResolution.height / sizeDesignResolution.height;


这里先介绍官方的两种等比缩放的适配方案

(1)kResolutionNoBorder,采取缩放因子大的比列缩放开发分辨率,得到视口宽高

(2)kResolutionShowAll,采取缩放因子小的比列缩放开发分辨率,得到视口宽高

举例:

CCSize sizeDesignResolution = CCSizeMake(960, 540);//开发分比率

CCSize sizeScreenResolution= CCSizeMake(1024, 768);//用户分比率

比列因子

fScale_x  = 1.067

fScale_y = 1.422

 

说明fScale_x   < fScale_y 开发分辨率的高度小了;

如果采取kResolutionShowAll,得到的是宽度缩放因子,使得fScale_x = fScale_y  = 1.067,这样只是让宽度刚好得到平铺,而高度会出现黑边,可以由它的视口大小可以看出。

视口的大小

// calculate the rect of viewport    

float viewPortW = m_obDesignResolutionSize.width * m_fScaleX = 1024;

float viewPortH = m_obDesignResolutionSize.height * m_fScaleY = 576;


如果采用kResolutionNoBorder,取较大的值fScale_x = fScale_y  = 1.422,这样可以高度可以刚好铺满屏幕,这不过图片宽度会部分被截取掉

float viewPortW = m_obDesignResolutionSize.width * m_fScaleX = 1365.3334;

float viewPortH = m_obDesignResolutionSize.height * m_fScaleY = 768.00000;


其实在这种fScale_x   < fScale_y的情况下,kResolutionNoBorder适配方案可以很好的满足上面提到的这两种适配条件,但在fScale_x   > fScale_y的情况下,kResolutionShowAll也可以满足该适配条件。

综上所述,在AppDelegate.cpp中写一个综合这两种情况的判别条件处理方法,即可以达到最终的适配要求:

        //设置开发者使用的分辨率CCSize sizeDesignResolution = CCSizeMake(960, 540);CCSize sizeScreen = pEGLView->getFrameSize();float fScale_x = sizeScreen.width / sizeDesignResolution.width;float fScale_y = sizeScreen.height / sizeDesignResolution.height;if(fScale_x > fScale_y)//设计分辨率的高度大了,高度等比缩小{CCSize sizeResolution = CCSizeMake(sizeDesignResolution.width, sizeScreen.height / fScale_x);pEGLView->setDesignResolutionSize(sizeResolution.width, sizeResolution.height, kResolutionNoBorder);}else//设计分辨率的宽度大了,将其宽度等比缩小{CCSize sizeResolution = CCSizeMake(sizeScreen.width / fScale_y, sizeDesignResolution.height);pEGLView->setDesignResolutionSize(sizeResolution.width, sizeResolution.height, kResolutionNoBorder);}

这里的setDesignResolutionSize函数中的第三个参数填写kResolutionNoBorder或kResolutionShowAll都行,因为这里的宽高比列都是一样的了。
这列有一点要注意的是,在UI布局的时候,图片边界部分包含重要按钮或其他相关图片资源时,尽量写成相对坐标,这样可以保证,每个不同的机型加载的资源都会在手机上面正确显示。


二、洗牌算法

思想:

预先保留数组,含有54个元素,并由1到54依次初始化赋值;

初始化种子,并取1~54的随机数,实现下标的数组值交换,代码如下:

         #define random(X) ((rand() % (X)) + 1)int nLoop = 54;srand((unsigned int)time(0));for(int i = 1; i <= nLoop ; i++){int rand1 = random(54);int rand2 = random(54);int temp1 = m_arrayCards[rand1];m_arrayCards[rand1] = m_arrayCards[rand2];m_arrayCards[rand2] = temp1;}

这里nLoop是交换的次数,此值越大,得到的牌就越离散(注:如果哪位知道更好的洗牌算法,可以告知)。

三、牌面正面翻转效果所涉及的投影相关问题


在进行牌翻转的时候,往往只有在居中的牌,在能够刚好实现正面翻转,而在其他位置的牌,翻转的时候往往存在一定的角度,达不到正面翻转牌的效果。

这样的问题涉及到了openGL中投影相关的知识。

OpenGL中涉及到的投影变换包含两种,一种是正射投影,一种是透视投影,在cocos2dx中默认的投影是透视投影,m_eProjection = kCCDirectorProjection3D;根据透视投影的特性,是以人眼的方式所展现的,符合人们的视觉习惯,所以在居中的地方,牌会刚好实现正面的翻转,因为相机(可以理解为人眼)的方向正好居中垂直朝向屏幕内,所以看到的图片翻转式正面翻转,而在其他地方的翻转会出现一定的角度偏差。(等会还侧重讲一下这个透视投影在cocos2dx中的展现原理)。

要解决这样的问题,可以先理解正射投影的特性:

它的视景体是一个平行的管道,并且无论物体距离相机多远,投影后的物体大小尺寸不变:

这样的特性刚好可以满足实现牌面正面翻转的功能,不管牌在什么位置,都相当于无数个正面照射牌位置的相机使之居中翻转显示(不知道这样解释有没有问题,因为正射投影中不需要设定照相机位置、方向以及视点的位置)。

CCDirector::sharedDirector()->setProjection(kCCDirectorProjection2D);

 

 

在CCDirect.cpp中,有getZEye(void)的函数

float CCDirector::getZEye(void)
{return (m_obWinSizeInPoints.height / 1.1566f);
}

下面说说这个1.1566f是怎么来的,以这个透视图来看

cocos2dx对透视投影的设置

            float zeye = this->getZEye();kmMat4 matrixPerspective, matrixLookup;kmGLMatrixMode(KM_GL_PROJECTION);kmGLLoadIdentity();#if CC_TARGET_PLATFORM == CC_PLATFORM_WP8//if needed, we need to add a rotation for Landscape orientations on Windows Phone 8 since it is always in Portrait ModekmGLMultMatrix(CCEGLView::sharedOpenGLView()->getOrientationMatrix());
#endif// issue #1334kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, zeye*2);// kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, 1500);kmGLMultMatrix(&matrixPerspective);kmGLMatrixMode(KM_GL_MODELVIEW);kmGLLoadIdentity();kmVec3 eye, center, up;kmVec3Fill( &eye, size.width/2, size.height/2, zeye );kmVec3Fill( ¢center, size.width/2, size.height/2, 0.0f );kmVec3Fill( &up, 0.0f, 1.0f, 0.0f);kmMat4LookAt(&matrixLookup, &eye, ¢er, &up);


由透视投影矩阵函数kmMat4PerspectiveProjection可以知道:

视角:60

aspect:用户分辨率的宽高比

近平面距离:0.1f

远平面距离:2*zeye

最后可以得到透视投影矩阵matrixPerspective;如果已知透视投影矩阵matrixPerspective也可以反向求的视角、宽高比等其他参数;

这里可以来看以下zEyes值的由来,先看沿着X轴负方向向zy平面投影:

很明显,这样的一个三角形式等边三角形:

cos30 = (m_obWinSizeInPoints.height / 1.1566f)/ h
h = (m_obWinSizeInPoints.height / 1.1566f)/cos30 = m_obWinSizeInPoints.height;

可以知道投影在(z=0,XY平面)的截面高度h与用户分辨率的高度相同;Cocos2d-x是2D游戏渲染引擎,针对该引擎的模型的z坐标都是0,因此模型实际上就在xy平面内,也就 是说eye与原点的距离恰好就是eye与模型的距离,而模型可显示区域的最大高度也就是h;、(但在3D游戏的渲染引擎中,eye与模型的距离不一定就是eye与原点的距离;)

 

这里知道了eye距模型的距离,但其具体的位置(x,y)还没有确定,通过上述代码可以知道,相机的位置eye(size.width/2, size.height/2, zeye),指向的位置center(size.width/2, size.height/2, 0.0f),头顶方向的位置(0.0f, 1.0f, 0.0f),并得到模型视图矩阵matrixLookup(已知该矩阵也可以逆向推出相机的具体位置)。

 

自己对投影矩阵在三维场景中的应用的一些想法:

1、已知模型的位置

2、已知投影视图矩阵

3、已知模型视图矩阵

根据模型视图矩阵==》相机参数(位置,朝向,向上方向)

根据投影视图矩阵==》视角、宽高比

视角、eye.z==》截面高度(已知宽高比)==》截面宽度(已知eye的具体位置)==》所截取模型的矩形范围(知道这个范围,可以应用与多种实际应用中,比如影像的自动贴图,视觉范围内的影像本地保持等等云云。。。)

 

这里就大致先写到这里,后续如果有新的想法在加。

 

最后贴个斗地主游戏的下载地址,想要玩的随便下:

http://apk.hiapk.com/appinfo/com.combat.playcards

 

 

 



http://www.ppmy.cn/news/392354.html

相关文章

Java实现模拟斗地主洗牌发牌

按照斗地主的规则&#xff0c;完成洗牌发牌看牌的动作。最终结果预计为&#xff1a; 具体规则&#xff1a; 1.组装54张扑克牌 2.将54张扑克牌顺序打乱 3.三个玩家参与游戏&#xff0c;三人交替摸牌&#xff0c;每人17张&#xff0c;最后三张做底牌 4.查看三人手中各自的牌&…

斗地主的两种发牌方式

作为一个初学java的菜鸟,近期在老师的指导下做了一个包含斗地主洗牌发牌的简单小项目. 我自己做的思路是直接将54张牌分成3组 17张,最后剩的3张直接给地主 首先创建两个实体类Card和Player. ![Card类](https://img-blog.csdnimg.cn/20200718182854747.png)![Player类](https://…

斗地主java实现

注&#xff1a;勿用作商业用途&#xff0c;仿照别人的源代码&#xff0c;自己实现了一下&#xff0c;仅供参考学习 项目架构&#xff1a; com包下&#xff1a; Card类&#xff1a; package com;import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.…

csol显示服务器中断请重新连接,csol服务器连接超时

弹性云服务器 ECS 弹性云服务器(Elastic Cloud Server)是一种可随时自助获取、可弹性伸缩的云服务器&#xff0c;帮助用户打造可靠、安全、灵活、高效的应用环境&#xff0c;确保服务持久稳定运行&#xff0c;提升运维效率 三年低至5折&#xff0c;多种配置可选了解详情 用户数…

封电脑机器码怎么解决_如何通过修改机器码解决游戏封号问题

相信大家都遇到过&#xff0c;游戏被封了&#xff0c;就不能玩了&#xff0c;今天给大家带来一款游戏解封的方法&#xff0c;开始我们今天的教程。 首先&#xff0c;打开硬件修改大师进行IE设置。勾选IE版本和IE产品&#xff0c;然后点击随机设置。 点击NAME&#xff0c;勾选电…

英雄联盟召唤师名封号查询

写作由来&#xff1a; 今天早上玩游戏&#xff0c;在LOL的主界面上看到了一些列被封号的名单公式&#xff0c;然后点进去看了看&#xff0c;发现名单太多了&#xff0c;根本就找不过来&#xff0c;所以自己就尝试着写了个程序去查找我想要找的召唤师名。 附上封号链接&#x…

封电脑机器码怎么解决_游戏封号解决方法之修改机器码 如何修改机器码

相信大家都遇到过&#xff0c;游戏被封了&#xff0c;就不能玩了&#xff0c;今天给大家带来一款游戏解封的方法&#xff0c;开始我们今天的教程&#xff01; 方法/步骤 一般游戏被封号&#xff0c;基本封的就是你电脑的机器码&#xff0c;所谓解码是什么呢&#xff1f;其实就是…

INS防封号技巧,这些注意事项如果你不知道容易被封号停用

最近很多小伙伴根据东哥的教程成功注册了ins&#xff0c;还没等他们玩够呢&#xff0c;就出现了账号被封的情况。为了防止更多人的ins账号被封&#xff0c;东哥花时间整理了一份ins的使用注意事项。 是东哥我酝酿了比较久的一个总结&#xff0c;这其中凝结了在INS领域实操很久的…