新手入门,unity2d,Unity,游戏开发

「Unity2D」使用Unity创建一个2D游戏系列-1

本文由泰然教程组成员 HelloWorld 翻译,原文请参阅「Install Unity and create your first scene」

安装unity并且创建你的第一个场景

在第一章,你将会学习到一些非常基本的内容:首先是unity的下载和安装,其次是准备创建我们游戏内的第一个场景。

配置你的环境

我们从简单的部分开始:下载和配置Unity。

在这里输入图片描述

安装Unity

官方网站下载最新的版本。启动可执行的文件,之后一切都会正确的安装。

选择一个代码编译器

Unity是依附于MonoDevelop(4.0.1目前)来编写代码。

Windows

如果你在Windows环境下,那么你可以(也应该)选择另一个选项:

阅读全文»

Quick-Cocos2d-x初学者游戏教程12

上章我们讲解了物体之间的碰撞检测,而本章开始,我们将讲解触摸事件的实现,同时,我们还将给 Player 加上血量条。

需求说明

在开始之前,我们先来看看本节游戏的一些需求。

对于本教程游戏来说,我们的需求是在点击屏幕的时候,给 Player 一个向上的速度,让它能飞起来,否则它会受到重力的影响向下掉落。当掉落到地面上时,Player 会掉血,所以我们必须不停的点击屏幕以避免 Player 掉落到地上。在避免 Player 掉落的同时,我们还可以通过控制 Player 的飞起和降落来躲开障碍物和拾取心心。

游戏开始后 Player 精力充沛,有满满的血量,但当 Player 撞到障碍物和地面时,会根据碰撞到的类型来扣除不同点数的血量,当 Player 碰到心心时,可以增加一定的血量,并且会消除心心,消除的同时给它一个消除特效,这个特效用粒子系统来完成。Player 血量为0或地图跑外时,游戏结束。

需求分析清楚以后,下面我们就开始实现也上所描述的功能。

添加触摸事件

首先,我们来添加触摸事件。

触摸响应是游戏开发中一个很重要的模块,它是手游中玩家与游戏交互的主要途径。在 Quick 中,触摸事件机制是非常简单的,它允许任何一个 Node 接受触摸事件,而不局限于 Layer。

在我们的游戏中,我们需要在 Player 开始下落的时候启动触摸事件的响应,所以,我们将在 playerFlyToScene 函数的 startDrop 方法中启动触摸事件的响应,相关代码如下所示:

local function startDrop()
self.player:getPhysicsBody():setGravityEnable(true)
self.player:drop()
self.backgroundLayer:startGame()

self.backgroundLayer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
return self:onTouch(event.name, event.x, event.y)
end)
self.backgroundLayer:setTouchEnabled(true)

end

这里,我们给 self.backgroundLayer 背景层添加了触摸事件的监听,其中 addNodeEventListener 方法用于注册系统事件的监听,如上所诉的触摸事件,以及帧事件、按键事件等等。

可能你会问:为什么是给 self.backgroundLayer 添加触摸事件的监听呢,为什么不是 self 场景自身,或者 Player?这里我们需要解释一下的是:触摸响应不能直接给 scene 添加事件监听,而如果只给 Player 添加触摸监听,那么我们只能在 Player 这个很小的范围内响应到触摸事件,所以我们需要用一个层来完成。在游戏中又只创建了一个背景层,所以我们就将就着把触摸事件的监听添加到它身上。当然,你也可以新建一个层来添加触摸监听,这里我们就不那么讲究了!

setTouchEnabled 方法用于开启触摸功能,如果 setTouchEnabled(false),那么背景层将不能接受到触摸响应。

另外,onTouch 方法是触摸事件回调,其定义如下:

function GameScene:onTouch(event, x, y)
if event == "began" then

self.player:flying()
self.player:getPhysicsBody():setVelocity(cc.p(0, 98))

return true
-- elseif event == "moved" then

elseif event == "ended" then
self.player:drop()
-- else event == "cancelled" then
end
end

因为我们要实现点击屏幕就给 Player 一个向上的速度,不点的时候 Player 向下掉落。所以,这里我们只需在触摸开始时,让 Player 处于飞行状态且给它一个方向向上的速度(0, 98);在触摸结束时,让 Player 下落就可以了。而不必去考虑在触摸移动 "moved" 和触摸取消 "cancelled" 时的状态。

还有一点要注意的是:在触摸开始时,必须返回 true,不然之后的 "ended" 等消息将不会被响应。

添加血条

接下来我们来给 Player 添加血量条,这可以用引擎中已经封装好的进度条(ProgressTimer)来实现。

以下是在 Player 中添加的相关代码,我们先来看看。

function Player:createProgress()
self.blood = 100 -- 1
local progressbg = display.newSprite("#progress1.png") -- 2
self.fill = display.newProgressTimer("#progress2.png", display.PROGRESS_TIMER_BAR) -- 3

self.fill:setMidpoint(cc.p(0, 0.5)) -- 4
self.fill:setBarChangeRate(cc.p(1.0, 0)) -- 5
-- 6
self.fill:setPosition(progressbg:getContentSize().width/2, progressbg:getContentSize().height/2)
progressbg:addChild(self.fill)
self.fill:setPercentage(self.blood) -- 7

-- 8
progressbg:setAnchorPoint(cc.p(0, 1))
self:getParent():addChild(progressbg)
progressbg:setPosition(cc.p(display.left, display.top))
end

function Player:setProPercentage(Percentage)
self.fill:setPercentage(Percentage) -- 9
end

