cocos2d消灭星星怎样控制cocos 下落动画代码和左移的顺序

quick cocos2d-x重写消灭星星
编辑:www.fx114.net
本篇文章主要介绍了"quick cocos2d-x重写消灭星星 ",主要涉及到quick cocos2d-x重写消灭星星 方面的内容,对于quick cocos2d-x重写消灭星星 感兴趣的同学可以参考一下。
&&& 之前学习过c++在cocos2d-x游戏引擎上实现的消灭星星游戏,为了熟悉quick cocos2d-x以及Lua语言,我使用2.1.4版本的quick cocos2d-x重写了消灭星星,不过只是实现了其基本的消除,移动,计分以及过关等功能,一些文字漂移、粒子特效等功能有待以后完善。
&&& 该游戏的界面非常简单,只有两个场景的切换,首先是一个开始场景,该场景下有一个背景图片以及一个按钮,点击该按钮可以进入到游戏场景界面。开始场景的主要实现代码如下:
1 function MainScene:ctor()
self.bg = display.newSprite("bg_menuscene.jpg", display.cx,display.cy)
self:addChild(self.bg)
local item ={}
item[1]= ui.newImageMenuItem({image = "menu_start.png", imageSelected = "menu_start.png",
listener = function()
game.enterGameScene() end , x = display.cx, y = display.cy})
local menu = ui.newMenu(item)
self:addChild(menu)
10 end
其中菜单按钮用table来实现,在Lua语言中没有其他的数据结构,只有table,利用table可以实现各种数据结构,下面讲解星星的消除算法的时候会详细介绍,这里的按钮事件是game.enterGameScene(),这是在game文件中实现的一个函数,用于进入游戏场景,在game文件中game被申明为一个全局的table变量,可以在其他的文件中使用。
&& 在游戏场景上面添加了一个层,该层用来实现星星矩阵的初始化显示,分数菜单的显示以及触摸事件。我们先看星星矩阵的初始化:
1 local STAR_RES_LIST = {"blue.png","green.png",
2 "orange.png","red.png","purple.png"}
4 function MatrixStar:initMatrix()
--[[self.STAR[i][j]是一个表,其中i表示星星矩阵的行,j表示列,它包含四个元素
self.STAR[i][j][1]表示星星精灵
self.STAR[i][j][2]表示该精灵的颜色
self.STAR[i][j][3]表示该精灵是否被选中
self.STAR[i][j][4]表示该精灵的x轴坐标
10
self.STAR[i][j][5]表示该精灵的y轴坐标
math.randomseed(os.time())
for row = 1, ROW do
14
local y = (row-1) * STAR_HEIGHT + STAR_HEIGHT/2
15
self.STAR[row] = {}
16
for col = 1, COL do
17
self.STAR[row][col] = {}
18
local x = (col-1) * STAR_WIDTH + STAR_WIDTH/2
19
local i=math.random(1,5)
20
local star = display.newSprite(STAR_RES_LIST[i])
21
self.STAR[row][col][1] = star
22
self.STAR[row][col][2] = i
23
self.STAR[row][col][3] = false
24
star:setPosition(x,y)
25
self.STAR[row][col][4] = x
26
self.STAR[row][col][5] = y
27
self:addChild(star)
28
end
30 end
这里利用随机函数,在for循环中生成了不同颜色的星星精灵表 STAR_RES_LIST记录了六种颜色的星星精灵,使用表self.STAR[i][j]记录了每一个星星的颜色、位置、是否被选中,这些信息用于后面对星星的消除算法,在C++中我们可以使用一个结构体来定义这些变量,而Lua中使用的是table. 分数的菜单使用了3个Label对象来实现的,分别记录了最高分数,目标分数以及当前分数,并且通过设置TAG来方便以后对该Label对象实现分数更新。
1 HSCORETAG = 100
2 LEVELTAG = 101
3 CSCORETAG = 102
5 function MatrixStar:setLabel(Hscore,Level,Goal,Cscore)
local HscoreUI = ui.newTTFLabel({
text = string.format("HighestScore: %s", tostring(Hscore)),
x, y = display.left, display.top,
HscoreUI:setScale(SCALE)
11
HscoreUI:setPosition(display.right, display.cy)
12
HscoreUI:setPosition(display.cx, display.top - SCALE * HscoreUI:getContentSize().height)
13
self:addChild(HscoreUI)
14
HscoreUI:setTag(HSCORETAG)
15
local LevelUI = ui.newTTFLabel({
17
text = string.format("Level: %s".." ".."Goal: %s", tostring(Level),tostring(Goal)),
18
x, y = display.left, display.top,
LevelUI:setScale(SCALE)
21
LevelUI:setPosition(display.cx, display.top - SCALE * (HscoreUI:getContentSize().height +
LevelUI:getContentSize().height))
23
self:addChild(LevelUI)
24
LevelUI:setTag(LEVELTAG)
25
local CscoreUI = ui.newTTFLabel({
27
text = string.format("CurrentScore: %s", tostring(Cscore)),
28
x, y = display.left, display.top,
CscoreUI:setScale(SCALE)
31
CscoreUI:setPosition(display.cx, display.top - SCALE * (HscoreUI:getContentSize().height +
LevelUI:getContentSize().height + CscoreUI:getContentSize().height))
33
self:addChild(CscoreUI)
34
CscoreUI:setTag(CSCORETAG)
35 end
接下来是实现触摸事件,在触摸事件中要将点中的星星和他周围与他颜色相同的星星消除,这里先用一个table记录选中的相同颜色星星个数,每次点击都要先将其设置为空。并且使用一个table来帮助选出周围与触摸星星颜色相同的星星,当触摸到一个星星后,将该星星插入到该表中,然后遍历它四周的星星是否与该星星相同,相同则插入表中。然后将表中的第一个元素从表中移除,接着对表中的元素进行上述操作,值到表为空为止。这个过程实际上就是利用队列来实现一个广度优先算法。具体代码如下:
local travel = {}
--当作一个队列使用,用于选出周围与触摸星星颜色相同的星星
if self.STAR[i][j][1] == nil then
table.insert(travel, {self.STAR[i][j][1], i, j})
while #travel ~= 0 do
if i + 1 &= ROW and self.STAR[i][j][3] ~= true and
self.STAR[i][j][2] == self.STAR[i + 1][j][2] then
10
table.insert(travel, {self.STAR[i+1][j][1],i+1,j})
11
if i-1 &= 1 and self.STAR[i][j][3] ~= true and
14
self.STAR[i][j][2] ==self.STAR[i-1][j][2] then
15
table.insert(travel, {self.STAR[i-1][j][1],i-1,j})
16
if j+1 &= COL and self.STAR[i][j][3] ~= true and
19
self.STAR[i][j][2] ==self.STAR[i][j+1][2] then
20
table.insert(travel, {self.STAR[i][j+1][1],i,j+1})
if j-1 &= 1 and self.STAR[i][j][3] ~= true and
24
self.STAR[i][j][2] ==self.STAR[i][j-1][2] then
25
table.insert(travel, {self.STAR[i][j-1][1],i,j-1})
26
if self.STAR[i][j][3] ~= true then
29
self.STAR[i][j][3] = true
30
table.insert(self.SELECT_STAR,{self.STAR[i][j][1],i,j})
31
table.remove(travel,1)
--table没有类似双向队列的功能直接删除第一个元素
34
if #travel ~= 0 then
i, j = travel[1][2], travel[1][3] --取出表的第一个元素
36
&在C++的deque容器可以在O(1)的时间复杂度中将队头元素移除,而这里的table.remove的时间复杂度为O(n),不知道是否有更好的
&方法实现。当我们得到选中的星星后便可以更新分数,将选中的星星删除同时更新剩余星星的位置。位置的更新主要涉及垂直方向与水平方向。先看垂直方向,当我们删除部分星星时,这些星星上面的星星自然要掉下来,我们用掉下来的星星信息覆盖已删除星星的信息,并且将掉下来的星星信息设为nil。再看水平方向,当有一列的星星全部删除时,我们要求该列右边的星星能自动向左移动,实现过程与垂直方向类似,源代码如下:
1 function MatrixStar:UpdateMatrix()
for i = 1, ROW do
for j = 1,COL do
if self.STAR[i][j][1] == nil then
local up = i
local dis = 0
while self.STAR[up][j][1] == nil do
dis = dis + 1
up = up + 1
10
if(up&ROW) then
11
for begin_i = i + dis, ROW do
16
if self.STAR[begin_i][j][1]~=nil then
self.STAR[begin_i-dis][j][1]=self.STAR[begin_i][j][1]
18
self.STAR[begin_i-dis][j][2]=self.STAR[begin_i][j][2]
19
self.STAR[begin_i-dis][j][3]=self.STAR[begin_i][j][3]
20
local x = (j-1)*STAR_WIDTH + STAR_WIDTH/2
local y = (begin_i-dis-1)*STAR_HEIGHT + STAR_HEIGHT/2
self.STAR[begin_i-dis][j][4] = x
23
self.STAR[begin_i-dis][j][5] = y
24
self.STAR[begin_i][j][1] = nil
25
self.STAR[begin_i][j][2] = nil
26
self.STAR[begin_i][j][3] = nil
27
self.STAR[begin_i][j][4] = nil
28
self.STAR[begin_i][j][5] = nil
29
for j = 1, COL do
36
if self.STAR[1][j][1] == nil then
37
local des = 0
local right = j
39
while self.STAR[1][right][1] == nil do
40
des = des + 1
41
right = right + 1
42
if right&COL then
43
for begin_i = ROW, 1,-1 do
47
for begin_j = j + des, COL do
if self.STAR[begin_i][begin_j][1] ~= nil then
49
self.STAR[begin_i][begin_j-des][1]=self.STAR[begin_i][begin_j][1]
50
self.STAR[begin_i][begin_j-des][2]=self.STAR[begin_i][begin_j][2]
51
self.STAR[begin_i][begin_j-des][3]=self.STAR[begin_i][begin_j][3]
52
local x = (begin_j-des-1)*STAR_WIDTH + STAR_WIDTH/2
local y = (begin_i-1)*STAR_HEIGHT + STAR_HEIGHT/2
self.STAR[begin_i][begin_j-des][4] = x
55
self.STAR[begin_i][begin_j-des][5] = y
56
self.STAR[begin_i][begin_j][1] = nil
57
self.STAR[begin_i][begin_j][2] = nil
58
self.STAR[begin_i][begin_j][3] = nil
59
self.STAR[begin_i][begin_j][4] = nil
60
self.STAR[begin_i][begin_j][5] = nil
61
end
66 end
星星的位置信息通过上述代码得到更新,我们通过设置Update事件,在每帧中更新星星的位置,为了有一个移动的效果,我们不是直接使用setPostion到目的位置,而是使用一个速度参数使其移动到目的位置。
1 function MatrixStar:updatePos(posX,posY,i,j)
if posY ~= self.STAR[i][j][5] then
self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5] - MOVESPEED)
if self.STAR[i][j][1]:getPositionY() & self.STAR[i][j][5]
self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5])
local x, y = self.STAR[i][j][1]:getPosition()
if posX ~= self.STAR[i][j][4] then
11
self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4] - MOVESPEED)
12
if self.STAR[i][j][1]:getPositionX() & self.STAR[i][j][4]
self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4])
14
end
16 end
整个游戏的基本代码就这些,代码写的比较乱,有待改进,但还是能跑起来,源代码地址:
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:&&& 之前学习过c++在cocos2d-x游戏引擎上实现的消灭星星游戏,为了熟悉quick cocos2d-x以及Lua语言,我使用2.1.4版本的quick cocos2d-x重写了消灭星星,不过只是实现了其基本的消除,移动,计分以及过关等功能,一些文字漂移、粒子特效等功能有待以后完善。
&&& 该游戏的界面非常简单,只有两个场景的切换,首先是一个开始场景,该场景下有一个背景图片以及一个按钮,点击该按钮可以进入到游戏场景界面。开始场景的主要实现代码如下:
1 function MainScene:ctor()
self.bg = display.newSprite("bg_menuscene.jpg", display.cx,display.cy)
self:addChild(self.bg)
local item ={}
item[1]= ui.newImageMenuItem({image = "menu_start.png", imageSelected = "menu_start.png",
listener = function()
game.enterGameScene() end , x = display.cx, y = display.cy})
local menu = ui.newMenu(item)
self:addChild(menu)
其中菜单按钮用table来实现,在Lua语言中没有其他的数据结构,只有table,利用table可以实现各种数据结构,下面讲解星星的消除算法的时候会详细介绍,这里的按钮事件是game.enterGameScene(),这是在game文件中实现的一个函数,用于进入游戏场景,在game文件中game被申明为一个全局的table变量,可以在其他的文件中使用。
&& 在游戏场景上面添加了一个层,该层用来实现星星矩阵的初始化显示,分数菜单的显示以及触摸事件。我们先看星星矩阵的初始化:
1 local STAR_RES_LIST = {"blue.png","green.png",
2 "orange.png","red.png","purple.png"}
4 function MatrixStar:initMatrix()
--[[self.STAR[i][j]是一个表,其中i表示星星矩阵的行,j表示列,它包含四个元素
self.STAR[i][j][1]表示星星精灵
self.STAR[i][j][2]表示该精灵的颜色
self.STAR[i][j][3]表示该精灵是否被选中
self.STAR[i][j][4]表示该精灵的x轴坐标
self.STAR[i][j][5]表示该精灵的y轴坐标
math.randomseed(os.time())
for row = 1, ROW do
local y = (row-1) * STAR_HEIGHT + STAR_HEIGHT/2
self.STAR[row] = {}
for col = 1, COL do
self.STAR[row][col] = {}
local x = (col-1) * STAR_WIDTH + STAR_WIDTH/2
local i=math.random(1,5)
local star = display.newSprite(STAR_RES_LIST[i])
self.STAR[row][col][1] = star
self.STAR[row][col][2] = i
self.STAR[row][col][3] = false
star:setPosition(x,y)
self.STAR[row][col][4] = x
self.STAR[row][col][5] = y
self:addChild(star)
这里利用随机函数,在for循环中生成了不同颜色的星星精灵表 STAR_RES_LIST记录了六种颜色的星星精灵,使用表self.STAR[i][j]记录了每一个星星的颜色、位置、是否被选中,这些信息用于后面对星星的消除算法,在C++中我们可以使用一个结构体来定义这些变量,而Lua中使用的是table. 分数的菜单使用了3个Label对象来实现的,分别记录了最高分数,目标分数以及当前分数,并且通过设置TAG来方便以后对该Label对象实现分数更新。
1 HSCORETAG = 100
2 LEVELTAG = 101
3 CSCORETAG = 102
5 function MatrixStar:setLabel(Hscore,Level,Goal,Cscore)
local HscoreUI = ui.newTTFLabel({
text = string.format("HighestScore: %s", tostring(Hscore)),
x, y = display.left, display.top,
HscoreUI:setScale(SCALE)
HscoreUI:setPosition(display.right, display.cy)
HscoreUI:setPosition(display.cx, display.top - SCALE * HscoreUI:getContentSize().height)
self:addChild(HscoreUI)
HscoreUI:setTag(HSCORETAG)
local LevelUI = ui.newTTFLabel({
text = string.format("Level: %s".." ".."Goal: %s", tostring(Level),tostring(Goal)),
x, y = display.left, display.top,
LevelUI:setScale(SCALE)
LevelUI:setPosition(display.cx, display.top - SCALE * (HscoreUI:getContentSize().height +
LevelUI:getContentSize().height))
self:addChild(LevelUI)
LevelUI:setTag(LEVELTAG)
local CscoreUI = ui.newTTFLabel({
text = string.format("CurrentScore: %s", tostring(Cscore)),
x, y = display.left, display.top,
CscoreUI:setScale(SCALE)
CscoreUI:setPosition(display.cx, display.top - SCALE * (HscoreUI:getContentSize().height +
LevelUI:getContentSize().height + CscoreUI:getContentSize().height))
self:addChild(CscoreUI)
CscoreUI:setTag(CSCORETAG)
接下来是实现触摸事件,在触摸事件中要将点中的星星和他周围与他颜色相同的星星消除,这里先用一个table记录选中的相同颜色星星个数,每次点击都要先将其设置为空。并且使用一个table来帮助选出周围与触摸星星颜色相同的星星,当触摸到一个星星后,将该星星插入到该表中,然后遍历它四周的星星是否与该星星相同,相同则插入表中。然后将表中的第一个元素从表中移除,接着对表中的元素进行上述操作,值到表为空为止。这个过程实际上就是利用队列来实现一个广度优先算法。具体代码如下:
local travel = {}
--当作一个队列使用,用于选出周围与触摸星星颜色相同的星星
if self.STAR[i][j][1] == nil then
table.insert(travel, {self.STAR[i][j][1], i, j})
while #travel ~= 0 do
if i + 1 &= ROW and self.STAR[i][j][3] ~= true and
self.STAR[i][j][2] == self.STAR[i + 1][j][2] then
table.insert(travel, {self.STAR[i+1][j][1],i+1,j})
if i-1 &= 1 and self.STAR[i][j][3] ~= true and
self.STAR[i][j][2] ==self.STAR[i-1][j][2] then
table.insert(travel, {self.STAR[i-1][j][1],i-1,j})
if j+1 &= COL and self.STAR[i][j][3] ~= true and
self.STAR[i][j][2] ==self.STAR[i][j+1][2] then
table.insert(travel, {self.STAR[i][j+1][1],i,j+1})
if j-1 &= 1 and self.STAR[i][j][3] ~= true and
self.STAR[i][j][2] ==self.STAR[i][j-1][2] then
table.insert(travel, {self.STAR[i][j-1][1],i,j-1})
if self.STAR[i][j][3] ~= true then
self.STAR[i][j][3] = true
table.insert(self.SELECT_STAR,{self.STAR[i][j][1],i,j})
table.remove(travel,1)
--table没有类似双向队列的功能直接删除第一个元素
if #travel ~= 0 then
i, j = travel[1][2], travel[1][3] --取出表的第一个元素
&在C++的deque容器可以在O(1)的时间复杂度中将队头元素移除,而这里的table.remove的时间复杂度为O(n),不知道是否有更好的
&方法实现。当我们得到选中的星星后便可以更新分数,将选中的星星删除同时更新剩余星星的位置。位置的更新主要涉及垂直方向与水平方向。先看垂直方向,当我们删除部分星星时,这些星星上面的星星自然要掉下来,我们用掉下来的星星信息覆盖已删除星星的信息,并且将掉下来的星星信息设为nil。再看水平方向,当有一列的星星全部删除时,我们要求该列右边的星星能自动向左移动,实现过程与垂直方向类似,源代码如下:
1 function MatrixStar:UpdateMatrix()
for i = 1, ROW do
for j = 1,COL do
if self.STAR[i][j][1] == nil then
local up = i
local dis = 0
while self.STAR[up][j][1] == nil do
dis = dis + 1
up = up + 1
if(up&ROW) then
for begin_i = i + dis, ROW do
if self.STAR[begin_i][j][1]~=nil then
self.STAR[begin_i-dis][j][1]=self.STAR[begin_i][j][1]
self.STAR[begin_i-dis][j][2]=self.STAR[begin_i][j][2]
self.STAR[begin_i-dis][j][3]=self.STAR[begin_i][j][3]
local x = (j-1)*STAR_WIDTH + STAR_WIDTH/2
local y = (begin_i-dis-1)*STAR_HEIGHT + STAR_HEIGHT/2
self.STAR[begin_i-dis][j][4] = x
self.STAR[begin_i-dis][j][5] = y
self.STAR[begin_i][j][1] = nil
self.STAR[begin_i][j][2] = nil
self.STAR[begin_i][j][3] = nil
self.STAR[begin_i][j][4] = nil
self.STAR[begin_i][j][5] = nil
for j = 1, COL do
if self.STAR[1][j][1] == nil then
local des = 0
local right = j
while self.STAR[1][right][1] == nil do
des = des + 1
right = right + 1
if right&COL then
for begin_i = ROW, 1,-1 do
for begin_j = j + des, COL do
if self.STAR[begin_i][begin_j][1] ~= nil then
self.STAR[begin_i][begin_j-des][1]=self.STAR[begin_i][begin_j][1]
self.STAR[begin_i][begin_j-des][2]=self.STAR[begin_i][begin_j][2]
self.STAR[begin_i][begin_j-des][3]=self.STAR[begin_i][begin_j][3]
local x = (begin_j-des-1)*STAR_WIDTH + STAR_WIDTH/2
local y = (begin_i-1)*STAR_HEIGHT + STAR_HEIGHT/2
self.STAR[begin_i][begin_j-des][4] = x
self.STAR[begin_i][begin_j-des][5] = y
self.STAR[begin_i][begin_j][1] = nil
self.STAR[begin_i][begin_j][2] = nil
self.STAR[begin_i][begin_j][3] = nil
self.STAR[begin_i][begin_j][4] = nil
self.STAR[begin_i][begin_j][5] = nil
星星的位置信息通过上述代码得到更新,我们通过设置Update事件,在每帧中更新星星的位置,为了有一个移动的效果,我们不是直接使用setPostion到目的位置,而是使用一个速度参数使其移动到目的位置。
1 function MatrixStar:updatePos(posX,posY,i,j)
if posY ~= self.STAR[i][j][5] then
self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5] - MOVESPEED)
if self.STAR[i][j][1]:getPositionY() & self.STAR[i][j][5]
self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5])
local x, y = self.STAR[i][j][1]:getPosition()
if posX ~= self.STAR[i][j][4] then
self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4] - MOVESPEED)
if self.STAR[i][j][1]:getPositionX() & self.STAR[i][j][4]
self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4])
整个游戏的基本代码就这些,代码写的比较乱,有待改进,但还是能跑起来,源代码地址:
&原文链接:
阅读排行榜Cocos2d-JS v3.1
Cocos Code IDE v1.0.0.Final
自带的跟随函数cc.follow,跟随的时候总是以目标为中心位置,而且在非移动范围边缘进行移动时,目标只要稍微进行移动,也会触发跟随动作。
本文没有在web上进行测试、改善
本文以X轴为例,目标移动时超出某个范围才进行跟随动作,如图:
本文只是经验分享,Y轴的跟随本文没有实现,而且响应的事件为键盘上的左右方向。另外,程序写的比较随意,显得略搓.......大家别在意....
另外这里的视窗指这个hellowWorldLayer,也就是这个helloWorld层,是一个层,不是opengl的视口,写的时候没注意让大家混乱了不好意思。
(其实也就是层的移动跟随,本文的视窗不是指opengl的视口,让层进行移动来达到看起来是视窗跟随的效果)
最终效果如下(暂时没有黑线):
上传的时候不知道为何变成JPG格式了= =那就传到相册空间好了,这里放一个链接吧...:
背景图片用的是Tiled制作的地图,本文最后会提供资源,瓦片地图的大小为:
制作该地图的过程就省略了,网上好多教程。
1.新建一个工程,本文的工程为横向,分辨率为960*640,不过显示的是main.js里800*450的默认分辨率。把app.js里用不上的删掉,剩下这些:
var HelloWorldLayer = cc.Layer.extend({
ctor:function () {
this._super();
var size = cc.winS
var HelloWorldScene = cc.Scene.extend({
onEnter:function () {
this._super();
var layer = new HelloWorldLayer();
this.addChild(layer);
2.把.tmx地图文件和对应的.png文件放到res文件夹下。接着修改tmx文件引用的图片路径为相对路径,改路径这里介绍两种方法。
方法一:把引用图片路径改为引用的图片名字(加上格式)。
然后在main.js里面添加res路径到文件搜索,添加后整个文件代码为:
cc.game.onStart = function(){
cc.view.adjustViewPort(true);
cc.view.setDesignResolutionSize(800, 450, cc.ResolutionPolicy.SHOW_ALL);
cc.view.resizeWithBrowserSize(true);
var searchPaths = jsb.fileUtils.getSearchPaths();
var paths = [
'res'
for (var i = 0; i & paths. i++) {
searchPaths.push(paths[i]);
jsb.fileUtils.setSearchPaths(searchPaths);
//load resources
cc.LoaderScene.preload(g_resources, function () {
cc.director.runScene(new HelloWorldScene());
cc.game.run();
方法二:直接在路径写上res/ &:
&image source=&res/tmw_desert_spacing.png&
3.加载地图,在app.js的HelloWorldLayer构造函数ctor里添加如下代码:
var tiled = new cc.TMXTiledMap(&res/test1111.tmx&);//直接加载路径下tmx文件
this.addChild(tiled);
4.添加目标,这里用helloworld图片,先在HelloWorldLayer里面添加一个变量:
hero:null,
然后在第三步后面继续添加:
this.hero = new cc.Sprite(&res/HelloWorld.png&);
this.hero.scale = 0.2;//因为原图片太大,于是缩小为原大小的20%
this.hero.setPosition(size.width * 0.5, size.height * 0.3);
this.addChild(this.hero, 1);
5.添加键盘事件和目标左右移动:
(关于更多的事件,请参考这个:,或者其他demo、资料。)
在HelloWorldLayer里添加以下变量,用作判断左移或者右移、目标缩放后的宽度:
isLeft:null,
isRight:null,
heroWidth:null,
再添一个目标移动速度:(好吧我表示直接初始化更加省事了)
heroSpeed:5,
在ctor里初始化:
this.isLeft =
this.isRight =
注意在创建hero后才赋值,经过测试,在缩放后获取的宽度为不缩放时大小,所以要乘以0.2:
this.heroWidth = this.hero._getWidth() * 0.2;
在第四步后添加事件监听和处理:
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,//事件为键盘按键
onKeyPressed:
function(keyCode, event){
var helloWorldLayer = event.getCurrentTarget();//获取当前操作的作用域,与最后一行的那个参数有关,this则为该HelloWorldLayer。
cc.log(&Key & + keyCode.toString() + & was pressed!&);//测试出按下的键的编号,额,,,没去找按键对应编号的表
if (keyCode == 23) {//左方向
cc.log(&left&);
helloWorldLayer.isLeft =
helloWorldLayer.isRight =
if (keyCode == 24) {//右方向
cc.log(&right&);
helloWorldLayer.isRight =
helloWorldLayer.isLeft =
onKeyReleased: function(keyCode, event){
//var label = event.getCurrentTarget();
var helloWorldLayer = event.getCurrentTarget();
if (keyCode == 23)
helloWorldLayer.isLeft =
if (keyCode == 24)
helloWorldLayer.isRight =
cc.log(&Key & + keyCode.toString() + & was released!&);
这里特别说明一下:为了在按下一个方向时,按下另一个方向,目标会立刻转向运动,所以在键盘按下时除了要将需要前进的方向值为true,另一个方向同时置为false,实现的方法有好多种,大家不要在意本文的写法......
接着开启update,在update里面更新目标的位置。在后面继续添加:
this.scheduleUpdate();然后再在HelloWorldLayer里重写update方法(注意在ctor的最后加逗号,):update : function(dt) {
var pos = this.hero.getPositionX();
if (this.isLeft && !this.isRight) {
if ((pos - this.heroWidth *0.5) & 0
) //超出左边移动边界就不让目标左移
this.hero.setPositionX(pos - this.heroSpeed);
if (this.isRight && !this.isLeft) {
if ( (this.mapLength ) & (pos + this.heroWidth)) //超出右边界就不让目标右移
this.hero.setPositionX(pos + this.heroSpeed);
如无意外目标可以左右移动了。
注意,按键事件和update在每一帧的处理顺序:先处理按键,再到update。
5.5这里说一下cc.Follow
用new创建的话,控制台会报这样的问题:jsb_create_apis.js:437:ReferenceError:
ret is not defined
改为.ctreate创建就好了
接着不想做自定义视窗跟随函数的同学,直接添加以下代码即可完事:
var followAction = cc.Follow.create(this.hero, cc.rect(0, 0, 3800, size.height));
this.runAction(followAction);
若有黑线问题第七步有讲
6.添加自定义的视窗跟随函数(也就是层的移动跟随,本文的视窗不是指opengl的视口,让层进行移动来达到看起来是视窗跟随的效果):
先交代一下cc.Follow,这个动作创建的时候最好用.create方法,用new的话
先在HelloWorldLayer里添加一个变量,用来表示视窗移动的状态,本人比较懒,用一个整形表示,0为不动,1为左移,2为右移,理论上用枚举类型会比较符合规范=
cameraStatue:null,
再加个变量保存地图的宽度
mapLength:null,
接着在ctor初始化为0:
this.cameraStatue = 0;
在创建tiled(地图)后保存他们的宽度
this.mapLength = tiled.getContentSize().
然后在HelloWorldLayer里添加自定义的视窗跟随函数:
setCamera : function(targetPositionX, offsetLeft, offsetRight, windowWidthHalf,tiledW) {
var cameraX = this.getPositionX();//获取视窗的X坐标
var isOut = Math.abs(targetPositionX - (-cameraX));//得出视窗与目标X轴上的距离
var ofx = windowWidthHalf - 105;//实际上减去的值为80+25,下面介绍如何得出
if (targetPositionX &
(ofx) && (targetPositionX & (tiledW - windowWidthHalf +25))) {//视窗移动范围判定
if (isOut & offsetLeft) {//视窗是否移动判定
this.cameraStatue = 1;
&= offsetLeft && isOut &= offsetRight) {//视窗是否移动判定
this.cameraStatue = 0;
if (isOut & offsetRight) {
this.cameraStatue = 2;
if (this.cameraStatue == 1) {
this.setPositionX(cameraX + this.cameraSpeed);
if (this.cameraStatue == 2) {
this.setPositionX(cameraX - this.cameraSpeed);
}接下来讲解一下这个函数(锚点默认):
参数targetPositionX为需要跟随目标的X坐标,
参数offsetLeft为左边移动边界,也就是目标和视窗X轴上的相对位置,
参数offsetRight为右边移动边界,也就是目标和视窗X轴上的相对位置,
参数windowWidthHalf为视窗宽度的一半,
参数tiledW为地图的宽度。
以下所有的分析都是以锚点为默认的情况下(Layer默认锚点是(0,0),里面的node默认(0.5,0.5)),而且main.js里显示的画布为:800*450,所以cc.winSize的宽度为800。(大家可以用cc.log打印cc.winSize.width看看)
相机起始X坐标:0,
目标起始X坐标400,(在屏幕宽度(800)一半(400),恩,应该是这样算的)
var isOut = Math.abs(targetPositionX - (-cameraX));这句的作用是取得跟随的目标和视窗X轴上的差值,这里视窗,也就是cameraX值取反,是因为视窗往右移,X轴的坐标是越来越小的,也就是和目标的方向相反,X轴的原点一致,大家可以自己输出视窗的X轴坐标观察结果。这里把最后的值取绝对值,在本文中其实加不加绝对值也没问题,因为目标都是在X大于0的时候进行移动,取绝对值是为了应对在目标移动到X轴负坐标的时候,但是本文没有这种情况= =...
var ofx = windowWidthHalf - 105;
这句等号右边完整的表达式是:windowWidthHalf - 80 -25,减去80是为了补偿图片一半的宽度,因为锚点为目标中点,所以要补回左边边缘到中点的长度。然后这里的25为人工调试测出的结果(猜测跟分辨率从960*640的3:2变到800*450的16:9有关),不然会出现视窗移动后再移回来,回不到视窗原点。
(上传后不知为何变成JPG格式= =那就传到相册空间,放个链接吧)
if (targetPositionX &
(ofx) && (targetPositionX & (tiledW -windowWidthHalf +25))) {
再次强调目标右移的X坐标为增量,而视窗右移为减量。大家可以自己输出看看结果
这句为视窗可以移动的范围,由于判断是根据目标的X轴,所以向右为正。视窗不能移到地图外面,所以左边界不是0,而是视窗宽度的一半,加上目标锚点和测试时出现的偏移影响,所以左边界为上一句表达式所示;右边界同理。
之后就是判断目标和视窗的相对距离有没有超出预设的左右值,由于视窗X轴向右为负,所以向左移动时加上移动速度,向右移动时减去移动速度。
最后在update里的最后调用这个函数:
this.setCamera(pos, 300, 500, cc.winSize.width * 0.5, this.mapLength);
7.去除移动时出现的黑线
上面的动态图最后会出现这样的黑线:
在本博客的另一篇文章讲解了如何修复黑线的问题:
8.源码和资源
cc.game.onStart = function(){
cc.view.adjustViewPort(true);
cc.view.setDesignResolutionSize(800, 450, cc.ResolutionPolicy.SHOW_ALL);
cc.view.resizeWithBrowserSize(true);
var searchPaths = jsb.fileUtils.getSearchPaths();
var paths = [
'res'
for (var i = 0; i & paths. i++) {
searchPaths.push(paths[i]);
jsb.fileUtils.setSearchPaths(searchPaths);
//load resources
cc.LoaderScene.preload(g_resources, function () {
cc.director.runScene(new HelloWorldScene());
cc.game.run();
var HelloWorldLayer = cc.Layer.extend({
isLeft:null,
isRight:null,
hero:null,
cameraStatue:null,
mapLength:null,
heroWidth:null,
heroSpeed:20,
cameraSpeed:20,
ctor:function () {
this._super();
var size = cc.winS
this.isLeft =
this.isRight =
this.cameraStatue = 0;
var tiled = new cc.TMXTiledMap(&res/test1111.tmx&);
this.addChild(tiled);
this.hero = new cc.Sprite(&res/HelloWorld.png&);
this.hero.scale = 0.2;
this.hero.setPosition(size.width * 0.5, size.height * 0.3);
this.addChild(this.hero, 1);
this.mapLength = tiled.getContentSize().
this.heroWidth = this.hero._getWidth() * 0.2;
cc.log(this.hero._getWidth()*0.2*0.5);
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyPressed:
function(keyCode, event){
var helloWorldLayer = event.getCurrentTarget();
var pos = helloWorldLayer.hero.getPositionX();
cc.log(&Key & + keyCode.toString() + & was pressed!&);
if (keyCode == 23) {
cc.log(&left&);
helloWorldLayer.isLeft =
helloWorldLayer.isRight =
if (keyCode == 24) {
cc.log(&right&);
helloWorldLayer.isRight =
helloWorldLayer.isLeft =
onKeyReleased: function(keyCode, event){
//var label = event.getCurrentTarget();
var helloWorldLayer = event.getCurrentTarget();
if (keyCode == 23)
helloWorldLayer.isLeft =
if (keyCode == 24)
helloWorldLayer.isRight =
cc.log(&Key & + keyCode.toString() + & was released!&);
this.scheduleUpdate();
update : function(dt) {
var pos = this.hero.getPositionX();
if (this.isLeft && !this.isRight) {
if ((pos - this.heroWidth *0.5) & 0
this.hero.setPositionX(pos - this.heroSpeed);
if (this.isRight && !this.isLeft) {
if ( (this.mapLength ) & (pos + this.heroWidth))
this.hero.setPositionX(pos + this.heroSpeed);
this.setCamera(pos, 300, 500, cc.winSize.width * 0.5, this.mapLength);
setCamera : function(targetPositionX, offsetLeft, offsetRight, windowWidthHalf,tiledW) {
var cameraX = this.getPositionX();
var isOut = Math.abs(targetPositionX - (-cameraX));
var ofx = windowWidthHalf - 105;
if (targetPositionX &
(ofx) && (targetPositionX & (tiledW -windowWidthHalf +25))) {
if (isOut & offsetLeft) {
this.cameraStatue = 1;
&= offsetLeft && isOut &= offsetRight) {
this.cameraStatue = 0;
if (isOut & offsetRight) {
this.cameraStatue = 2;
if (this.cameraStatue == 1) {
this.setPositionX(cameraX + this.cameraSpeed);
if (this.cameraStatue == 2) {
this.setPositionX(cameraX - this.cameraSpeed);
var HelloWorldScene = cc.Scene.extend({
onEnter:function () {
this._super();
var layer = new HelloWorldLayer();
this.addChild(layer);
用到的tmx和tmx对应的png文件:
本文已收录于以下专栏:
相关文章推荐
创建AssetManager, 设置资源包路径
替换所有AssetManager的引用
AssetManager newAssetManager = (AssetManager) AssetMana...
http://blog.csdn.net/u/article/details/
主题 Coco...
熟悉js的dom事件或者flash事件的,基本都能立马明白cc.eventManager的用法。
cc.eventManager有两种注册监听器的方式,一种是原生事件,例如
cc.even...
熟悉js的dom事件或者flash事件的,基本都能立马明白cc.eventManager的用法。
cc.eventManager有两种注册监听器的方式,一种是原生事件,例如
Cocos2d-JS v3.1
Cocos Code IDE v1.0.0.Final
本文介绍的方法比较随意,另官方也有规范的教程:http://www.co...
除了使用Cocos2d-JS的11种内置粒子系统外,我们还可以通过创建ParticleSystem对象,并设置属性实现自定义粒子系统,通过这种方式完全可以实现我们说需要的各种效果的粒子系统。使用Par...
基于cocos2d js封装一个按钮控件!
自定义事件是当其它事件不满足用户的时候可以自己定义。像传递值或者对象。
我们都知道创建一个监听器无非就是两个步骤:一是创建Listener,二是添加到eventManage上。但是EventCust...
holydancer原创,如需转载,请在显要位置注明:
转自holydancer的CSDN专栏,专栏地址:http://blog.csdn.net/holydancer
精灵是游戏的主角,...
在游戏开发中,为了获得更好的交互效果,经常使用对话框,cocos实现对话框也比较容易,说到底对话框也是一个Layer。我们在添加Layer之前首先对对话框进行一定的设置,之后在Layer的OnEnte...
他的最新文章
讲师:李江龙
讲师:司徒正美
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 消灭星星3电脑版 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信