Quick-Cocos2d-x初学者游戏教程(十)
在我们的游戏中,我们除了添加奖励品外,还需要添加一些必要的障碍物来丰富游戏逻辑,增加游戏难度,所以本章我们将继续上章的内容——添加游戏障碍物。游戏中,障碍物是不止一种,这里有飞行的鸟,有上下移动的飞艇。
创建障碍物-飞艇
其实创建飞艇的逻辑和前面创建心心的逻辑是一样的,只不过这里我想让飞艇不停的上下移动,一方面做点带感的效果出来,另一方面也可以增加游戏难度。
看过之前教程的童鞋,现在应该懂得怎样创建这样的一个飞艇了吧。所以下面我们直接给出它的定义:
local Airship = class("Airship", function()
return display.newSprite("#airship.png")
end)
local MATERIAL_DEFAULT = cc.PhysicsMaterial(0.0, 0.0, 0.0)
function Airship:ctor(x, y)
local airshipSize = self:getContentSize() -- 得到Airship自身的尺寸大小
local airshipBody = cc.PhysicsBody:createCircle(airshipSize.width / 2,
MATERIAL_DEFAULT)
self:setPhysicsBody(airshipBody)
self:getPhysicsBody():setGravityEnable(false)
self:setPosition(x, y)
local move1 = cc.MoveBy:create(3, cc.p(0, airshipSize.height / 2))
local move2 = cc.MoveBy:create(3, cc.p(0, -airshipSize.height / 2))
local SequenceAction = cc.Sequence:create( move1, move2 )
transition.execute(self, cc.RepeatForever:create( SequenceAction ))
end
return Airship
再强调一点的是:这里我们在创建刚体时把它的密度,反弹力、摩擦力都设为0是为了在碰撞的时候不发生任何物理形变。
密度是用来计算物体质量的,它可以是等于零或大于零的正数。摩擦力经常会设置在0.0到1.0之间,0.0表示没有摩擦力,1.0会产生强摩擦。弹性系数的值通常设置到0.0到1.0之间,0.0表示物体不会弹起,1.0表示物体会完全反弹,即称为弹性碰撞。
创建障碍物-鸟
这里我们要创建一个飞行的小鸟。创建它与创建心心唯一不同的是:它是一个动态的游戏对象。下面是 Bird 的定义:
local Bird = class("Bird", function()
return display.newSprite("#bird1.png")
end)
local MATERIAL_DEFAULT = cc.PhysicsMaterial(0.0, 0.0, 0.0)
function Bird:ctor(x, y)
local birdBody = cc.PhysicsBody:createCircle(self:getContentSize().width / 2,
MATERIAL_DEFAULT)
self:setPhysicsBody(birdBody)
self:getPhysicsBody():setGravityEnable(false)
self:setPosition(x, y)
local frames = display.newFrames("bird%d.png", 1, 9)
local animation = display.newAnimation(frames, 0.5 / 9)
animation:setDelayPerUnit(0.1)
local animate = cc.Animate:create(animation)
self:runAction(cc.RepeatForever:create(animate))
end
return Bird
封装加载函数
现在我们已经创建了心心、飞艇,还有鸟。虽然种类不多,但我已经不想再创建其他的了,反正原理都差不多,所以还是给大家留个自由发挥和创作的机会吧。
创建好游戏对象后,我们接下来要做的就是把它们都加载到场景中。这一过程你可以效仿上一章加载心心的方法来加载另外的两种游戏对象。不过如果你的要求更高,那你一定会想把这些函数封装一下,就如下列代码所示:
function BackgroundLayer:addBody(objectGroupName, class)
local objects = self.map:getObjectGroup(objectGroupName):getObjects()
local dict = nil
local i = 0
local len = table.getn(objects)
for i = 0, len-1, 1 do
dict = objects[i + 1]
if dict == nil then
break
end
local key = "x"
local x = dict["x"]
key = "y"
local y = dict["y"]
local sprite = class.new(x, y)
self.map:addChild(sprite)
end
end
addBody函数抽象出对象组的名字和类类型作为参数,这样我们就可以通过它来加载各种不同的游戏对象了。
self:addBody("heart", Heart)
self:addBody("airship", Airship)
self:addBody("bird", Bird)
加载这些对象时,不要忘了在 BackgroundLayer 文件中载入相应的文件:
local Heart = require("app.objects.Heart")
local Airship = require("app.objects.Airship")
local Bird = require("app.objects.Bird")
此时运行游戏,你就可以在场景中看见各种不同的游戏对象了。
给鸟添加飞行效果
目前这些障碍物和奖励品都只是随着背景滚动,显得游戏了无生趣,所以接下来我们来给鸟添加一个动态的飞行效果,让玩家可以明显的感受到它是朝前飞的。
那下面我们就来看看怎样实现吧。
1、首先,我们先给 BackgroundLayer 定义一个table数组来存放游戏中所有的鸟,即在ctor方法中加入如下的变量:
self.bird = {}
2、然后,在创建鸟这个游戏对象时,我们需要把所有的鸟都添加到定义的 self.bird 数组中。所以在 addBody 方法中,我们需要加上一则判断:
local sprite = class.new(x, y)
self.map:addChild(sprite)
if objectGroupName == "bird" then
table.insert(self.bird, sprite)
end
即当创建的对象是鸟(bird)时,就把该对象插入 self.bird。
3、接着,我们在 BackgroundLayer 中添加如下的一个函数:
function BackgroundLayer:addVelocityToBird()
local dict = nil
local i = 0
local len = table.getn(self.bird)
for i = 0, len-1, 1 do
dict = self.bird[i + 1]
if dict == nil then
break
end
local x = dict:getPositionX()
if x <= display.width - self.map:getPositionX() then
if dict:getPhysicsBody():getVelocity().x == 0 then
dict:getPhysicsBody():setVelocity(cc.p(-70, math.random(-40, 40)))
else
table.remove(self.bird, i + 1)
end
end
end
end
在该函数中,我们遍历 self.bird 数组中的所有 Bird 对象,当检测到某个 Bird 对象刚好要进入屏幕,且还没给过它任何速度时,我们会给它一个向左的速度,这个速度的范围从(-70, -40)到(-70, 40)。通俗一点就是说: Bird 对象将在横坐标上有一个大小为70,方向向左的速度;在纵坐标上有一个大小在(-40, 40)之间,方向不定的速度。
其中math.random(-40, 40)可以产生-40到40的随机数。为了不产生相同的随机数,我们需要在MyApp:run()中“种”一棵随机数种子,即添加如下的一行代码:
math.randomseed(os.time())
当已经给过某些 Bird 对象速度时,我们要把该对象从 self.bird 数组中移除,这样可以减短遍历数组的时间。table.remove(table, pos)函数将删除并返回 table 数组中位于 pos 位置上的元素。
总的来讲,addVelocityToBird 函数的目的就是在小鸟进入屏幕时给它一个速度,让它朝着游戏角色冲过来。
4、最后,因为我们需要不停的遍历 self.bird 数组、不停的检测是否给小鸟加上速度,所以我们需要在刷新屏幕时调用以上的 addVelocityToBird() 函数。
那就偷个懒,直接在 scrollBackgrounds(dt) 函数的最后面添加下列函数:
self:addVelocityToBird()
现在注释掉GameScene:ctor()方法中的self.world:setDebugDrawMask(cc.PhysicsWorld.DEBUGDRAW_ALL)
和添加Player的代码,那我们可以得到如下的一个游戏效果:
补充
因为游戏中的Player、Heart、Airship、Bird都是刚体,所以现在把这些刚体放在同一个物理世界是很容易发生碰撞、反弹、旋转、被挤出场景等等问题的。所以,这里我们要补充的就是怎样有效的解决这些问题,当然,制定具体的解决方案还需要结合碰撞检测来做,这个我们下章会讲。
setDynamic(dynamic):如果你想你的刚体固定不动,那么你可以调用该函数。如游戏中的心心,它在物理世界中就是个相对固定不动的对象,所以我们可以设置它的刚体属性dynamic为false,即 body:setDynamic(false) 。
setRotationEnable(enable):如果你想你的刚体不旋转,那么你可以调用该函数。如 Player、Airship 和 Bird 对象,它们在物理世界中是 Dynamic(动态)的,但我们不希望它们在动的过程中重心不稳发生旋转,所以,我们可以给 Player 刚体添加这样的属性加以约束,即:body:setRotationEnable(false)。
好了,今天就说到这里吧,这两章说的有点啰嗦,下章我们会加快进度,给大家讲讲如何给游戏添加触摸事件,并编写碰撞检测的逻辑。
关于源代码,下一两周内我会整理了会放出来。各位稍安勿躁,( ̄艸 ̄”)!
转载请注明出自:http://shannn.com/archives/431