其中 createProgress 方法的作用是添加一个进度条,setProPercentage 方法的作用是设置进度条的百分比。下面我们一一讲解下代码:

  1. 添加血量属性 self.blood,这里初始值我设为了 100,这样我们后面就可以根据血量来设置进度条的百分比了(懒人做法)。
  2. 给进度条创建一个底,也就是在进度条的下面放一个背景,这样当进度条逐渐变短时,用户可以更直观的看到它减少了多少。
    进度条背景和进度条图片分别如下所示:
    progress1 progress2
  3. 创建进度条 self.fill,display.newProgressTimer 方法的两个参数分别表示创建进度条所用的图片,以及进度条的类型。引擎中进度条的类型有两种:

    • display.PROGRESS_TIMER_BAR:条形,这种类型的进度条通常用于创建类似生命条,等级条的一类进度条。
    • display.PROGRESS_TIMER_RADIAL:环形,它通常用于创建类似加载功能的进度条,比如游戏加载资源时页面上旋转的菊花(PS:词穷,就是菊花吧,不要想歪)。
  4. 设置进度条的起始点,(0,y)表示最左边,(1,y)表示最右边,(x,1)表示最上面,(x,0)表示最下面。
  5. 设置进度条变化方向,如果不用变化的方向,则设置该方向为0,否则设置为1。所以(1,0)表示横方向,(0,1)表示纵方向。
  6. 把进度条的位置设置在 progressbg 上,并将进度条添加到 progressbg 上。
  7. 调用 ProgressTimer 的 setPercentage 方法设置进度条的百分比为 100%(因为 self.blood 的值为100)。
    ProgressTimer 类有一个很最要的percentage属性。它代表当前进度条的进度值。其中 setPercentage 方法能设置 ProgressTimer 的 percentage 值。
  8. 把 progressbg 加入屏幕的左上角。这里做了三件事:
    • 首先要把 progressbg 的锚点设置到它的左上角,锚点这个概念我忘了前面讲没讲过了,这里还是简单说明一下。
      锚点的两个参数在0~1之间。一般节点的锚点默认值都是(0.5, 0.5),也就是在节点的最中间。(0, 1)就表示左上角,将一个节点添加到父节点里面时,需要设置节点在父节点上的位置,其本质上就是设置节点的锚点在父节点坐标系上的位置。
    • 接着,我们把 progressbg 加到了 Player 的父节点上,这里也就是 GameScene 场景中。这样,进度条才不会随着 Player 的移动而移动了。
    • 最后,这里我们把 progressbg 放到屏幕的左上角。 anchor
  9. setProPercentage 是我们来设置进度条百分比的。

好了,以上创建血条的代码段应该讲解的够清楚了吧,接下来我们需要做的就是在合适的地方调用它。这里我们在 GameScene 中调用:

self.player = Player.new()
self.player:setPosition(-20, display.height * 2 / 3)
self:addChild(self.player)
self:playerFlyToScene()

self.player:createProgress() -- here

此刻,运行游戏,我们就可以看到如下的效果了。

smallw

好了,本章就到处为止,下章将是我们教程的最后一章,大家期待的完整代码将放出,敬请期待吧。

转载请注明出自:http://shannn.com/archives/437

Quick-Cocos2d-x初学者游戏教程11

本章主要讲解物体碰撞检测之间的原理,以及具体的实现方法。

碰撞检测

本游戏使用物理引擎的一个重要目的是为了让碰撞检测更方便,使用物理引擎可以进行精确的碰撞检测,而且执行的效率也很高。

在 Quick 3.3final 版本中,所有事件均有事件派发器统一管理,物理引擎的碰撞事件也不例外。它由 cc.EventListenerPhysicsContact 的实例来监听。

监听事件分类

碰撞监听事件有以下几种:

  • cc.Handler.EVENT_PHYSICS_CONTACT_BEGIN
    它是碰撞刚发生时触发的事件,并且在此次碰撞中只会被调用一次。我们可以通过返回 true 或者 false 来决定物体是否发生碰撞。
    需要注意的是,当这个事件的回调函数返回 flase 时,EVENT_PHYSICS_CONTACT_PRESOLVEEVENT_PHYSICS_CONTACT_POSTSOLVE将不会被触发,但EVENT_PHYSICS_CONTACT_SEPERATE必定会触发。

  • cc.Handler.EVENT_PHYSICS_CONTACT_PRESOLVE
    它在碰撞接触后的每帧都会调用。在该事件的回调函数中我们可以计算碰撞处理的一些属性,比如弹力,速度等。同样它可以通过返回 true 或者 false 来决定物体是否发生碰撞。

  • cc.Handler.EVENT_PHYSICS_CONTACT_POSTSOLVE
    发生在碰撞计算完毕的每个步骤(帧),你可以在此做一些碰撞的后续处理,比如安全的移除某个物体等。

  • cc.Handler.EVENT_PHYSICS_CONTACT_SEPERATE
    发生在碰撞结束两物体分离时,同样只会被调用一次。

下面我们来看看添加碰撞监听的代码,如下所示:

local contactListener = cc.EventListenerPhysicsContact:create()   -- 1
contactListener:registerScriptHandler(onContactBegin, cc.Handler.EVENT_PHYSICS_CONTACT_BEGIN) -- 2
contactListener:registerScriptHandler(onContactSeperate, cc.Handler.EVENT_PHYSICS_CONTACT_SEPERATE) -- 3
local eventDispatcher = cc.Director:getInstance():getEventDispatcher() -- 4
eventDispatcher:addEventListenerWithFixedPriority(contactListener, 1) -- 5
  1. 创建物体碰撞检测事件监听器对象(contactListener);
  2. 设置监听器的碰撞开始函数 onContactBegin;
  3. 设置监听器的碰撞分离函数 onContactSeperate;
  4. 监听器设置完毕,需要把它加入到引擎导演的事件分发器中。所以这里获取游戏的事件分发器(eventDispatcher);
  5. 将检测事件监听器(contactListener)添加到事件分发器(eventDispatcher)中,这样就可以触发碰撞检测事件。addEventListenerWithFixedPriority 方法是指定固定的事件优先级注册监听器,事件优先级决定事件响应的优先级别,值越小优先级越高。

掩码属性

在讲解 onContactBegin 和 onContactSeperate 函数之前,这里我们需要清楚地一点。即在默认情况下,物理引擎中的物体是不会触发碰撞回调事件的。也就是说,上面代码中的 onContactBegin 和 onContactSeperate 方法永远都不会调用到。

为什么啦? O(∩_∩)O~呵呵,咱不卖关子。因为每个 cc.PhysicsBody 都具有三个掩码属性,两个刚体能不能碰撞,能不能发送接触事件信息,都依靠于这三个参数的值。

所以,为了更好地解决刚才遇到的问题,下面我们先来了解下刚体的这三个 mask 属性。

  • CategoryBitmask:32位整型,刚体的类别掩码。它定义了一个物体所属类别,每一个物体在场景中都能被分配到多达32位不同的类别。默认值为0xFFFFFFFF。

  • ContactTestBitmask:32位整型,刚体的接触测试掩码。当两个物体接触时,用一个物体的类别掩码与另一个物体的接触测试掩码做“逻辑与”运行,如果结果为非零值,引擎才会新建 PhysicsContact 对象,发送碰撞事件。那么才发送碰撞事件消息。
    ContactTestBitmask 的设计是为了优化性能,并不是所有物体之间的碰撞我们都关心,所有这个 ContactTestBitmask 的默认值为0x00000000。

  • CollisionBitmask:32位整型,刚体的碰撞掩码。当两个物体接触后,用一个物体的碰撞掩码与另一个物体的类别掩码执行“逻辑与”运算,如果结果为非零值,那么该物体能够对另一个物体的碰撞发生反应。这里的“碰撞反应”会表现为一个物体受到另外物体的碰撞,而改变运动方向。默认值为0xFFFFFFFF。

