标签:
续上章载入 TiledMap 背景后,接下来的这章我们将开始引入物理引擎相关的东西,并且会开始创建我们的游戏角色。游戏地图中各类障碍物和奖励品的创建则会留到下一章。
首先,物理引擎是干什么的应该不用我说吧?好吧,还是说一下(百度的):物理引擎通过为刚性物体赋予真实的物理属性的方式来计算运动、旋转和碰撞反映。所以用它来模拟真实世界的飞行、掉落等功能是具有得天独厚的优势的,这也是为什么我们的游戏要使用它的原因。
然后,我们要怎样使用物理引擎啦?在之前的 Cocos2d-x 2.x 中,游戏需要选择直接调用 Box2D 或 Chipmunk 的 API 来处理逻辑,这种方法比较复杂,需要开发人员对物理引擎和 Cocos2d-x 都非常了解才能把两者融合得很好。而在现在的 Cocos2d-x 3.x(Quick 3.x同样)版本中封装了一个全新的 Physics 接口,这个接口将 Chipmunk(默认使用 Chipmunk 作为内部物理引擎)和 Box2D 封装到引擎内部,使开发者的上层调用变得更加友好、简单。
物理引擎属较高阶一点的内容,关于它的一些基础概念,比如:刚体、形状、密度、世界等等,可查找 Chipmunk 和 Box2D 相关文档进行脑补。本教程只针对需要使用的API做一定的了解。
封装了 Physics 接口后,物理世界被融入到 Scene 中,即当创建一个场景时,可以指定这个场景是否使用物理引擎。
回到我们的游戏,我们一开始就已经认定了 GameScene 是我们的主游戏场景,所以,它需要是一个使用物理引擎的游戏场景。所以,打开 GameScene 文件,我们需要在创建它的地方把它修改为带物理世界的 scene:
display.newPhysicsScene("GameScene")
之后,你可在 ctor 方法中加入如下的一段代码:
self.world = self:getPhysicsWorld()
self.world:setGravity(cc.p(0, -98.0))
self.world:setDebugDrawMask(cc.PhysicsWorld.DEBUGDRAW_ALL)
其中,self:getPhysicsWorld()
用来获取场景绑定的物理世界对象。
获取的 self.world 默认是有带重力的,大小为(0.0f, -98.0f), 但我们也可以通过的setGravity()方法来改变重力大小。
setDebugDrawMask 方法是在调试物理世界时使用的,该方法可以开启调试模,能把物理世界中不可见的body,shape,joint等元素可视化(如下图所示)。当调试结束时,需要把该功能关闭。
在第六章中我们曾说过,本游戏教程将创建一个飞行的娃娃角色,所以接下来我们一起来创建一个带物理特性的游戏角色。
在开始之前,我们先在 src/app 中创建一个文件夹 objects 来存放接下来要创建的游戏对象。
接着,新建一个 lua 文件并命名为 Player,然后把他存放入 objects 文件夹中,下面稍稍定义下这个类:
local Player = class("Player", function()
return display.newSprite("#flying1.png")
end)
function Player:ctor()
end
return Player
接下来我们来给游戏主角添加物理特性。
引擎封装了 Physics 接口后,Node 就自带了 body 属性,也就是每个 Sprite 都自带了 body 属性。所以我们要创建一个可受重力作用的 Sprite 是非常容易的,下面我们在 Player 的 ctor 中加入如下的一段代码就可以为它绑定一个 body:
local body = cc.PhysicsBody:createBox(self:getContentSize(), cc.PHYSICSBODY_MATERIAL_DEFAULT, cc.p(0,0))
self:setPhysicsBody(body)
这里调用cc.PhysicsBody::createBox()
方法创建了一个矩形的 body,createBox 方法有三个参数,分别是:
cc.PhysicsMaterial(density, restitution, friction)
与 createBox 方法类似的还有 createCircle(radius, material, offset),该方法可以创建一个圆形的 body,除第一个参数为半径外,其余两参数与 createBox 方法一样。
body是有很多属性的,当我们有需要时,再调用对应的方法。
我们的游戏主角有各种不同的游戏状态(飞行、下落、死亡),所以接下来我们就来实现它的这部分功能。
这里我们通过帧动画实现游戏角色的运动,帧动画的原理是将连续的帧图像(如下图)在渲染的时候通过逐帧或插值的方式播放出来而形成的动态效果。就像翻动小人书一样。
引擎中,帧动画的具体内容是依靠精灵显示出来的,为了显示动态图片,我们需要不停切换精灵显示的内容,通过把静态的精灵变为动画播放器从而实现动画效果。帧动画由帧组成,每一帧都是一个纹理,我们可以使用一个纹理序列来创建动画。
Quick 框架中,我们可以这样来播放一个动画:
-- 创建一个包含flying1.png到flying4.png的4个图像帧对象的数组
local frames = display.newFrames("flying%d.png", 1, 4)
-- 以包含图像帧的数组创建一个动画 Animation 对象
local animation = display.newAnimation(frames, 0.3 / 4)
-- 在显示对象上循环播放动画,并返回 Action 动画动作对象。
transition.playAnimationForever(self, animation)
因为我们的游戏对象有不只一种的动画,所以在本教程中,我们可以先把这些动画都添加到动画缓存,这样在需要播放相应的动画的时候,我们就可以从缓存中直接获取动画来播放了,而不用再浪费时间重新创建动画。
所以,请在 Player.lua 文件中添加如下的一段函数:
function Player:addAnimationCache()
local animations = {"flying", "drop", "die"}
local animationFrameNum = {4, 3, 4}
for i = 1, #animations do
-- 1
local frames = display.newFrames( animations[i] .. "%d.png", 1, animationFrameNum[i])
-- 2
local animation = display.newAnimation(frames, 0.3 / 4)
-- 3
display.setAnimationCache(animations[i], animation)
end
end
animations,animationFrameNum分别表示角色的三种动画和三种动画分别有的帧总数。
遍历animations时,下面一一解释下函数的作用:
把动画载入缓存后,我们就可以写下对应的函数去执行动画了。如下:
function Player:flying()
transition.stopTarget(self)
transition.playAnimationForever(self, display.getAnimationCache("flying"))
end
function Player:drop()
transition.stopTarget(self)
transition.playAnimationForever(self, display.getAnimationCache("drop"))
end
function Player:die()
transition.stopTarget(self)
transition.playAnimationForever(self, display.getAnimationCache("die"))
end
最后在创建 Player 对象后,我们就可以调用以上相应的方法来播放指定的动画了。
转载请注明出自:http://shannn.com/archives/422
Quick-Cocos2d-x初学者游戏教程(八)----------------- 物理引擎和角色
标签:
原文地址:http://www.cnblogs.com/dudu580231/p/4807545.html