说明:

<学习>系列所有的源代码均由《计算机游戏程序设计》提供。本人会在这些代码中融入自己的想法,对其进行迭代优化,旨在个人学习。

实现效果:

学习目标:

1. 了解物理模拟、精灵的绘制与移动、触摸事件的应用等。

2. 熟悉基于Box2D的物理引擎。

3. 掌握Box2D触屏检测和碰撞检测机制。

修改内容:

1.优化击球方式。

2.增加一个进洞口。

3.修改球杆跟随力度变化的状态。

步骤与过程

1.完成游戏编译

老套路编译示例代码并运行程序。

图 1

2.优化击球方式

修改击球方式为:在击球区域拖动鼠标左键,可以实现球杆的瞄准以及能量的蓄积,松开鼠标左键,实现击球。

  • 仔细研究原代码,发现“在击球区域拖动鼠标左键,可以实现球杆的瞄准”这一功能原本就已经实现了,无需多做修改。
  • 而对于“在击球区域拖动鼠标左键,可以实现能量的蓄积”这一功能,只需把原来在“能量滑块区域”滑动更改为在“击球区域”中滑动即可。

因此,在拖动鼠标调用的函数onTouchMoved()中,无需再把“球杆瞄准”和“能量积蓄”两个功能分别写在“击球区”和“能量滑动区”中实现,而是统一放到“击球区”中实现即可。

此时,“当前击球能量”变量_curPower的值可更改为由“白球”的坐标和“目标点”的坐标的距离长度(为更好控制数值,可让它们再除以2)。

即curPower=(touch->getLocation()-changePos(mainBilliards->getPosition())).getLength()/2

  • “松开鼠标左键,实现击球”这一功能在原代码中也已经实现了,只不过它限定了在“能量滑动区域”的范围里。因此,只需要把这一个限定条件“_powerRect.containsPoint(touch->getLocation())” 给删掉就可以了。

修改后代码为:

图 2

图 3

图 4

3.增加进洞口

Ps一张“球洞”图片,命名为“hole”。

图 5

  • 直接利用BilliardSprite类来创建“球洞”对象,但是与创建“台球”对象不同的是,由于“球洞”不是“运动物体”而是“静态物体”,所以在create时要注意参数isStatic设置为true。

图 6

由于台球游戏一般有四个洞,所以我也给这个游戏设了四个“球洞”。所以,四个球洞除了位置的不同外,还应该有旋转角度的不同,由上图可见四个球洞精灵对象分别要旋转0、90、180、270度。但由于BilliardSprite初始化函数中没有设置精灵对象的旋转角度的代码。所以可以另外在BilliardSprite类中写一个方法函数initHole(float rotation)来设置精灵对象的旋转角度。

但要注意的是,BilliardSprite中的update函数中会不断地更新精灵的位置以及根据body的角度变化来设置精灵的旋转。但是在默认情况下,物体都是不动的,所以会不断地给精灵的旋转角度设置为0 ,这样initHole函数设置的“洞口”旋转角度就前功尽废了。如下图update代码所示:

图 7

所以,为了“球洞”精灵不受update函数的影响。我们可以在initHole函数执行this->unscheduleAllSelectors(),解除update定时器,让“球洞”维持“静止”。

而“球洞”精灵的位置,要由“球洞”物体的位置来转换而成。因此,“球洞”初始化函数initHole代码有:

图 8

  • 当“白球”进洞时,重新开始游戏。该功能实现只需要如实验三一样,在游戏主场景PhysicsBox2dScene.cpp中执行如下代码,进行与新场景的切换即可:

CCDirector::sharedDirector()->replaceScene(PhysicsBox2dScene::createScene());

于是,问题的关键就在于如何判断“白球进洞”并执行上述代码了。可给碰撞监听类GameContactListener添加一个bool类型的私有变量mainBallInHole,表示白球是否进洞,并添加该变量的get方法。

当物体间发生碰撞后,GameContactListener.cpp的BeginContact函数会被调用,该函数通过b2Contact参数获取到两个碰撞对象。因此,只需通过获取这两个碰撞对象的name并进行比对,如果是“main”和“hole”便能确定是“白球进洞”,然后再把mainBallInHole变量设为true。