总结:

  1. CategoryBitmask 是其它两个掩码比较的基础。
  2. CategoryBitmask & ContactTestBitmask 决定是否发送事件消息。
  3. CategoryBitmask & CollisionBitmask 决定是否产生刚体反弹效果。
  4. ContactTestBitmask 和 CollisionBitmask 互相之间没有联系。

注:每个 mask 都有对应的 get 和 set 接口来获取或者修改mask。
另外,发生碰撞和发送事件消息是不同的概念,前者是直观地一种表现-碰撞反弹,后者是一种消息机制,就是说是否调用碰撞事件的回调函数。

回到我们的游戏,根据需求我们配置了一份各类 Node 的掩码属性表,如下所示:

节点 类别掩码 接触测试掩码 碰撞掩码
玩家:Player 0111 1111 1001
心心:Heart 0001 0100 0001
鸟:Bird 0010 0010 1000
飞艇:Airship 0100 0100 1000
地面 1000 0001 0011
天界 1000 0000 0001

首先,以玩家和心心为例,我们希望它们发生碰撞,并希望发送事件消息。所以,玩家的类别掩码0111 逻辑&与 心心的碰撞掩码0001结果为0001(不为0),发生碰撞;且玩家的类别掩码0111 逻辑&与 心心的接触测试掩码0100结果为0100(不为0),发送事件消息。反之,心心的类别掩码0001 & 玩家的碰撞掩码1001结果为0001(不为0),发生碰撞;且心心的类别掩码0001 逻辑&与 玩家的接触测试掩码1111结果为0001(不为0),发送事件消息。所以,玩家和心心两个物体相互接触时,它们会发生碰撞反弹,同时会发出事件消息。

我们再举一例,这次以玩家和鸟为例,我们希望它们不发生碰撞,但希望发送事件消息。所以,玩家的类别掩码0111 逻辑&与 鸟的碰撞掩码1000结果为0000(为0),不发生碰撞;且玩家的类别掩码0111 逻辑&与 鸟的接触测试掩码0010结果为0010(不为0),发送事件消息。反之,鸟的类别掩码0010 & 玩家的碰撞掩码1001结果为0000(为0),不发生碰撞;且鸟的类别掩码0010 逻辑&与 玩家的接触测试掩码1111结果为0010(不为0),发送事件消息。所以,玩家和鸟两个物体相互接触时,它们不发生碰撞反弹,但会发出事件消息。

设置属性

为了更方便碰撞检测,我们给各个节点设置一个标签。标签的定义我们可以放在 config.lua 文件中。定义如下所示:

GROUND_TAG   = 1
HEART_TAG = 2
BIRD_TAG = 3
AIRSHIP_TAG = 4
PLAYER_TAG = 5

根据以上的掩码属性和标签属性,我们在游戏项目中要设置好这些属性,如对于 Player,我们要在绑定刚体的地方加上如下的一段代码,即 Player:ctor()方法中:

body:setCategoryBitmask(0x0111)
body:setContactTestBitmask(0x1111)
body:setCollisionBitmask(0x1001)

self:setTag(PLAYER_TAG)

其他节点同理,这里就不一一添加了。

碰撞实现

下面我们给出碰撞检测的整段函数,程序中我们把它封装在了 addCollision 方法中,如下所示:

function GameScene:addCollision()

local function contactLogic(node)
-- 4
if node:getTag() == HEART_TAG then
-- 给玩家增加血量,并添加心心消除特效,下章会加上
node:removeFromParent()
-- 5
elseif node:getTag() == GROUND_TAG then
-- 减少玩家20点血量,并添加玩家受伤动画,下章会加上

elseif node:getTag() == AIRSHIP_TAG then
-- 减少玩家10点血量,并添加玩家受伤动画

elseif node:getTag() == BIRD_TAG then
-- 减少玩家5点血量,并添加玩家受伤动画
end
end

local function onContactBegin(contact) -- 1
-- 2
local a = contact:getShapeA():getBody():getNode()
local b = contact:getShapeB():getBody():getNode()
-- 3
contactLogic(a)
contactLogic(b)

return true
end

local function onContactSeperate(contact) -- 6
-- 在这里检测当玩家的血量减少是否为0,游戏是否结束。
end

local contactListener = cc.EventListenerPhysicsContact:create()
contactListener:registerScriptHandler(onContactBegin, cc.Handler.EVENT_PHYSICS_CONTACT_BEGIN)
contactListener:registerScriptHandler(onContactSeperate, cc.Handler.EVENT_PHYSICS_CONTACT_SEPERATE)
local eventDispatcher = cc.Director:getInstance():getEventDispatcher()
eventDispatcher:addEventListenerWithFixedPriority(contactListener, 1)
end

之前提到过的 onContactBegin 和 onContactSeperate 函数我们都写在了 addCollision 方法中,而 contactLogic(node) 方法则是碰撞检测的逻辑函数。

下面我们依次来看看这些代码,请顺着编号的顺序来看:

  1. onContactBegin 方法是碰撞开始时触发的回调函数。只有当场景中两个碰撞的物体的CategoryBitmask & ContactTestBitmask 不为0时才调用。
  2. 获取发生了碰撞的两个节点。
  3. 调用 contactLogic 方法检测碰撞逻辑。因为两个物体发生碰撞时,可能是A碰了B,也可能是B来碰了A,所以这里我们调用了两次 contactLogic 方法。
  4. 在 contactLogic 方法中,当被检测节点的标签为 HEART_TAG,即心心时,我们将在这里给玩家增加血量,添加心心消除特效,并且从屏幕中移除被撞的心心。
  5. 当被检测节点的标签为地面(GROUND_TAG)、飞艇(AIRSHIP_TAG)、鸟(BIRD_TAG)时,减少玩家相应地血量,并添加玩家受伤动画。其中给玩家增加血量,添加心心消除特效等我们下章再讲。
  6. onContactSeperate 方法是碰撞分离时触发的方法,在这里检测当玩家的血量减少是否为0,游戏是否结束。

