Cocos2d-X 3.2 lua语言飞机大战开发实例(二)
1.敌机类的封装以及碰撞检测
--
Enemy的类中
require "Cocos2d"
local Enemy=class("Enemy",function ()
return cc.Node:create()
end)
function Enemy:create(t,x,y)
local enemy=Enemy.new()
enemy:addChild(enemy:init(t,y))
return enemy
end
--构造
function Enemy:ctor()
self.winsize=cc.Director:getInstance():getWinSize()
self.ex=0
self.ey=0
self.type=0
self.dirH=true --真为rigth 假为left
self.dirV=true --false up truedown
self.flyWidth=30 --摇摆的幅度
self.flyX=0 --当前的摇摆值
self.count=0 --控制移动的逻辑执行的次数
end
--init()
function Enemy:init(t,y)
local layer=cc.Layer:create()
local sp=cc.Sprite:create()
layer:addChild(sp)
--敌机动画
if t==0 then
--动画的每一帧
local sf1=cc.SpriteFrame:create("fonts/Resources/ld1.png",cc.rect(0,0,87,100))
local sf2=cc.SpriteFrame:create("fonts/Resources/ld1.png",cc.rect(87,100))
local allf={sf1,sf2}
--创建动画
local animation=cc.Animation:createWithSpriteFrames(allf,0.1)
local animate=cc.Animate:create(animation)
sp:runAction(cc.RepeatForever:create(animate))
elseif t==1 then
local sf1=cc.SpriteFrame:create("fonts/Resources/ld1.png",0.1)
local animate=cc.Animate:create(animation)
sp:runAction(cc.RepeatForever:create(animate))
elseif t==2 then
local sf1=cc.SpriteFrame:create("fonts/Resources/ld2.png",100))
local sf2=cc.SpriteFrame:create("fonts/Resources/ld2.png",0.1)
local animate=cc.Animate:create(animation)
sp:runAction(cc.RepeatForever:create(animate))
end
--设置坐标
sp:setPosition(x,y)
self.ex=x
self.ey=y
self.type=t
--计划任务,然敌机自动向下飞
local function logic(t)
self.count=self.count+1 -—控制它的帧率
if self.count<5 then
return
else
self.count=0
end
if self.type==0 then
--自动向下飞
self.ey=self.ey-10
if self.ey<0 then
self:removeFromParent()--移除
return
end
elseif self.type==1 then
--左右摇摆向下飞
self.ey=self.ey-2
if self.ey<0 then
self:removeFromParent()--移除
return
end
--摇摆
if self.dirH then --向右摇摆
self.ex=self.ex+self.flyX--敌机的横坐标+摇摆的值
else
self.ex=self.ex-self.flyX--敌机的横坐标—摇摆的值
end
self.flyX=self.flyX+3 --当前的摇摆值
if self.flyX>self.flyWidth then--如果当前的摇摆值大于摇摆的幅度
self.flyX=0 --摇摆值归0
self.dirH=not self.dirH --反向
end
elseif self.type==2 then
--飞到屏幕的中央向两侧飞行
if self.ey>=self.winsize.height/2 then
self.ey=self.ey-2--如果在屏幕中间的上方就让它不断乡下走
else
self.ex=self.ex+5--向右走
if self.ex>self.winsize.width then --如果大于屏幕的宽度
self:removeFromParent() --就移除
return
end
end
end
sp:setPosition(self.ex,self.ey) --敌机的坐标
end
sp:scheduleUpdateWithPriorityLua(logic,0) --让这个敌机执行它的计划任务
return layer
end
return Enemy
--这样我们就实现好了敌机类的封装,下面我们就从GameScene中再添加敌机
2.在GameScene的init()中
跟飞机产生子弹的原理一致,首先需要在构造函数中添加一个计数器
self.countEnemy=0 --敌机产生的计数器
--添加敌机
--添加敌机
local function newEnemy(t)
self.countEnemy=self.countEnemy+1
if self.countEnemy>=120 then
--产生敌机
local newEnemy=require("nodes.Enemy")
local num=math.random()*3--math是lua中的基本函数。math.random()它产生的是0~1的随机数,*3之后变成1~3的随机数
local etype=0 --敌机的类型
if num>2 and num<=3 then etype=2 end
if num>1 and num<=2 then etype=1 end
if num>0 and num<=1 then etype=0 end
local ne=newEnemy:create(etype,math.random()*self.winsize.width,self.winsize.height)
layer:addChild(ne)
self.countEnemy=0
end
end
--给敌机计划任务
local node2=cc.Node:create()
layer:addChild(node2)
node2:scheduleUpdateWithPriorityLua(newEnemy,0)
--
3.碰撞检测的实现,首先要确定的是思路,我们该怎么取到子弹和敌机呢?这样做。。。
产生子弹时,我们不但要将子弹添加到layer中,还要定义table,将子弹添加到table中
在GameData全局数据中定义:
g_allBullet={}—保存所有的子弹
g_allEnemy={}—保存所有的敌机
我们在子弹类的构造函数中,定义:
self.indexInAllBullet=0 --当前这个子弹在table集合中的编号
table.remove(g_allBullet,self.indexInAllBullet)
--调整编号
for i=1,#g_allBullet do
if g_allBullet[i].indexInAllBullet>self.indexInAllBulletthen
g_allBullet[i].indexInAllBullet=g_allBullet[i].indexInAllBullet-1
end
end
self.unscheduleUpdate()
在GameScene中子弹产生,添加到layer的同时也要添加这个子弹到全局数据里
newb.indexInAllBullet=#g_allBullet+1 --记录当前这颗子弹在这个集合中的下标是几
g_allBullet[#g_allBullet+1]=newb --#号能够返回这个table中有多少个数据!+1是下标从1开始
--print("目前子弹的个数"..tostring(#g_allBullet))—-每产生一个子弹都再g_allBullet中
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~
同理,我们也需要将敌机做这样的处理
self.indexInAllEnemy=0 --当前这个敌机在table集合中的编号
table.remove(g_allEnemy,self.indexInAllEnemy) --删除这个表中的这个元素
--后续编号--
for i=1,#g_allEnemydo
if g_allEnemy[i].indexOfAllEnemy>self.indexOfAllEnemy then
g_allEnemy[i].indexOfAllEnemy=g_allEnemy[i].indexOfAllEnemy-1
end
end
self:unscheduleUpdate()
在GameScene中敌机产生,添加到layer的同时也要添加这个敌机到全局table里
--把这个敌机添加到全局的table中
ne.indexOfAllEnemy=#g_allEnemy+1--记录当前这个敌机在这个集合中的下标是几 g_allEnemy[#g_allEnemy+1]=ne --#号能够返回这个table中有多少个数据!+1是下标从1开始
--print("目前敌机的数量"..tostring(#g_allEnemy))
--实际上我们的做到这里只是为了做碰撞检测的一个前提,我们已经把所有的敌机和子弹都转化成了table中的数据这样我们就可以实现访问敌机和子弹了—接下来我们就该做碰撞检测了
4.碰撞检测
--增加碰撞检测逻辑
local function gamelogic(t)
--碰撞检测
--i就是第i个元素,v就是第i个元素的值,v,还可以写成nowbullet,g_allBullet返回的是这个元素的编号
--for i,nowbullet in pairs(g_allBullet) do
-- for j,nowenemy inpairs(g_allEnemy) do
--
--
-- end
--end
for i=1,#g_allBullet do--i从1循环到g_allbullet的长度
local nowbullet=g_allBullet[i] --获取第i个子弹
for j=1,#g_allEnemy do
local nowe=g_allEnemy[j]
local rect1=cc.rect(nowbullet.bx,nowbullet.by,7,10)
local rect2=cc.rect(nowe.ex,nowe.ey,50)
--print(nowe.ex..","..nowe.ey..","..nowbullet.bx..","..nowbullet.by)
if cc.rectIntersectsRect(rect1,rect2) then
--子弹消失
table.remove(g_allBullet,nowbullet.indexInAllBullet)--从全局表里删除自己--table表中的第i个元素消失
--后续编号--
for i=1,#g_allBulletdo
if g_allBullet[i].indexInAllBullet>nowbullet.indexInAllBulletthen
g_allBullet[i].indexInAllBullet=g_allBullet[i].indexInAllBullet-1
end
end
nowbullet:unscheduleUpdate()
nowbullet:removeFromParent() --将本节点删除
--敌机消失
table.remove(g_allEnemy,nowe.indexOfAllEnemy)
--后续编号--
for i=1,#g_allEnemydo
if g_allEnemy[i].indexOfAllEnemy>nowe.indexOfAllEnemy then
g_allEnemy[i].indexOfAllEnemy=g_allEnemy[i].indexOfAllEnemy-1
end
end
nowe:unscheduleUpdate()
nowe:removeFromParent() --将本节点删除
break
end
end
end
end
local node3=cc.Node:create()
layer:addChild(node3)
node3:scheduleUpdateWithPriorityLua(gamelogic,0)
5.在子弹的类这敌机的类中我们也要对后续的table表中的编号进行重整
子弹类的init()的移除子弹处,中我们这样做:
--后续编号--
for i=1,#g_allBullet do
--要移除的是第i(self.indexInAllBullet)个子弹, 假如我们移除了第2个子弹,我们就让第3个子弹的编号变成2
if g_allBullet[i].indexInAllBullet>self.indexInAllBulletthen
g_allBullet[i].indexInAllBullet=g_allBullet[i].indexInAllBullet-1
end
end
self:unscheduleUpdate()
6.在敌机的类中我们都需要对移除敌机时进行后续编号的一个处理
在敌机类的init()移除敌机中时:
--后续编号--
for i=1,#g_allEnemydo
if g_allEnemy[i].indexOfAllEnemy>self.indexOfAllEnemy then
g_allEnemy[i].indexOfAllEnemy=g_allEnemy[i].indexOfAllEnemy-1
end
end
self:unscheduleUpdate()