而PhysicsBox2dScene.cpp的update函数中通过get方法获取到mainBallInHole变量再进行if判断,条件符合后便执行场景切换函数即可。

代码为:

GameContactListener.cpp:

图 9

PhysicsBox2dScene.cpp的update函数:

图 10

PhysicsBox2dScene.cpp:

图 11

  • 当除了白球的“普通球”进洞时,该球要消失。结合②部分可知,只需在GameContactListener.cpp的BeginContact函数中添加一个name为“ball”与“hole”碰撞的情况即可。其中,最好的实现方法莫过于把要移除的小球给记录在链表ballsRemovalList中,在时间长step执行后及场景被渲染前,执行GameContactListener的函数deleteBody来遍历ballsRemovalList,对其中记录的小球对象进行删除。

然而,由于BilliardSprite对象被调用的地方比较多,导致直接删除该对象(delete BilliardSprite*)程序报错,本人功力不够深厚没能解决这一问题。只能退而求其次,在BilliardSprite类中写一个新的函数方法deleteBody(),通过调用其来删除BilliardSprite对象中的_body以及移除_sprite 。这样做虽然不是最佳方案但也能实现同样的功能。

代码为:

GameContactListener.cpp:

图 12

PhysicsBox2dScene.cpp (要在step后执行删除操作):

图 13

GameContactListener.cpp:

图 14

BilliardSprite.cpp:

图 15

4.修改球杆跟随力度变化的状态

重点观察PhysicsBox2dScene.cpp中的函数updateLine()的“计算球杆位置”部分的代码,有如下所示:

图 16

从这个代码中我们很难看得出什么,我们对其进行展开和转换。以x轴坐标为例,即:

(((end_p - start_p).getLength() + 45) * start_p.x - 45 * end_p.x) / (end_p - start_p).getLength()

我们可以把其转化为:

start_p.x + 45 * (start_p.x - end_p.x) / (end_p - start_p).getLength()

由转换后的代码我们就比较容易看出start_p.x指白球的x坐标,而 (start_p.x - end_p.x) / (end_p - start_p).getLength() 指的是夹角的余弦值。因此,易知这个45指的应该是球杆与白球的距离(y轴坐标分析同理)。

可知,默认情况下球杆离白球的距离为45。因此,我们只需根据力度的数值改变这45的距离即可。引入_curPower,把代码中的45都改为45+_curPower/2  (除以2是为了适当控制距离,令球杆不要离白球太远),即:

图 17

5其余

  • 由一个洞口添加到四个洞口(前文已说明)
  • 窗口分辨率调整为1600 x 900
  • 小球由5个增添到10个,并对位置进行了调整
  • 添加新的背景精灵bg,即为绿色的台球布。代码为:

图 18

6程序运行

初始图:

图 19

注意球杆和白球距离,以及力量条间的关系:

图 20

图 21