在 GameScene 的 ctor 中调用 addCollision 方法后,你就可以实现碰撞检测了,此时只有玩家与心心碰上了才有反应。

本章说了太多细节,所以由于篇幅的原因,本章就此结束,咱们下章继续。

转载请注明出自:http://shannn.com/archives/435

Quick-Cocos2d-x初学者游戏教程10

在我们的游戏中,我们除了添加奖励品外,还需要添加一些必要的障碍物来丰富游戏逻辑,增加游戏难度,所以本章我们将继续上章的内容——添加游戏障碍物。游戏中,障碍物是不止一种,这里有飞行的鸟,有上下移动的飞艇。

创建障碍物-飞艇

其实创建飞艇的逻辑和前面创建心心的逻辑是一样的,只不过这里我想让飞艇不停的上下移动,一方面做点带感的效果出来,另一方面也可以增加游戏难度。

看过之前教程的童鞋,现在应该懂得怎样创建这样的一个飞艇了吧。所以下面我们直接给出它的定义:

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

Quick-Cocos2d-x初学者游戏教程2

上一章我们已经了解了Quick的一些基础知识,所以本章我们将开始深入到Quick内部,了解它内部的代码结构,同时在解析的过程中学到相应的原理,并学会如何修改、添加相应的代码文件,比如实现屏幕的分辨率适配。

前面我们创建了一个叫做parkour的游戏项目,其意思就是本人本来打算要做一个跑酷游戏的,但是因为这几天玩了一款叫做《el》的飞行游戏,非常有意境,并且几乎零差评,所以请允许我任性一下,善变的我不想做跑酷游戏了,而是想要挑战下这种类型的游戏。

《el》其实蛮类似跑酷游戏的,同时,它也很像前段时间超火的《Flappy bird》,喜欢这类游戏风格的童鞋不妨可以下载下来玩玩(我木有打广告,不是软文,不是)。

解析代码文件

正如上面所说的一样,本教程改做飞行游戏了。于是乎,我重新创建了一个叫做el的游戏项目。然后打开Sublime编辑器,把整个游戏项目都拖到该编辑器中,这样既方便代码编辑,又方便相关属性的查找。

下面我们就来打开新项目的src文件夹,一个一个的解析里面的lua文件吧。

1、config.lua

首先,打开config.lua文件,config文件中保存了游戏项目一些重要的属性配置,包括调试信息状态、屏幕大小、屏幕适配的方式等等。

下面是它现有属性的具体含义:

  • DEBUG: 配置Quick工程的调试信息状态,0表示关闭,1表示打印少量调试信息,2表示打印标准调试信息。
  • DEBUG_FPS: 是否显示模拟器左下角的FPS信息
  • DEBUG_MEM: 是否要每10秒打印一次内存信息
  • LOAD_DEPRECATED_API: 是否加载已经废弃了的API
  • LOAD_SHORTCODES_API: 是否加载短代码
  • CONFIG_SCREEN_ORIENTATION: 游戏中的屏幕方向,landscape横屏,portrait竖屏。
  • CONFIG_SCREEN_WIDTH: 屏幕宽度,但屏幕方向为“landscape”横屏时,该属性表示屏幕的高度
  • CONFIG_SCREEN_HEIGHT: 屏幕高度,但屏幕方向为“landscape”横屏时,该属性表示屏幕的宽度
  • CONFIG_SCREEN_AUTOSCALE: 屏幕适配策略,如FIXED_WIDTH、FIXED_HEIGHT和FILL_ALL

这些属性都是创建项目时默认配置好的,当然我们可以根据项目需要对这些值进行修改,比如进行分辨率适配时。此外,在config文件中我们也可以加入自定义的一些属性,比如声音、字体、图片、网络配置等等常量和宏的定义。

既然都提起了分辨率适配,那么接下来我们就来看看如何进行分辨率适配吧。

分辨率适配原理

众所周知,现今市场中各种屏幕尺寸和分辨率的移动设备(特别是Android机)层出不穷,所以为了让我们开发的程序项目能够更好地适应这些设备的不同需求,它的分辨率适配就显的尤其的重要。

如果读者之前对Cocos2d-x的分辨率适配原理有一点的了解,那么我想这部分内容理解起来应该是很容易的,但考虑了下初学者,所以下面我们还是简单的说说原理吧。

Cocos2d-x以及Quick中图片显示到屏幕有下面两个逻辑过程,两个过程结合在一起,影响了最终的显示效果。

  1. 资源布局到设计分辨率;
  2. 设计分辨率布局到屏幕。

其中设计分辨率是指我们在config文件中设置的CONFIG_SCREEN_WIDTH 和 CONFIG_SCREEN_HEIGHT,它相当于一个参考分辨率。只有确定了我们的参考分辨率,才能得到我们的图片资源的缩放比例。

在第一个过程中,我们需要通过以下函数来完成相应的转换:

cc.Director:getInstance():setContentScaleFactor(value)

setContentScaleFactor方法决定了图片资源显示到屏幕的缩放因子,顾名思义就是决定了整个游戏内容放大或者缩小的比例系数。
它的参数由(背景图片资源宽高/设计分辨率宽高)得到,而不是通过(背景图片资源宽高/屏幕宽高)得来。这样也就避开了游戏开发者去直接关注移动设备的实际屏幕。

setContentScaleFactor通常会用两个方式来设置参数,不同的设置方法会有不同的缩放负作用。

  • 用(资源高/设计分辨率高)的高度比作为参数,也就是内容的缩放因子,这样保证了背景资源的垂直方向在设计分辨率范围内的全部显示,但在水平方向上可能会溢出屏蔽或留有黑边。
  • 用(资源宽/设计分辨率宽)的宽度比作为内容缩放因子,保证了背景资源的水平方向在设计分辨率范围内的全部显示,但在垂直方向上可能会超出屏蔽范围或留有黑边。

第二个过程中,我们需要通过以下函数接口完成转换:

setDesignResolutionSize(width, height, cc.ResolutionPolicy)

