• Quick-Cocos2d-x初学者游戏教程(十) ---------------- 添加游戏障碍物


    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")

    此时运行游戏,你就可以在场景中看见各种不同的游戏对象了。

    something

    给鸟添加飞行效果

    目前这些障碍物和奖励品都只是随着背景滚动,显得游戏了无生趣,所以接下来我们来给鸟添加一个动态的飞行效果,让玩家可以明显的感受到它是朝前飞的。

    那下面我们就来看看怎样实现吧。

    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的代码,那我们可以得到如下的一个游戏效果:

    fly

    补充

    因为游戏中的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

  • 相关阅读:
    泛在电力物联网建设路线
    如何建设泛在电力物联网?
    泛在电力物联网到底该怎么建?
    泛在电力物联网(能源互联网+物联网)浅析
    泛在电力物联网分析—架构形式
    泛在电力物联网:两个业务 两种发展逻辑
    国网“泛在电力物联网”的战略与逻辑
    MVC中使用Hangfire按秒执行任务
    hangfire 实现已完成的job设置过期,防止数据无限增长
    解决ASP.NET Core部署到IIS,更新项目"另一个程序正在使用此文件,进程无法访问"
  • 原文地址:https://www.cnblogs.com/dudu580231/p/4807552.html
Copyright © 2020-2023  润新知