学习4 碰撞检测与运动模拟(Box2D桌球)相关推荐

  1. box2d 碰撞检测_谁动了我的刚体——Box2D碰撞检测

    今天我们来学习用Box2D的b2Contact和b2ContactListener来获取碰撞对象(Box2D中用contact一词来表示碰撞,知道这一点,对后面的理解会有帮助). Box2D是一个非常 ...

  2. Web前端学习仿拼多多软件——模拟练习

    Web前端学习仿拼多多软件模拟练习,作者声明:该项目只是学习模拟软件前端的界面,不允许用于商业行为,否则后果自负! 代码界面截图(因为只是学习分享,所以已经多处避免雷同): 下载资源后运行的时候要记得 ...

  3. Unity学习记录——空间与运动

    Unity学习记录--空间与运动 前言 ​ 本文是中山大学软件工程学院2020级3d游戏编程与设计的作业3 编程题 1. 模拟太阳系 ​ 首先向unity中Assets添加所找的贴图素材Solar T ...

  4. Windows进程与线程学习笔记(五)—— 模拟线程切换

    Windows进程与线程学习笔记(五)-- 模拟线程切换 ThreadSwitch代码分析 ThreadSwitch.cpp ThreadCore.h ThreadCore.cpp 总结 Thread ...

  5. 操作系统学习之用C语言模拟CLOCK算法

    前言 CLOCK算法,顾名思义,时钟算法,是一个在FIFO和LRU的折衷算法,很符合我们的中庸之道,来学一学它折衷了哪些部分. Buddy算法:操作系统学习之用C语言模拟伙伴(Buddy)算法 FIF ...

  6. 操作系统学习之用C语言模拟LRU算法

    前言 LRU算比较经典,而且考的也比较多,LRU算法全称Least Recently Used,译为最近最少使用.用C模拟一下吧. Buddy算法:操作系统学习之用C语言模拟伙伴(Buddy)算法 F ...

  7. 操作系统学习之用C语言模拟伙伴(Buddy)算法

    前言 学到了操作系统的的虚拟内存部分,硬件不太好的我学起来有些吃力,概念性知识点太多,所以我决定用软件的方式,实现一下虚拟内存常用的算法,因为用到了指针,暂时用C语言写一下Buddy算法.FIFO算法 ...

  8. 【运动学】基于matlab GUI三体运动模拟【含Matlab源码 871期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[运动学]基于matlab GUI三体运动模拟[含Matlab源码 871期] 点击上面蓝色字体,直接付费下载,即可. 获取代码方式2: ...

  9. 2008年最精彩科技图片:电流运动模拟图居首

    2008年最精彩科技图片:电流运动模拟图居首 北京时间1月5日消息,据英国<新科学家>杂志报道,在刚刚过去的2008年,科学家们拍摄或者绘制了许多精彩绚丽的科技图片,这其中包括模拟电流运动 ...

最新文章

  1. Python入门100题 | 第041题
  2. perl正则表达式-1
  3. vs如何设置对话框显示在最前面_“打开”对话框的使用
  4. java 并发编程视频教程_全面深入学习java并发编程,视频教程下载
  5. ubuntu ???????????? no permissions 问题解决
  6. C语言基础知识(二)-------C++变量及赋值
  7. jsf 导航_JSF动作方法导航示例教程– from-action标记
  8. Android:Intent传递数据
  9. 天锐绿盾解密_天锐绿盾数据防泄密系统
  10. 计算机ps cs2考试,photoshop cs2试题汇编素材(中级考试题目答案和素材)
  11. 彻底解决web调试时,修改css样式后刷新网页无改变
  12. Linux的DNS域名解析服务
  13. 以 ARM 开发板 和 Arduino UNO 开发板通过串口通信为例,思考嵌入式设备之间通过串口通信的问题总结
  14. 常用的mysql函数及在TP中使用示例
  15. 微信摇一摇插件ios_iOS开发——全局响应MotionEvent(微信摇一摇)
  16. 董氏奇穴学习记录(上课记录)
  17. java如何通过client客戶端http实现get/ post请求传递json参数到restful 服务接口
  18. 分布式开源存储架构Ceph概述
  19. 【云原生 | Kubernetes 系列】K8s 实战 一文学会如何从 PodSecurityPolicy 迁移到内置的 PodSecurity 准入控制器
  20. inotify+rsync 实现实时同步

热门文章

  1. 瓜子大数据架构首曝光:掩藏在“二手车”背后的技术思考
  2. hybris学习笔记:New Extension
  3. 计算机看到硬盘是空白状态,我的可移动硬盘打不开了,插入后电脑上有显示,就是打不开,查看属性是满盘了,在电脑磁盘运行里看是空的...
  4. pandas学习案例-北京市火锅店数据分析
  5. AI调参师会被取代吗?对话AutoML初创公司探智立方
  6. 小米平板5参数配置 小米平板5 8月10日发布
  7. 计算机最基本的2大功能,电脑必须要学会最基础功能(必收藏)
  8. PE49-Prime permutations
  9. Oracle表空间_PK是什么意思,Oracle表空间详解
  10. Java做打印服务打印A4