setDesignResolutionSize方法会在display.lua中被调用,所以这里我们不用管它,只需要注意它的参数设置就好。
其中参数 width 和 height 指的是设计分辨率的宽、高,cc.ResolutionPolicy 是分辨率适配策略,它们分别由config.lua文件中的 CONFIG_SCREEN_WIDTH、CONFIG_SCREEN_HEIGHT 和 CONFIG_SCREEN_AUTOSCALE来设置。
Quick中CONFIG_SCREEN_AUTOSCALE的值有三种情况:

  • FIXED_WIDTH:保持传入的设计分辨率宽度不变,根据屏幕分辨率修正设计分辨率的高度。
  • FIXED_HEIGHT:保持传入的设计分辨率高度不变,根据屏幕分辨率修正设计分辨率的宽度。
  • FILL_ALL:保证了设计区域总有一个方向铺满屏幕,另一个方向可能超出屏幕或留有黑边。

以上两个过程相辅相成,它们相互影响,所以做好分辨率适配必须确保两步坚固。
说到这里我不得不提的是,在做分辨率适配的时候,常有人忽略以上的第一个过程,因此作为小白的我还是会经常遇到那么一些人问:为什么我的分辨率适配护好了还是有黑边,还是有问题?
对此我要说:请设置内容缩放因子。

下面我们以本教程游戏作为例子,看看具体的实现方法。

分辨率适配的实现

本教程将做一个横屏的飞行游戏,我们需要做到让背景图在高度方向上全部显示,所以显然地,如果高度方向上全部显示,那么在宽度方向上必然会做出一些牺牲(要么被裁减,要么留黑边(留黑边的问题可以通过将图片宽度做得更宽一点来解决))。

要实现这上述目标,需要保证各过程都是在宽度方向上裁减。所以我们给出了以下的实现过程:

1、首先我们选择 1136 x 640 的图片资源,这样宽高比够大,能确保在某些极端的分辨率下也能完整不留黑边的显示整个游戏画面。

2、接着打开src/config.lua,设置配置信息,如下:

CONFIG_SCREEN_ORIENTATION = "landscape"
CONFIG_SCREEN_WIDTH = 480
CONFIG_SCREEN_HEIGHT = 320
CONFIG_SCREEN_AUTOSCALE = "FIXED_HEIGHT"

CONFIG_SCREEN_ORIENTATION这个配置告诉 Quick 引擎,游戏是横屏的。该参数是拿来适配的时候使用的。

注意:如果使用 Cocos Code IDE 调试程序,那么请确保config.json配置文件的isLandscape 字段值为true,两者保持一致。反正,若游戏是竖屏,那么请确保isLandscape值为false。

对于 CONFIG_SCREEN_WIDTH 和 CONFIG_SCREEN_HEIGHT 的配置,其实我觉得只要配置好 CONFIG_SCREEN_AUTOSCALE 和内容缩放因子,那就不会有什么问题。

因为是横屏游戏,所以我们选择了 FIXED_HEIGHT 作为适配模式——让 Y 轴方向能完全显示在屏幕上。

3、最后,打开src/app/MyApp.lua,修改run()方法,加入内容缩放因子。

function MyApp:run()
cc.FileUtils:getInstance():addSearchPath("res/")
cc.Director:getInstance():setContentScaleFactor(640 / CONFIG_SCREEN_HEIGHT)
self:enterScene("MainScene")
end

因为我们选择了FIXED_HEIGHT。故此,计算内容缩放因子时,其参数为:资源高度 / 屏幕分辨率高度。关于MyApp:run()方法,我们后面将做详细的讲解。

好了,本章我们就到这里吧!也不知道是不是我太啰嗦,写了这么多居然才讲了一个.lua文件,看来下章开始不能再啰嗦了。另外,以上分辨率适配的验证将在后面添加资源图片的时候得到验证。

Quick-Cocos2d-x初学者游戏教程1

前言

虽然之前已经写过了好些 Cocos2d-x 相关的教程和文档,但本次却是我第一次接触 Quick,第一次接触 Lua,所以此次的教程本人将站在一个初学者的角度(看到这里是不是想白眼我了,哈哈,别切啊!尽管第一次,但我身边可是有很多 Quick 大神的,廖大大也在旁边办公室,没准撒个娇大神就把他知道的全部要点倾囊相授了啦!),全方位的解析 Quick 的学习过程,并同大家一起学习如何利用 Quick-Cocos2d-x 开发一款属于自己的游戏,包教包会的哦。
好了,那么下面我们就开始进入正题吧。

Quick-Coco2d-x是什么?

首先,想了解 Quick-Coco2d-x 就必须先知道 Cocos2d-x 是什么,不过我想关于 Cocos2d-x 的介绍这里就不用我来废话了吧,毕竟这么牛的游戏引擎还是应该很点名气的吧!

其次,由于 Cocos2d-x 中使用的是 C++ 语言,而 C++ 又对开发人员要求较高,所以逐渐地,开发者们开始将 Cocos2d-x 的 C++ 接口转成了 Lua 接口,从而衍生出了 Cocos2d-lua 的版本。而 Quick(Quick-Coco2d-x)是 Cocos2d-lua 的一个豪华增强和扩展版本,它重写了支持代码、解决了内存泄露和只能使用全局函数做回调等等问题。Quick 能让开发者使用 Lua 这种简单易懂的脚本语言来编写游戏,并大大提高了开发效率。现在廖大大的 Quick 团队也已接手了 Cocos2d-lua 的开发和维护工作,所以未来 Quick 和 Cocos2d-lua 将有望完全合并起来。

本次教程所用 Quick-Coco2d-x 版本为 v3.3 Final,大家可在http://cn.cocos2d-x.org/download/链接中找到对应的下载地址并安装该程序。

注意:不要把 Quick 安装到根目录,或者带有空格或中文的路径中。另外,Quick-Cocos2d-x 需要 Python 的支持,所以请自行检测你的电脑是否装有Python,方法是在终端中输入 python命令行,如未安装请先下载安装2.x版本的 Python。

Quick 安装完成后,在它的根目录下可以找到有两个名为setup_mac.sh、setup_win.bat的批处理脚本,它们分别是搭建Mac和Windows开发环境的脚本,根据自己系统的需要运行相应的脚步,就可以自动为你完成 Quick 环境的配置。在此之后,我们就可以双击安装目录下的 player3 图标(Windows 下桌面上会生成 player 的快捷键),启动 Quick 自带的模拟器了。在该模拟器界面中,我们可以创建、打开、运行项目,同时还能查看很多 Quick 自带的示例项目。

关于 Quick 更多的使用说明可参考安装目录下的 README 文件。

Quick-Coco2d-x开发工具

