1
今天进行代码的编写。
ps:因为本人也是初学者,所以步骤会有些繁杂希望大家不要在意,旨在能够学习CocosCreaor!
------------------------------------------------------------我是一只分割线------------------------------------------------------------
1.先进行地板轮播移动
创建一个名为GameData的脚本类(本人习惯把一些常用数值写在一个全局类中,方便以后在其他脚本进行调用)
脚本中编写
//这个类类似单例
cc.GAMEDATA= cc.GAMEDATA || {};
//地板移动时间间隔
cc.GAMEDATA.GROUND_MOVE_INTERVAL = 0.05;
//地板单位时间内移动的偏移量
cc.GAMEDATA.GROUND_MOVE_SPEED = 5;
创建Main脚本,这个也会是我们之后的主脚本。
编写Main脚本
(1)
properties: {
ground0:cc.Node,
ground1:cc.Node,
},
这里偷个懒没有用正规的声名格式qaq 声名两个地板。
(2)
//地板移动
onGroundMove:function(){
this.ground0.x -= cc.GAMEDATA.GROUND_MOVE_SPEED; //让地板朝着x轴-=5的偏移量
this.ground1.x -= cc.GAMEDATA.GROUND_MOVE_SPEED;//让地板朝着x轴-=5的偏移量
//通过判断ground0和ground1的x轴和宽的一半与背景节点一半比较来赋值位置
if(this.ground0.x+this.ground0.width/2 < -this.node.width/2){
this.ground0.x = this.ground1.x+this.ground0.width
}
if(this.ground1.x+this.ground1.width/2 < -this.node.width/2){
this.ground1.x = this.ground0.x+this.ground0.width
}
},
在onLoad里使用计时器进行调用
onLoad () {
//启动地板移动的计时器 每0.05秒执行一次this.onGroundMove方法
this.schedule(this.onGroundMove,cc.GAMEDATA.GROUND_MOVE_INTERVAL)
},
ps:这里用到了计时器,大家可以点击链接查看官方解释:官方计时器
效果图:
2.制作小鸟的运动动画
(1)设置全局数值
//小鸟下落时间间隔
cc.GAMEDATA.BRID_DROP_INTERVAL =0.02;
//小鸟加速度
cc.GAMEDATA.BRID_DROP_ACC =0.5;
//小鸟的弹跳值
cc.GAMEDATA.BRID_JUMP_VALUE =-6.6;
(2)创建Bird脚本编写如下:
cc.Class({
extends: cc.Component,
properties: {
},
// onLoad () {},
start () {
this.speed =0;
},
startDrop(){
//开启计时器 每0.02秒运行一次onDrop方法
this.schedule(this.onDrop,cc.GAMEDATA.BRID_DROP_INTERVAL);
},
onDrop(){
//赋值速度给node.y
this.speed +=cc.GAMEDATA.BRID_DROP_ACC;
this.node.y -=this.speed;
},
onJump(){
//小鸟的移动力度
this.speed =cc.GAMEDATA.BRID_JUMP_VALUE;
},
stop(){
//关闭计时器
this.unschedule(this.onDrop);
this.getComponent(cc.Animation).stop("fly");//动画帧停止
}
// update (dt) {},
});
并添加在Bird节点身上
在Main脚本中编写如下:
properties: {
ground0:cc.Node,
ground1:cc.Node,
//声明小鸟对象
bird:cc.Node,
//声名当前分数
scoreLabel : cc.Label,
//声明最高分
highScoreLabel:cc.Label,
//声名开始按钮
beginBut :cc.Button,
//声明返回按钮
quitBut:cc.Button,
//声名Logo
logo:cc.Node,
//音效
jumpAudio:cc.AudioSource
},
在onLoad中编写:
onLoad () {
this.score =0;//辅助计分
this.quitBut.node.active =false;
this.scoreLabel.node.active =false;
//启动地板移动的计时器 每0.05秒执行一次this.onGroundMove方法
this.schedule(this.onGroundMove,cc.GAMEDATA.GROUND_MOVE_INTERVAL)
},
添加onButtonClick开始游戏方法并进行绑定:
//开始游戏
onButtonClick(event,customData)
{
this.logo.active =false;//logo隐藏
this.highScoreLabel.node.active =false;//最高分隐藏
this.beginBut.node.active =false;//开始按钮隐藏
this.scoreLabel.node.active =true;//当前分数显示
this.scoreLabel.string =this.score;//辅助得分赋值给当前分数
//给背景添加触摸事件 点击屏幕小鸟飞
this.node.on("touchstart",function(){
this.bird.getComponent("Bird").onJump();//调用bird身上脚本中的跳跃方法
this.jumpAudio.play();//播放音效
}.bind(this));
//小鸟下掉
this.bird.getComponent("Bird").startDrop(); //this.bird.startDorp();
},
效果图:
(3)管道生成及小鸟得分
创建管道预制件:
在GameData中添加如下:
//管道缝隙的最小值
cc.GAMEDATA.PIPE_MIN_GAP =100;
//管道缝隙的最大值
cc.GAMEDATA.PIPE_MAX_GAP =200;
//管道组合的最低位置
cc.GAMEDATA.PIPE_MIN_OFFSETY =-140;
//管道组合的最高位置
cc.GAMEDATA.PIPE_MAX_OFFSETY =80;
//管道生成的时间间隔
cc.GAMEDATA.PIPE_CREATE_INTERVAL = 1.5;
//返回指定范围内的随机数 m - n
cc.GAMEDATA.getRandombyRange = function(min,max)
{
return parseInt(Math.random() * (max - min +1) + min);
};
ps:关于随机数Math.random() * (max - min +1) 请移步我的另一篇文章
parseInt是将将字符串转换为整数。
在Main脚本中写管道生成方法:
先声明预制件:
//声明管道预制件
pipePrefab:cc.Prefab,
拖动预制件到声明处:
创建生成方法:
//管道生成
createrPipe()
{
//实例化一个预制件
let pipe = cc.instantiate(this.pipePrefab);
this.node.addChild(pipe);
pipe.getComponent("Pipe").init(this);//把this传递过去
this.ground1.zIndex = pipe.zIndex+1;
this.ground2.zIndex = pipe.zIndex+1 ;
this.goback.node.zIndex = pipe.zIndex+1;
},
在开始按钮事件中调用生成方法:
//开始游戏
onButtonClick(event,customData)
{
this.logo.active =false;//logo隐藏
this.highScoreLabel.node.active =false;//最高分隐藏
this.beginBut.node.active =false;//开始按钮隐藏
this.scoreLabel.node.active =true;//当前分数显示
this.scoreLabel.string =this.score;//辅助得分赋值给当前分数
//给背景添加触摸事件 点击屏幕小鸟飞
this.node.on("touchstart",function(){
this.bird.getComponent("Bird").onJump();//调用bird身上脚本中的跳跃方法
this.jumpAudio.play();//播放音效
}.bind(this));
//小鸟下掉
this.bird.getComponent("Bird").startDrop(); //this.bird.startDorp();
//启动管道生成计时器
this.schedule(this.createrPipe,cc.GAMEDATA.PIPE_CREATE_INTERVAL);
},
创建Pipe脚本并绑定在预制件上:
编写Pipe脚本:
properties: {
g1:cc.Node,//两根管道
g2:cc.Node,
},
在start中设置移动、间隙、位置
start () {
//获取小鸟节点
this.bird =cc.find("Canvas/Background/bird");
//生成间隙
this.g1.y =cc.GAMEDATA.getRandombyRange(cc.GAMEDATA.PIPE_MIN_GAP,cc.GAMEDATA.PIPE_MAX_GAP);
//生成位置
this.node.y=cc.GAMEDATA.getRandombyRange(cc.GAMEDATA.PIPE_MIN_OFFSETY,cc.GAMEDATA.PIPE_MAX_OFFSETY);
//管道移动
this.schedule(this.onPipeMove,cc.GAMEDATA.GROUND_MOVE_INTERVAL);
//防止分数一直加而设置标签
this.ispass =false;
},
用于传参
init(par)
{
this.par = par;
},
创建管道移动方法
//管道移动
onPipeMove()
{
if(this.par.isGameOver)
{
this.unschedule(this.onPipeMove);
}
this.node.x -= cc.GAMEDATA.GROUND_MOVE_SPEED;
},
在GameData里使用缓存来保存最高分数
//设置最高分数
cc.GAMEDATA.setHighScore= function(score){
cc.sys.localStorage.setItem("flabby_bird23",score);//把分数保存在本地文件
}
//从本地文件夹获取最高记录
cc.GAMEDATA.getHighScore= function(){
let highScore = cc.sys.localStorage.getItem("flabby_bird23") || 0;
return Number(highScore);
}
用户存储可以分为缓存和json,本文用的是缓存数据。存储官方已有很明确的案例
在Main脚本中编写得分和游戏结束
//游戏结束
gameOver(){
this.isGameOver = true;
this.bird.getComponent("Bird").stop();
this.unschedule(this.onGroundMove);//关闭地板移动计时器
this.unschedule(this.createrPipe);//关闭管道生成计时器
//把按钮活动属性设为真
this.goback.node.active=true;
if(this.score>this.highScore)//如果当前分数大于最高分数
{
cc.GAMEDATA.setHighScore(this.score);//保存分数为最高分
}
},
//得分
addscore()
{
this.score +=1;
this.scoreLab.string =this.score;
},
在update中对底板和小鸟的检测
update (dt) {
if(this.isGameOver)return;
if(this.bird.y - this.bird.height/2 <= this.ground1.y+this.ground1.height/2)
{
this.bird.y =this.ground1.y+this.ground1.height/2 +this.bird.height/2;
this.gameOver();
}
},
返回界面按钮
//返回界面
gojiemian()
{
cc.director.loadScene("game");//返回加载场景
},
最后最后最后是在Pipe脚本中的Update中对管道和小鸟的碰撞检测;
update (dt) {
if(this.par.isGameOver) return;
let pipeUpBox = this.g1.getBoundingBoxToWorld();
let pipeDownBox = this.g2.getBoundingBoxToWorld();
let birdBox = this.bird.getBoundingBoxToWorld();
if(pipeUpBox.intersects(birdBox)|| pipeDownBox.intersects(birdBox))
{
this.par.gameOver();
}
if(pipeUpBox.x+pipeDownBox.width< birdBox.x &&!this.ispass)
{
this.par.addscore();
this.ispass =true;
}
},
ps:flyBird物体之间的碰撞我用的是包围盒进行检测的。具体包围盒用法请参考官方api:https://docs.cocos.com/creator/api/zh/classes/Node.html#getboundingboxtoworld
intersects 是用来判断当前矩形与指定矩形是否相交。api用法
如果有对代码更好的建议请告知谢谢!共同学习!