(五)Lua小游戏别撞车——碰撞检测

发表于2015-06-27
评论0 2k浏览

当红色小车来不及躲避的时候发生碰撞游戏结束,那么如何判断俩辆小车碰撞了呢,我们可以通过俩辆小车的位置来确定,比如当他们的x和y坐标相同的时候就是发生了碰撞,再精确一点就是y坐标相同,x坐标的距离是俩辆小车的宽度之和的一半。甚么时候代表俩辆小车同向运动错开行驶了呢,y坐标有一个差值,x坐标和上边的一样。实际在运用的时候发现在lua中比较数字是否相同是不太好的,因为lua中只有浮点类型,转化为整形可以使用floor或者ceil函数,不过我采用的方法是先判断是否在同一个轨道,在前几篇的博客中当小车变轨的时候我设置了小车的switch变量,通过这个变量的真假来判断小车是在内圈还是外圈。这样y方向的判断我们就用这个变量,而x方向的判断我用的就是数字,判断俩车的距离。

在运用黄色小车的switch变量的时候,发现bug,所以我们先来修正这个bug,让黄色小车的switch跟随他的内外圈运动而变,修正后的代码如下,是在上一篇博客的基础上改的。

1function MainGameScene:runYelloCar(car)
2 
3    --返回执行里圈轨道或者外圈轨道的动作
4    local function getAction()
5        --初始化运动过程中需要的成员变量 代表外圈的轨道
6        local y1 = self.track_size.height*0.445
7        local y2 = -y1
8        local point1 = cc.p(self.track_size.width*0.245,self.car_bottomy)
9        local point2 = cc.p(self.track_size.width*0.745,self.car_topy)
10 
11        --判断执行里圈的轨道还是外圈的轨道
12        local switch = self.yello_switch
13        --代表里圈的轨道
14        if switch then
15            y1 = self.track_size.height*0.335
16            y2 = -y1
17            point1 = cc.p(self.track_size.width*0.245,self.track_size.height*0.171)
18            point2 = cc.p(self.track_size.width*0.745,self.track_size.height*0.844)
19        end
20 
21        --[[根据速率计算小车需要运动的时间--]]
22        local rate = GlobalData.rate
23        --圆周运动的时间
24        local tm = math.pi*y1/rate
25        --直线运动的时间
26        local tm2 = (self.track_size.width*0.5)/rate
27 
28        --创建动作
29        local circle1 = tt.CircleBy:create(tm,{x=0,y=y1},180)
30        local spawn1 = cc.Spawn:create(circle1:reverse(),cc.RotateBy:create(tm,-180))
31        local move2 = cc.MoveTo:create(tm2,{x=point1.x,y=point2.y})
32        local circle2 = tt.CircleBy:create(tm,{x=0,y=y2},180)
33        local spawn2 = cc.Spawn:create(circle2:reverse(),cc.RotateBy:create(tm,-180))
34        local move1 = cc.MoveTo:create(tm2,{x=point2.x,y=point1.y})
35 
36        return tm,tm2,spawn1,move2,spawn2,move1
37    end
38 
39    local tm,tm2,spawn1,move2,spawn2,move1 = getAction()
40 
41    --先将是否变轨的变量保存一下
42    local switch= self.yello_switch
43 
44    --获得一个随机数
45    math.randomseed(os.time())
46    local r = math.random(0,100)
47    --只有当小车在外部的轨道,并且满足概率的时候才会进入内部的轨道
48    if r > 50 and (self.yello_switch == falsethen
49        --变轨固定在这个点 进入内部的轨道
50        local circle1 = cc.Spawn:create(tt.CircleBy:create(tm/2,{x=-30,y=self.track_size.height*0.4},-90),cc.RotateBy:create(tm/2,-90))
51        local circle2 = cc.Spawn:create(tt.CircleBy:create(tm/2,{x=-162,y=self.track_size.height*0.0015},-90),cc.RotateBy:create(tm/2,-90))
52        --修正bug,增加一个动作,当小车运行完四分之一的轨迹以后就设置代表内外圈轨道的变量switch
53        spawn1 = cc.Sequence:create(
54        circle1,cc.CallFunc:create(function()self.yello_switch = true end),
55        circle2
56        )
57        --代表里圈轨道
58        self.yello_switch = true
59        tm,tm2,_,move2,spawn2,_ = getAction()
60    end
61 
62    r = math.random(0,100)
63    if r > 50 and (self.yello_switch == truethen
64        --变轨固定在这个点 转到外部的轨道
65        local circle1 = cc.Spawn:create(tt.CircleBy:create(tm/2,{x=-25,y=-self.track_size.height*0.4},-90),cc.RotateBy:create(tm/2,-90))
66        local circle2 = cc.Spawn:create(tt.CircleBy:create(tm/2,{x=225,y=self.track_size.height*0.02},-90),cc.RotateBy:create(tm/2,-90))
67        spawn2 = cc.Sequence:create(
68        circle1,cc.CallFunc:create(function()self.yello_switch = false end),
69        circle2
70        )
71        --代表外圈轨道
72        self.yello_switch = false
73    end
74 
75    --执行完毕一圈以后重新执行动作,这样轨道就是随机的
76    local callfunc = cc.CallFunc:create(function()
77        self:runYelloCar(self.car_yello)
78    end)
79 
80    --动作序列
81    local action_yello = cc.Sequence:create(move1,spawn1,move2,spawn2,callfunc)
82    action_yello:setTag(2)
83 
84    --使用玩switch来获得运动的轨迹以后,将原始switch还给小车
85    self.yello_switch = switch
86    car:runAction(action_yello)
87end

接下来就完成碰撞检测的逻辑,代码注释写的很清楚了,大家看注释吧!

1--碰撞检测
2function MainGameScene:collision(layer)
3    --是否播放yes的声音
4    local isYes = false
5 
6    local collistion_update = function()
7        --获得俩辆小车的位置,宽度
8        local red_x,red_y = self.car_red:getPosition()
9        local yello_x,yello_y = self.car_yello:getPosition()
10        local red_width = self.car_red:getContentSize().width
11        local yello_width = self.car_yello:getContentSize().width
12        --碰撞检测的条件
13        if self.red_switch == self.yello_switch and math.abs(red_x-yello_x)<(red_width+yello_width)/2 then
14            --停止小车运动,停止游戏
15            self.car_red:stopAllActions()
16            self.car_yello:stopAllActions()
17            self.play = false
18            --播放声音
19            SoundDeal:playEffect(EffectType.Crash)
20            cc.Director:getInstance():getScheduler():unschedulenoxssEntry(self.schedule_update)
21            self:gameOver(layer)
22        --没有发生碰撞检测俩车错过去,记录一下
23        elseif self.red_switch ~= self.yello_switch and math.abs(red_x-yello_x)<(red_width+yello_width)/2 then
24            --满足播放yes的条件
25            isYes = true
26        --在俩车相错的这段时间如果任然没有发生碰撞检测则真的是错过去了
27        elseif math.abs(red_x-yello_x)>(red_width+yello_width)/2 and isYes then
28            isYes = false
29            --设置全局的分数数据
30            GlobalData:setScore()
31            --改变UI
32            self.score:setString(GlobalData.score)
33            self.score:setScale(0.1)
34            self.score:runAction(cc.EaseElasticOut:create(cc.ScaleTo:create(0.2,1)))
35        end
36    end
37    --每帧都进行碰撞检测
38    self.schedule_update = cc.Director:getInstance():getScheduler():schedulenoxssFunc(collistion_update,0,false)
39end

接下来就是调用了,在调用之前完成一个开始按钮,当用户点击了开始按钮的时候小车运动,在这个过程中不断的进行碰撞检测。

1function MainGameScene:setButton(imageName,layer)
2    local play = cc.MenuItemImage:create(imageName,"","")
3    play:setPosition(self.size.width/2,self.size.height/2)
4    play:setScale(0.8)
5    local menu = cc.Menu:create(play)
6    menu:setPosition(cc.p(0,0))
7    layer:addChild(menu,3)
8 
9    --callback
10    local play_callback = function()
11        --播放音效
12        SoundDeal:playEffect(EffectType.Start)
13        play:runAction(cc.Sequence:create(cc.ScaleTo:create(0.05,1.3),cc.RemoveSelf:create()))
14        self:runRedCar(self.car_red)
15        self:runYelloCar(self.car_yello)
16        self.play = true
17        self:collision(layer)
18    end
19    play:registernoxssTapHandler(play_callback)
20    --判断游戏是否开始的变量
21    self.play = false
22end

代码中涉及到的对声音和数据的处理先不用管,下篇博客再添加。上边的代码有一个新的变量是play,这个变量是用来控制游戏是否在进行的,如果游戏没有开始,用户的触摸事件也是无效的,所以我们需要在触摸处理的回调函数中对这个变量进行判断,什么位置添加我想大家都应该很清楚吧。

游戏结束以后的处理正如代码中看到的那样,调用了一个gameOver函数,下面是这个函数的实现,涉及到数据和声音的部分不用管。

1function MainGameScene:gameOver(layer)
2    self:setButton("retry.png",layer)
3    --清除数据
4    GlobalData:reset()
5    self.score:setString("0")
6    --重新设置小车的位置
7    self:resetCar()
8end

Lua小游戏别撞车——碰撞检测

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引