一般情况下,我们通常都会采用Cocos Code IDE作为开发工具来快速开发游戏,这里Cocos Code IDE是一个基于 Eclipse 的跨平台 IDE,专门为 Cocos2d-x Lua & JavaScript 开发人员准备,通过 IDE 你可以方便的创建游戏工程、编写并且支持在不同平台上调试代码、实时查看代码被改变后的效果,最终直接发布成一个可上架的安装包。

然而,最近学习Quick的时候听同事和很多用户反馈说:Quick-Coco2d-x v3.3 Final这个版本在Cocos Code IDE上还存在一些Bug,并且执行效率也相对较慢。所以在大神的推荐下,本教程我们就不选用Cocos Code IDE作为开发工具了,而是使用另一种高效的方法来完成该跑酷游戏的开发——Sublime + QuickXDev。

当然如果你非要用Cocos Code IDE还是可以的,其安装和使用说明可参考:Cocos Code IDE + Quick-Cocos2d-x 快速开发游戏一文。

** 开发工具的安装配置 **

Sublime Text 是一个具有漂亮的用户界面和强大的功能的代码编辑器,也是HTML和散文先进的文本编辑器,它的很多功能都依赖于其强大的插件系统。Sublime Text支持Lua语言,但它本身不具有像代码提示这样的功能,所以要想用Sublime Text快速的开发Quick-Coco2d-x程序,我们就必须安装强大的QuickXDev插件。

Sublime Text的下载地址为:http://www.sublimetext.com/,下载后直接安装即可。

QuickXDev的下载地址为:http://git.oschina.net/lonewolf/QuickXDev,将它下载解压之后重命名为QuickXDev,然后把该QuickXDev文件夹放入到Sublime Text的Packages目录下(可通过Sublime Text->Preferences->Browse Packages打开)。

接着依次打开Preferences->Package Settings->QuickXDev->Settings–Default,如下图所示:
openset
复制该处的内容到Preferences->Package Settings->QuickXDev->Settings–User(此时User是空白的)中,同时在 “quick_cocos2dx_root” 项的后面设置Quick-Coco2d-x的安装路径,如下图所示:

set

设置完成后,User的内容将会覆盖Default下的设置。
注意:以上路径应为你自己的安装路径,如果是Windows系统,则该处的路径形如:

"quick_cocos2dx_root": "D:\\Quick\\quick-3.3"

新建项目

开发工具准备就绪以后,下面我们就可以开始创建我们的项目了.

首先启动 Quick 下的 player3,在这儿的示例标签下你可以看到很多Quick自带的示例,对于初学者来说,看看这些示例的使用方法会对我们学习Quick有很大的帮助,它也是快速学习Quick极好的教材。其界面如下图所示:
quick-example
接着我们来新建一个项目,点击界面上的“新建项目”,player会自动切换到新建项目的界面。
create

设置好新建项目的存放路径,包名,屏幕方向,以及是否复制C++源码等选项后,我们就可以点击右下角的 “Create Project” 按钮创建项目了。这里需要注意的是,如果你的项目不涉及到 C++ 部分,那么可以取消“Copy Source Files”项的勾选,这样可以加快项目的创建速度。

点击 Create Project 按钮后,你会发现右下角的 “Create Project” 按钮变成了“Open..”,同时还会出现一个显示创建项目结果的终端窗口。待终端窗口显示创建完成时,我们就可以点击“Open..”打开项目了。

一个默认创建好的项目其实就是个程序员最熟悉的“Hello World”程序,然后后面我们就可以以这个“Hello World”程序为基础来编写自己的游戏。

每个新建的Quick程序都带了一个控制台窗口,如下图所示。这个控制台窗口是player的输出窗口,它包括了你打印的日志以及崩溃日志,当你的程序报错时,它的输出日志将是很好的检验凭证。

helloworld

项目目录分析

为了更快更好的学习Quick程序开发,了解其项目结构是很有必要的,所以下面我们就来依次看看引擎和新建项目的目录结构。

引擎目录结构分析

打开 Quick 安装目录,其结构如下图所示:
quick

  • build:该目录是 Cocos2d-x 的项目存放目录。
  • cocos: 改文件夹中包含了大部分引擎的库文件,其中包括:2d、3d、声音、基础库、数学库、物理库等等一系列相关的类文件。
  • docs:该文件夹下包含了引擎的API文档、发布文档(最新版本更改介绍,运行环境要求,编译环境要求及如何运行测试用例的相关命令)、Cocos编程规范等等文档。我们可以通过它查看引擎的代码API,以及最新版本更改介绍,quick运行环境要求,编译环境要求及如何运行测试用例的相关命令。里面的文件多是html和md格式的。
  • extensions: 其中主要是GUI扩展库.
  • external中包含物理引擎第三方库,Box2D和chipmunk;数据库第三方库,sqlite3;网络第三方库,webp,websockets;以及一些其他第三方库,像编码转换库、数据格式库等等。
  • licenses里面包含了引擎中用到的各种许可证文件。LICENSE_SpiderMonkey,spider引擎中用到的SpiderMonkey-JS运行环境,需要此许可证,该许可证适用于MPL/GPL/LGPL几种许可证LICENSE_chipmunk,LICENSE_JS,LICENSE_lua等等。引擎在这些许可证下可以对相应的源代码进行任意拷贝和修改。
  • quick:这个是Quick引擎代码。其中包含了创建各个平台新工程的批处理工具,Quick框架的核心目录,2dx和一些其他依赖的c++文件,模版工程,Quick所带的例子等等Quick的核心文件。
  • README.html/README.md:Quick的使用指南,关于Quick的安装、使用、创建等等信息都可以出这里获取,它其实相当于docs内文件的目录。
  • setup_mac.sh: 搭建Mac开发环境的脚本。
  • setup_win.bat: 搭建Windows开发环境的脚本。
  • tools:Quick用做luabinding的工具,可用来导出自定义的C++类。
  • version:版本标示。

新项目目录结构分析

打开新建项目的目录,我们来分析下新建项目的目录结构,其结构如下图所示:

file

  • config.json: 项目信息配置文件。
  • debug.log: 项目日志,即打印控制台窗口输出的所有日志文件。
  • frameworks: 存放Cocos2d-x引擎核心代码及各个平台运行时资源。
  • res:存放项目资源的文件夹,也就是说,我们游戏开发中用到的所有图片、字体、音频等资源都放在这里。
  • runtime:存放预编译的运行时库。
  • src:项目源码所存放文件夹,即游戏中的所有的 .lua 文件都放在这里。

以上目录中 res 和 src 文件夹是比较最要的,开发中我们也只需要对这两个文件夹里的内容进行操作,就可以实现游戏的开发。

在新项目的src文件夹中,现在你是可以看到一些 .lua 文件的,这些就是我们工程的lua代码。接下来我们简单的介绍下src中各项的功能:

  • cocos: cocos引擎代码
  • framework: quick的核心部分,在Cocos2d-x基础上自己搭建的一套framework
  • config.lua: 工程配置文件,包括分辨率适配等信息
  • main.lua: 工程入口
  • app: 工程的界面等文件,存放我们的游戏代码
    • MyApp.lua: 游戏的第一个界面
    • scenes: 存放游戏各个场景代码的文件夹
      • MainScene: 游戏的第一个场景

在游戏开发中,需要修改和添加界面时,我们只需要在相应的文件夹中添加场景就可以了。

好了,这章就算讲完了,下一章我们将先讲解新建项目各个lua文件的代码结构和使用方法,并开始着手新游戏的开发。

[Cocos2d-x v3.x官方文档]节点剪裁


zeroyang原创,首发于泰然,转载请注明出处
https://github.com/chukong/cocos-docs/blob/master/manual/framework/native/v3/ClippingNode/zh.md
欢迎大家斧正错误,提交PR。

Cocos2d-x官方中文文档 v3.x

ClippingNode的使用

概述

ClippingNode(裁剪节点)可以用来对节点进行裁剪,可以根据一个模板切割图片的节点,生成任何形状的节点显示。

ClippingNode是Node的子类,可以像普通节点一样放入Layer,Scene,Node中。

  • ClippingNode 原理:

    ClippingNode是利用模板遮罩来完成对Node区域裁剪的技术。如何理解ClippingNode的遮罩?看下图的例子吧。

    所谓模板,就是一个形状,透过该形状可看到底板上的图层,如果底板上没有任何内容,则直接看到Layer上的内容,而底板上的东西又不会妨碍Layer上的东西,即模板在底板之外的空间对于Layer来说是透明的。

ClippingNode 常用方法

  1. create

    可以使用 static ClippingNode* create();方法创建一个ClippingNode对象。如下:

     auto clipper = ClippingNode::create();
    


    也可以使用 static ClippingNode* create(Node *stencil);方法创建;在创建的时候指定裁剪模板

     auto stencil = Sprite::create("CloseNormal.png");//模板节点
     clipper = ClippingNode::create(stencil);
    
  2. setStencil
    可以使用void setStencil(Node *stencil);方法设置“裁剪模板”节点。 如下:

     clipper->setStencil(stencil);//设置裁剪模板
    
  3. setInverted

    可以使用void setInverted(bool inverted);方法,设置是显示被裁剪的部分,还是显示裁剪。true 显示剩余部分。false显示被剪掉部分。 如下:

     clipper->setInverted(true);//设置底板可见,显示剩余部分
    
  4. setAlphaThreshold

    可以使用void setAlphaThreshold(GLfloat alphaThreshold);,设置alpha阈值, 只有模板(stencil)的alpha像素大于alpha阈值(alphaThreshold)时内容才会被绘制。 alpha阈值(threshold)范围应是0到1之间的浮点数。 alpha阈值(threshold)默认为1。 如下:

     clipper->setAlphaThreshold(0);//设置绘制底板的Alpha值为0
    

ClippingNode示例

    auto bg = LayerColor::create(Color4B(255, 255, 255,255));
    this->addChild(bg, -1);//1

    auto stencil = Sprite::create("CloseNormal.png");
    stencil->setScale(2);//2
    auto clipper = ClippingNode::create();
    clipper->setStencil(stencil);//设置裁剪模板 //3
    clipper->setInverted(true);//设置底板可见
    clipper->setAlphaThreshold(0);//设置绘制底板的Alpha值为0
    this->addChild(clipper);//4

    auto content = Sprite::create("HelloWorld.png");//被裁剪的内容
    clipper->addChild(content);//5

    clipper->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
  1. 添加了一个白色的LayerColor作为背景层。
  2. 创建一个精灵,作为裁剪模板,并放大2倍
  3. 创建ClippingNode节点,并设置裁剪模板
  4. 设置裁剪显示,Alpha阈值,并将裁剪节点加到层中
  5. 设置被裁剪的内容

运行效果如图:

将 clipper->setInverted(true); 改为 clipper->setInverted(false);
运行效果如图:

  • 资源图片

骨骼动画详解-Cocos Studio


任珊原创,首发于泰然,转载请注明出处
https://github.com/chukong/cocos-docs/blob/master/manual/framework/native/v3/spine-cocostudio/zh.md
欢迎大家斧正错误,提交PR。

Cocos2d-x官方中文文档 v3.x

在之前的骨骼动画详解-Spine一文中,我们已经介绍过什么是骨骼动画,骨骼动画的优缺点,以及骨骼动画编辑器-Spine的使用。接下来本文将结合另一个可编辑骨骼动画的编辑器(Cocos Studio)介绍骨骼动画的使用。

Cocos Studio介绍

Cocos Studio是一套基于Cocos2d-x的免费游戏开发工具集,它能帮助开发者快速创建游戏资源,将大部分繁琐的游戏开发工作使用编辑器来快速制作,进一步帮助游戏开发者减短开发周期、提高开发效率。

Cocos Studio本身不光只是针对骨骼动画的编辑而设计的,它还提供了UI、场景和数据等信息的编辑工作。就当前的Cocos Studio而言,主要分两种,一种是Win版本的Cocos Studio,另一个则是刚刚发布不久的Mac版 Cocos Studio v1.0 alpha1。前者由UI编辑器、动画编辑器、场景编辑器和数据编辑器四部分组成,分别用于处理游戏中的UI界面、动画资源、游戏场景和游戏数据。而Mac版的Cocos Studio整合了原有的UI和动画编辑器,使小伙伴们的使用更加自由。但由于Mac版的编辑器现在还不稳定,所以本文将介绍Win版本的Cocos Studio。

Win版Cocos Studio的动画编辑器支持关键帧动画,序列帧动画,骨骼动画等多种动画编辑方式。并且它还支持碎图导出,整图导出等多种资源优化方式。同时动画编辑器支持对Flash,PSD,Plist资源的解析。

创建骨骼动画

首先,打开Cocos Studio 的 Animation Editor(动画编辑器),新建一个动画工程。
同Spine一样,Cocos Studio动画编辑器也有两种模式,但这里是形体模式和动画模式。用户需要在形体模式下组装角色部件,并为其绑定骨骼;并在动画模式下调整骨骼相应属性生成骨骼动画。

下面我们先来对编辑器整体做一个认识,见下图。

形体模式下:


动画模式下:

上面两图中,标记为1的部分是渲染区域,也就是我们的画布,它是资源布局的主编辑区,在该区域可以对各对象进行移动,缩放,旋转的操作,所有主要的操作结果都会在这个区域中显示完成。

第2部分是快捷菜单栏,该窗口中有一些常用操作,其中包括模式的切换,创建骨骼,缩放,旋转等等一系列操作。

第3部分是资源栏,本项目中使用的所有资源都必须导入到该面板才可以使用。

第4部分是预览区域,当选中资源栏的资源时,会在该区域中显示,达到预览的作用。

第5部分是对象结构栏,编辑器将根据对象结构栏中对象的顺序依次渲染对象,在最下层的对象将先于渲染,也就是说它可能会被后渲染的对象遮盖。另外,对象的顺序在该栏中是可调的。

第6部分是属性栏,当选中一个对象时,属性窗口会显示出该对象的所有属性。修改任意属性都可以立即改变该节点在渲染区域的状态。

第7部分是动作列表栏,一个动画工程是允许有多个动作的,比如:行走、跳跃、奔跑等等。所以在该栏中用户可以创建多个动作,并在多个动作中切换。

第8部分是动画帧面板,该面板将显示画布中所有对象的序列帧,用户可通过添加帧和改变对象属性创建动画序列帧。

对编辑器有了大致的了解后,现在就可以开始编辑动画了。

  1. 在形体模式下,选择 文件->导入资源 或在资源栏中右键选择需要导入的资源文件,也可直接将资源拷入工程的Resources文件夹目录下,然后刷新资源面板。
  2. 将资源拖到渲染区,并摆好位置。
  3. 开始创建骨骼:选中快捷菜单栏中创建骨骼的按钮,在角色身体的各部位单击左键并拖动鼠标画出骨骼。
  4. 将资源素材与骨骼绑定,右击渲染区的资源素材,选择“绑定到骨骼”,然后选择骨骼(选择的骨骼会高亮显示),就可以实现骨骼的绑定。
  5. 当绑定好所有素材和骨骼后,右击骨骼选择“绑定父关系”,再选择该骨骼的父骨骼(选择的骨骼同样会高亮显示),这样依次根据身体部位的“父子”层级关系设定好。
  6. 切换到动画模式,选中相应控件,移动鼠标到动画帧一栏的某帧处,然后,改变被选择控件的某个属性,如旋转它,这样就能实现流畅的补间动画。
  7. 导出项目为程序可用的资源:导出的资源在工程目录的Export/..文件夹下,一共有三个资源文件,分别是 .ExportJson,.plist 和 .png文件。ExportJson文件中记录了骨骼动画的描述信息,plist文件则是记录碎图整合成大图后图片的位置描述信息,png文件是整合的大图。

在 Cocos2d-x 中加载动画资源

前面我们花了很多精力来创建骨骼动画,然而要将它运行在实际的项目中却非常的简单,只需几行代码,当然在这之前我们需要将动画编辑器导出的资源复制到项目Resource目录中去。

同样地,在Cocos2d-x程序中使用Cocos Studio动画首先需要包含相关头文件,如下:

#include "cocostudio/CocoStudio.h"
using namespace cocostudio;

创建一个骨骼动画对象,需要将动画文件和资源文件载入到程序。这里我们通过ArmatureManager动画数据管理器来加载动画。ArmatureManager本身是一个单例,它管理整个场景中的Armature。而Armature则封装了我们播放动画需要的Animation。由此可见,这是一个三层缔结的层次结构。其中ArmatureManager最大,然后是Armature,最后是Animation。

说完了原理,下面来看看代码。修改init函数, 在return前加入如下代码:

ArmatureDataManager::getInstance()->addArmatureFileInfo("NewAnimation0.png" , "NewAnimation0.plist" , "NewAnimation.ExportJson");
Armature *armature = Armature::create( "NewAnimation");
armature->setPosition(Point(visibleSize.width * 0.5, visibleSize.height * 0.5));
// 播放动画
armature->getAnimation()->play("walk");
this->addChild(armature);

效果图:

我们在动画编辑器中编辑的动作就是Animation,一个动画工程中可以编辑多个动作,也就是动作列表中可创建多个动作。如下图所示:

所以播放动画需要根据具体地需要来播放,这样才能知道用户要播放的动画是哪一个。可以像上面代码一样指定动画名来播放动画,也可以通过指定动作编号来播放动画,如下:

armature->getAnimation()->playWithIndex(0);

播放连续地动画可通过以下函数实现:

void playWithNames(const std::vector& movementNames, int durationTo = -1, bool loop = true);
void playWithIndexes(const std::vector& movementIndexes, int durationTo = -1, bool loop = true);

如何用Unity 2D制作一个像疯狂喷气机的游戏——第三部分

原文地址:http://www.raywenderlich.com/69675/make-game-like-jetpack-joyride-unity-2d-part-3 泰然翻译组:小荄、Verky。校对:glory。

如何用Unity 2D制作一个像疯狂喷气机的游戏——第三部分

这是关于如何用Unity 2D制作一个像疯狂喷气机的游戏的系列教程的最后一个部分。如果你落下了教程之前的部分,你最好先去完成之前教程的学习。它们分别是:第一部分第二部分

就像我在上个部分的结尾提到的那样,这个部分我们将享尽所有的乐趣。这将是走到这里的奖励。:)

在这个部分你将添加激光,硬币,音效,音乐甚至是视差滚动。好了,聊了够多了,让我们开始享受乐趣吧!

阅读全文»

如何做一款类似疯狂喷气机的游戏--Part2

原文地址:http://www.raywenderlich.com/69544/make-game-like-jetpack-joyride-unity-2d-part-2?utm_source=tuicool 泰然翻译组:xiao yu 校对:lareina。

本文是关于如何使用Unity 2D引擎制作一款类《疯狂喷气机》游戏教程的第二部分。如果你想要参见第一部分,请参见这里。

在教程的第一部分,我们实现了这样一个简单的小游戏-一只可爱的小老鼠在房间中上自由的飞来飞去,再辅以漂亮的火焰,游戏场景看起来非常炫酷。然而,尽管火焰看起来比较赏心悦目,但是仅仅简单的添加喷气火焰并不能使游戏具有很好的可玩性。

阅读全文»

?>