游戏预览
开始场景
搭建开始场景
摆放一个背景图,在背景图上添加背景地面、开始按钮、4个角色选择按钮、游戏logo。
创建游戏脚本
1. 实现开始按钮的回调,点击开始按钮,跳转到游戏场景。跳转场景方法如下:
cc.director.preloadScene('playScene', function () {
cc.director.loadScene('playScene');
});
2. 实现选择角色按钮的回调,点击某个角色时,先将其他角色设置为未选中状态,再将当前选择的角色设为选中状态,最后用cc.sys.localStorage.setItem(“key”,value);方法本地保存选择的角色类型。
3. 在onLoad()方法中,调用cc.sys.localStorage.getItem(“key”);方法获取到本地保存的角色类型,并设置角色按钮的选中状态。
4. 游戏中音效必不可少,点击各个按钮时,都需要播放音效,方法如下:
//播放音效
playSound : function(name, isLoop){
cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
if(err){
return;
}
let audioID = cc.audioEngine.playEffect(clip, isLoop);
});
},
开始场景和脚本关联
1. 将脚本拖到start场景的属性检查器中,并将脚本中声明的属性和组件关联起来,如下图:
2. 给开始按钮绑定回调事件,选中开始按钮,在属性检查器中,找到Button属性,将ClickEvents值改成1,表示有一个点击事件,再按照如下方式将函数和组件关联起来:
3. 给角色按钮绑定回调,方法和给开始按钮绑定回调完全一样,只是绑定的函数不同。
游戏场景
游戏玩法是控制我方英雄的发炮角度,如果打中敌方英雄就得分,否则会被敌方英雄的炮弹打中,如果我方英雄血量为0则游戏结束。
搭建游戏场景
1. 游戏主界面:包含背景,地面,我方英雄,分数文本,返回主界面按钮。
2. 结算界面:包含遮罩层,最高得分文本,当前得分文本,重新开始按钮,返回主界面按钮。
创建游戏脚本
gamePlay.js脚本是游戏的核心,主要方法如下:
1. 开启物理系统:
cc.director.getPhysicsManager().enabled = true;
2. 设置重力加速度:
cc.director.getPhysicsManager().gravity = cc.v2(0, -640);
3. 添加触摸监听,事件分为TOUCH_START(开始)、TOUCH_MOVE(移动)、TOUCHCANCEL(取消)、TOUCH_END(结束)四个状态,方法如下:
this.node.on(cc.Node.EventType.TOUCH_START, this.onEventStart, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onEventMove, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onEventCancel, this);
this.node.on(cc.Node.EventType.TOUCH_END, this.onEventEnd, this);
4. 当开始触摸屏幕时,触发开始的回调onEventStart(),回调中开启定时器,每隔0.03秒角度加1,并改变炮台的角度,方法如下:
//更新炮管角度
updateGunAngle : function(){
this.shootLineImg.active = true;
this._curAngle = 0;
this.gunSchedule = function(){
if (this._curAngle < 90){
this._curAngle += 1;
this.myGunImg.angle = this._curAngle;
}
};
this.schedule(this.gunSchedule, 0.03);
},
5. 当结束触摸时,触发结束的回调onEventEnd(),回调中关闭定时器,方法如下:
//停止更新炮管
stopGunAngle(){
this.unschedule(this.gunSchedule);
this.shootLineImg.active = false;
},
6. 敌人开炮,需要先调整角度再发炮,炮的角度通过敌方子弹和我方英雄的坐标可计算出来,方法如下:
//敌方开炮
enemyOpenFire : function(){
//敌方子弹世界坐标
let enemyBulletPos = this._enemyNode.enemyBulletWorldPos();
//我方英雄世界坐标
let myHeroPos = this.myHeroImg.parent.convertToWorldSpaceAR(cc.v2(this.myHeroImg.position.x, this.myHeroImg.position.y + 30));
//计算夹角
let lenX = Math.abs(enemyBulletPos.x - myHeroPos .x);
let lenY = Math.abs(enemyBulletPos.y - myHeroPos .y);
let angle = Math.atan2(lenY, lenX) * 180 / Math.PI;
//设置敌方小火炮的角度
this._enemyNode.setGunAngle(angle);
//计算炮运行的距离
let len = Math.sqrt(Math.pow(lenX, 2) + Math.pow(lenY, 2));
this._enemyNode.gunAni(len);
this.playSound("sound/enemyBullet", false);
},
7. 更换纹理方法:
//更换纹理
setImgTexture : function(str, node){
cc.loader.loadRes(str, cc.SpriteFrame, function (err, spriteFrame) {
if (err) {
cc.error(err.message || err);
return;
}
node.getComponent(cc.Sprite).spriteFrame = spriteFrame;
}.bind(this));
},
创建敌人脚本
敌人脚本包含敌人,柱子,敌方炮弹等信息,脚本中的主要方法有:
1. 随机设置柱子的高度:
//调整敌方柱子高度
setColumnHight : function(){
//随机获取高度
let y = Math.floor(Math.random() * -250) - 100;
this.cloumn.position = cc.v2(this._winSize.width / 2 + 100, y);
},
2. 敌人进出场的动作:
//敌人进场动作
comeOnAni : function(){
this.setColumnHight();
let w = Math.floor(Math.random() * (this._winSize.width / 4));
this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(w, this.cloumn.position.y)), cc.callFunc(() =>{
this.enemyHeroImg.active = true;
this.enemyGunImg.active = true;
this.enemyAni();
}, this)));
},
//敌方柱子运动
enemyMove : function(){
this.enemyHeroImg.active = false;
this.enemyGunImg.active = false;
this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(-this._winSize.width / 2 - 100, this.cloumn.position.y)), cc.callFunc(() =>{
if(this.callBack){
this.callBack();
}
})));
},
3. 敌人开炮:
//炮运动
gunAni : function(len){
let bulletPos = this.enemyBulletImg.position;
this.enemyBulletImg.runAction(cc.sequence(cc.moveTo(0.3, cc.v2(len, 0)), cc.callFunc(() =>{
if(this.hitHeroCallBack){
this.hitHeroCallBack();
}
this.enemyBulletImg.position = bulletPos;
})));
},
创建碰撞脚本
碰撞脚本是给需要做碰撞检测的刚体用的,在碰撞脚本中做碰撞监听,当触发监听后,再调用相应的回调。比如我方子弹需要监听与墙壁,敌人,柱子等物体的碰撞,那么我们先给子弹绑定好碰撞组件,如下图:
再在代码中实现碰撞的回调并保存下来,方法如下:
//碰撞监听
contactFunction (selfCollider, otherCollider){
if(this.callBack){
this.callBack(selfCollider, otherCollider);
}
},
contactCallBack (callBack){
this.callBack = callBack;
},
最后在碰撞开始的监听中调用回调,方法如下:
onBeginContact ( contact, selfCollider, otherCollider){
if(selfCollider.tag == 0 && otherCollider.tag == 0){
cc.log("onBeginContact..."); //碰撞开始
this.contactFunction(selfCollider, otherCollider);
}
},
创建动画脚本
游戏中有英雄角色的等待和走路动作,敌人等待动作,如果在编辑器做动画,编辑的个数比较多,所以我的做法是通过修改纹理达到动画效果,用法是将这个脚本绑定到需要播放动画的节点上,并设置一张大图,方法如下:
使用方法:
playAni(nameStr, count, dt, isLoop){
this.stopAni();
this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + 0);
let array = [];
for(let i = 0; i < count; i++){
array.push(cc.delayTime(dt));
array.push(cc.callFunc(() =>{
this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + i);
}));
}
if(isLoop){
this.node.runAction(cc.repeatForever(cc.sequence(array)));
}
else{
this.node.runAction(cc.sequence(array));
}
},
参数分别是图片名称,图片张数,间隔时间,是否循环,调用方法:
this.shieldImg.getComponent("spriteFrameAni").playAni("shield", 4, 0.1, true);
//-------------contact.js------------------
//碰撞监听脚本
cc.Class({
extends: cc.Component,
properties: {
},
onLoad () {
},
onDestroy () {
},
onBeginContact ( contact, selfCollider, otherCollider){
if(selfCollider.tag == 0 && otherCollider.tag == 0){
cc.log("onBeginContact..."); //碰撞开始
this.contactFunction(selfCollider, otherCollider);
}
},
onEndContact (contact, selfCollider, otherCollider){
//cc.log("onEndContact...");//碰撞结束
},
onPreSolve(contact, selfCollider, otherCollider){
//cc.log("onPreSolve...");//碰撞持续,接触时被调用
},
onPostSolve (contact, selfCollider, otherCollider){
//cc.log("onPostSolve...");//碰撞接触更新完后调用,可以获得冲量信息
},
//碰撞监听
contactFunction (selfCollider, otherCollider){
if(this.callBack){
this.callBack(selfCollider, otherCollider);
}
},
contactCallBack (callBack){
this.callBack = callBack;
},
});
//-------------enemy.js------------------
cc.Class({
extends: cc.Component,
properties: {
cloumnNode : cc.Node,
cloumn : cc.Node,
enemyGunImg : cc.Node,
enemyBulletImg : cc.Node,
enemyHeroImg : cc.Node,
enemyDieParticle : cc.ParticleSystem,
},
onLoad: function () {
this._winSize = cc.winSize;
this.enemyHeroImg.active = false;
this.enemyGunImg.active = false;
},
//敌人运动
enemyAni : function(){
this.enemyHeroImg.getComponent("spriteFrameAni").playAni("enemy", 3, 0.1, true);
},
//调整敌方柱子高度
setColumnHight : function(){
//随机获取高度
let y = Math.floor(Math.random() * -250) - 100;
this.cloumn.position = cc.v2(this._winSize.width / 2 + 100, y);
},
//敌人进场动作
comeOnAni : function(){
this.setColumnHight();
let w = Math.floor(Math.random() * (this._winSize.width / 4));
this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(w, this.cloumn.position.y)), cc.callFunc(() =>{
this.enemyHeroImg.active = true;
this.enemyGunImg.active = true;
this.enemyAni();
}, this)));
},
//敌方柱子运动
enemyMove : function(){
this.enemyHeroImg.active = false;
this.enemyGunImg.active = false;
this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(-this._winSize.width / 2 - 100, this.cloumn.position.y)), cc.callFunc(() =>{
if(this.callBack){
this.callBack();
}
})));
},
//获取敌方子弹的世界坐标
enemyBulletWorldPos : function(){
let pos = this.cloumn.convertToWorldSpaceAR(cc.v2(this.enemyGunImg.position));
return pos;
},
//设置炮的角度
setGunAngle : function(angle){
this.enemyGunImg.angle = angle;
},
//炮运动
gunAni : function(len){
let bulletPos = this.enemyBulletImg.position;
this.enemyBulletImg.runAction(cc.sequence(cc.moveTo(0.3, cc.v2(len, 0)), cc.callFunc(() =>{
if(this.hitHeroCallBack){
this.hitHeroCallBack();
}
this.enemyBulletImg.position = bulletPos;
})));
},
//敌方英雄死亡动画
enemyDie : function(){
this.enemyDieParticle.node.active = true;
this.enemyDieParticle.stopSystem();
this.enemyDieParticle.resetSystem();
//隐藏敌方英雄
this.enemyGunImg.active = false;
this.enemyHeroImg.active = false;
},
//播放音效
playSound : function(name, isLoop){
cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
if(err){
return;
}
var audioID = cc.audioEngine.playEffect(clip, isLoop);
});
},
//运动完成的回调
finishCallBack (callBack){
this.callBack = callBack;
},
//打中我方英雄后的回调
hitHeroCallBack : function(callBack){
this.hitHeroCallBack = callBack;
},
// called every frame
update: function (dt) {
},
});
//-------------gamePlay.js------------------
cc.Class({
extends: cc.Component,
properties: {
bgImg : cc.Node,
sunImg : cc.Node,
moonImg : cc.Node,
floorParent : cc.Node,
farHouseImg0 : cc.Node,
farHouseImg1 : cc.Node,
nearHouseImg0 : cc.Node,
nearHouseImg1 : cc.Node,
farFloorImg0 : cc.Node,
farFloorImg1 : cc.Node,
nearFloorImg0 : cc.Node,
nearFloorImg1 : cc.Node,
scoreText : cc.Label,
//我方英雄组件
heroNode : cc.Node,
shootLineImg : cc.Node,
myBulletImg : cc.Node,
myHeroImg : cc.Node,
myGunImg : cc.Node,
shieldImg : cc.Node,
bloodBar : cc.ProgressBar,
heroDieParticle : cc.ParticleSystem,
//结束层
endLayer : cc.Node,
bestScoreText : cc.Label,
allScoreText : cc.Label,
myBulletPrefab : {
default: [],
type: cc.Prefab,
},
enemyPrefab : cc.Prefab,
},
onLoad: function () {
this._winSize = cc.winSize;
this._canShooting = true; //是否能射击
this._canContact = true; //是否检测碰撞
this._curScore = 0; //当前得分
this._heroBloodValue = 100; //当前血量值
//打开物理系统
cc.director.getPhysicsManager().enabled = true;
//cc.director.getPhysicsManager().debugDrawFlags = true;
// 重力加速度的配置
cc.director.getPhysicsManager().gravity = cc.v2(0, -640);
//随机获取一种类型
this.randStyle = Math.floor(Math.random() * 100) % 3;
cc.sys.localStorage.setItem("gunHeroBgStyle", this.randStyle);
//角色类型
this.heroType = parseInt(cc.sys.localStorage.getItem("gunHeroType")) || 0;
//修改辅助线纹理
this.setImgTexture("imageRes/line" + this.heroType, this.shootLineImg);
//修改大炮纹理
this.setImgTexture("imageRes/gun" + this.heroType, this.myGunImg);
//游戏背景
this.setImgTexture("bg/bgImg" + this.randStyle, this.bgImg);
//太阳图片
if(this.randStyle == 2){
this.sunImg.active = false;
this.moonImg.active = true;
}
else{
this.moonImg.active = false;
this.sunImg.active = true;
this.setImgTexture("imageRes/sun" + this.randStyle, this.sunImg);
}
//远处房子
this.setImgTexture("imageRes/house" + this.randStyle, this.farHouseImg0);
this.setImgTexture("imageRes/house" + this.randStyle, this.farHouseImg1);
//近处房子
this.setImgTexture("imageRes/houshSmall" + this.randStyle, this.nearHouseImg0);
this.setImgTexture("imageRes/houshSmall" + this.randStyle, this.nearHouseImg1);
//远处地面
this.setImgTexture("imageRes/floor" + this.randStyle, this.farFloorImg0);
this.setImgTexture("imageRes/floor" + this.randStyle, this.farFloorImg1);
//近处地面
this.setImgTexture("imageRes/gameFloor" + this.randStyle, this.nearFloorImg0);
this.setImgTexture("imageRes/gameFloor" + this.randStyle, this.nearFloorImg1);
this.nearFloorImg0.zIndex = 5;
this.nearFloorImg1.zIndex = 5;
//得分
this.scoreText.string = "0";
this.node.on(cc.Node.EventType.TOUCH_START, this.onEventStart, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onEventMove, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onEventCancel, this);
this.node.on(cc.Node.EventType.TOUCH_END, this.onEventEnd, this);
//云动画
this.yunAni();
//创建敌人
this.createEnemy();
//我方英雄等待动作
this.myHeroAni(false);
//地方英雄等待动画
this._enemyNode.enemyAni();
//英雄身上的护盾动画
this.shieldImg.getComponent("spriteFrameAni").playAni("shield", 4, 0.1, true);
},
//云动画
yunAni : function(){
let curWidth = -this._winSize.width / 2;
while(curWidth < this._winSize.width / 2){
//随机一个类型
let t = Math.floor(Math.random() * 100) % 3;
//随机一个高度值
let h = Math.random() * (this._winSize.height * 1 / 6) + this._winSize.height * 2 / 8;
curWidth = curWidth + Math.random() * 150 + 150;
let yunNode = new cc.Node();
let yunSp = yunNode.addComponent(cc.Sprite);
yunNode.parent = this.floorParent;
yunNode.position = cc.v2(curWidth, h);
this.setImgTexture("imageRes/yun" + this.randStyle + "_" + t, yunSp);
yunNode.runAction(cc.repeatForever(cc.sequence(cc.moveBy(1.0, cc.v2(-20, 0)), cc.callFunc(() =>{
if(yunNode.position.x < -this._winSize.width / 2 - 100){
yunNode.position = cc.v2(this._winSize.width / 2 + 100, yunNode.position.y);
}
}))));
}
},
//创建敌人
createEnemy : function(){
let node = cc.instantiate(this.enemyPrefab);
node.position = cc.v2(0, -110);
node.parent = this.floorParent;
this._enemyNode = node.getComponent("enemy");
this._enemyNode.comeOnAni();
this._enemyNode.finishCallBack(()=>{
//可检测碰撞
this._canContact = true;
//设置为可发炮
this._canShooting = true;
node.removeFromParent();
node = null;
this.createEnemy();
});
this._enemyNode.hitHeroCallBack(()=>{
this._heroBloodValue = this._heroBloodValue - 25;
if(this._heroBloodValue <= 0){
this.playSound("sound/heroDie", false);
this._heroBloodValue = 0;
this.myHeroDie();
//显示结算界面
this.gameOver();
}
else{
this.playSound("sound/enemyDie", false);
this.setBloodValue();
//还原炮的角度
this.myGunImg.angle = 0;
//设置为允许开炮
this._canShooting = true;
this._canContact = true;
}
});
},
//更新炮管角度
updateGunAngle : function(){
this.shootLineImg.active = true;
this._curAngle = 0;
this.gunSchedule = function(){
if (this._curAngle < 90){
this._curAngle += 1;
this.myGunImg.angle = this._curAngle;
}
};
this.schedule(this.gunSchedule, 0.03);
},
//停止更新炮管
stopGunAngle(){
this.unschedule(this.gunSchedule);
this.shootLineImg.active = false;
},
//给自己的子弹绑定刚体
setBulletBody : function(){
//创建子弹
this.bulletNode = cc.instantiate(this.myBulletPrefab[this.heroType]);
this.bulletNode.parent = this.myGunImg;
this.bulletNode.position = this.myBulletImg.position;
let bulletSp = this.bulletNode.getComponent("contact");
bulletSp.contactCallBack((selfCollider, otherCollider) => {
if(!this._canContact){
return;
}
this.playSound("sound/openFire", false);
this._canContact = false;
//停止子弹监听
this.unschedule(this.bulletfun);
let bodyGroup0 = selfCollider.node.group;
let bodyGroup1 = otherCollider.node.group;
//子弹打到地面
if((bodyGroup0 == "heroBullet" && bodyGroup1 == "floor")
|| (bodyGroup0 == "floor" && bodyGroup1 == "heroBullet")){
this.node.runAction(cc.sequence(cc.delayTime(0.5),cc.callFunc(() =>{
this.bulletNode.removeFromParent();
this.bulletNode = null;
this.enemyOpenFire();
})));
}
//子弹打到柱子
if((bodyGroup0 == "heroBullet" && bodyGroup1 == "column")
|| (bodyGroup0 == "column" && bodyGroup1 == "heroBullet")){
this.node.runAction(cc.sequence(cc.delayTime(0.5),cc.callFunc(() =>{
this.bulletNode.removeFromParent();
this.bulletNode = null;
this.enemyOpenFire();
})));
}
//子弹打到敌人
if((bodyGroup0 == "heroBullet" && bodyGroup1 == "enemy")
|| (bodyGroup0 == "enemy" && bodyGroup1 == "heroBullet")){
this._enemyNode.enemyDie();
this.node.runAction(cc.sequence(cc.delayTime(0.3),cc.callFunc(() =>{
this.bulletNode.removeFromParent();
this.bulletNode = null;
this.updateScore();
this.myHeroAni(true);
this.myHeroScaleAni();
this.gameBgAni();
this._enemyNode.enemyMove();
})));
}
});
},
//我方英雄运动
myHeroAni : function(isRun){
if(isRun){
this.myHeroImg.getComponent("spriteFrameAni").playAni("heroRun" + this.heroType + "_", 5, 0.06, true);
}
else{
this.myHeroImg.getComponent("spriteFrameAni").playAni("heroWait" + this.heroType + "_", 3, 0.1, true);
}
},
//我方英雄缩放效果
myHeroScaleAni : function(){
this.heroNode.runAction(cc.sequence(cc.scaleTo(1.0, 1.1), cc.scaleTo(1.0, 1.0)));
},
//背景运动
gameBgAni : function(){
//远处房子
let fw = this.farHouseImg0.width;
this.farHouseImg0.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-200, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
if(this.farHouseImg0.position.x <= -fw - this._winSize.width / 2){
this.farHouseImg0.position = cc.v2(this.farHouseImg1.position.x + fw, this.farHouseImg0.position.y);
}
this.myHeroAni(false);
})));
this.farHouseImg1.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-200, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
if(this.farHouseImg1.position.x <= -fw - this._winSize.width / 2){
this.farHouseImg1.position = cc.v2(this.farHouseImg0.position.x + fw, this.farHouseImg1.position.y);
}
})));
//近处房子
let nw = this.nearHouseImg0.width;
this.nearHouseImg0.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-300, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
if(this.nearHouseImg0.position.x <= -nw - this._winSize.width / 2){
this.nearHouseImg0.position = cc.v2(this.nearHouseImg1.position.x + nw, this.nearHouseImg0.position.y);
}
})));
this.nearHouseImg1.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-300, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
if(this.nearHouseImg1.position.x <= -nw - this._winSize.width / 2){
this.nearHouseImg1.position = cc.v2(this.nearHouseImg0.position.x + nw, this.nearHouseImg1.position.y);
}
})));
//远处地面
let ffw = this.farFloorImg0.width;
this.farFloorImg0.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-400, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
if(this.farFloorImg0.position.x <= -ffw - this._winSize.width / 2){
this.farFloorImg0.position = cc.v2(this.farFloorImg1.position.x + ffw, this.farFloorImg0.position.y);
}
})));
this.farFloorImg1.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-400, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
if(this.farFloorImg1.position.x <= -ffw - this._winSize.width / 2){
this.farFloorImg1.position = cc.v2(this.farFloorImg0.position.x + ffw, this.farFloorImg1.position.y);
}
})));
//近处地面
let nfw = this.nearFloorImg0.width;
for(let i = 0; i < 100; i++){
this.nearFloorImg0.runAction(cc.sequence(cc.delayTime(0.02 * i), cc.callFunc(() =>{
if(i % 9 == 0){
this.playSound("sound/walk", false);
}
let pX1 = this.nearFloorImg0.position.x - 4;
this.nearFloorImg0.position = cc.v2(pX1, this.nearFloorImg0.position.y);
let pX2 = this.nearFloorImg1.position.x - 4;
this.nearFloorImg1.position = cc.v2(pX2, this.nearFloorImg1.position.y);
if(pX1 <= -nfw - this._winSize.width / 2){
this.nearFloorImg0.position = cc.v2(this.nearFloorImg1.position.x + nfw, this.nearFloorImg0.position.y);
}
if(pX2 <= -nfw - this._winSize.width / 2){
this.nearFloorImg1.position = cc.v2(this.nearFloorImg0.position.x + nfw, this.nearFloorImg1.position.y);
}
})));
}
},
//敌方开炮
enemyOpenFire : function(){
//敌方子弹世界坐标
let enemyBulletPos = this._enemyNode.enemyBulletWorldPos();
//我方英雄世界坐标
let myHeroPos = this.myHeroImg.parent.convertToWorldSpaceAR(cc.v2(this.myHeroImg.position.x, this.myHeroImg.position.y + 30));
//计算夹角
let lenX = Math.abs(enemyBulletPos.x - myHeroPos .x);
let lenY = Math.abs(enemyBulletPos.y - myHeroPos .y);
let angle = Math.atan2(lenY, lenX) * 180 / Math.PI;
//设置敌方小火炮的角度
this._enemyNode.setGunAngle(angle);
//计算炮运行的距离
let len = Math.sqrt(Math.pow(lenX, 2) + Math.pow(lenY, 2));
this._enemyNode.gunAni(len);
this.playSound("sound/enemyBullet", false);
},
//刷新英雄的血量
setBloodValue : function(){
//设置盾牌透明度
let p = this._heroBloodValue / 100;
this.shieldImg.opacity = Math.floor(p * 255);
//设置血量进度
this.bloodBar.progress = p;
},
//我方英雄死亡动画
myHeroDie : function(){
this.heroDieParticle.node.active = true;
this.heroDieParticle.stopSystem();
this.heroDieParticle.resetSystem();
//隐藏我方英雄
this.heroNode.active = false;
},
//游戏结束
gameOver : function(){
this.node.runAction(cc.sequence(cc.delayTime(1.0),cc.callFunc(() =>{
//显示结算界面
this.endLayer.active = true;
//显示最高得分
let bestScore = parseInt(cc.sys.localStorage.getItem("gunBestScore")) || 0;
if(this._curScore > bestScore){
this.bestScoreText.string = this._curScore;
cc.sys.localStorage.setItem("gunBestScore", this._curScore);
}
else{
this.bestScoreText.string = bestScore;
}
//显示当前得分
this.allScoreText.string = this._curScore;
})));
},
// 按钮的回调
exitCallBack : function(event, customEventData){
this.playSound("sound/click", false);
cc.director.preloadScene('start', function () {
cc.director.loadScene('start');
});
},
//重新开始回调
refreshCallBack : function(event, customEventData){
this.playSound("sound/click", false);
cc.director.preloadScene('playScene', function () {
cc.director.loadScene('playScene');
});
},
//屏幕触摸回调
onEventStart : function(event){
if(!this._canShooting){
return;
}
cc.log("onEventStart");
this.updateGunAngle();
},
onEventMove : function(event){
cc.log("onEventMove");
},
onEventEnd : function(event){
if(!this._canShooting){
return;
}
cc.log("onEventEnd");
this.playSound("sound/heroBullet", false);
this._canShooting = false;
this.stopGunAngle();
this.setBulletBody(this.myBulletImg);
let x = 5000;
//2号子弹体积较大,需要更大的力
if(this.heroType == 1){
x = 7000;
}
//通过角度计算力度
let y = x * Math.tan(Math.abs(this._curAngle) * (Math.PI / 180));
//给子弹设置冲量
this.bulletNode.getComponent(cc.RigidBody).applyForceToCenter(cc.v2(x, y));
let curPos = this.bulletNode.position;
let lastPos = curPos;
this.bulletfun = function(){
curPos = this.bulletNode.position;
//计算角度
let lenX = curPos.x - lastPos.x;
let lenY = 0;
let r = 0;
if(curPos.y < lastPos.y){ //向上运动
lenY = curPos.y - lastPos.y;
r = Math.atan2(lenY, lenX) * 180 / Math.PI;
}
else{ //向下运动
lenY = lastPos.y - curPos.y;
r = -1 * Math.atan2(lenY, lenX) * 180 / Math.PI;
}
lastPos = curPos;
this.bulletNode.angle = r;
};
this.schedule(this.bulletfun, 0.1);
},
onEventCancel : function(event){
this.onEventEnd(event);
},
//刷新得分
updateScore : function(){
this._curScore += 1;
this.scoreText.string = this._curScore;
this.playSound("sound/addScore", false);
},
//更换纹理
setImgTexture : function(str, node){
cc.loader.loadRes(str, cc.SpriteFrame, function (err, spriteFrame) {
if (err) {
cc.error(err.message || err);
return;
}
node.getComponent(cc.Sprite).spriteFrame = spriteFrame;
}.bind(this));
},
//播放音效
playSound : function(name, isLoop){
cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
if(err){
return;
}
var audioID = cc.audioEngine.playEffect(clip, isLoop);
});
},
update: function (dt) {
},
});
//-------------gameStart.js------------------
cc.Class({
extends: cc.Component,
properties: {
heroBtn : {
default: [],
type: cc.Button,
},
},
onLoad: function () {
//设置当前选择的英雄
let tag = parseInt(cc.sys.localStorage.getItem("gunHeroType") || 0);
for(let i = 0; i < 4; i++){
let hero = this.heroBtn[i];
hero.interactable = true;
}
let hero = this.heroBtn[tag];
hero.interactable = false;
},
//开始按钮回调
startBtnCallBack : function(event, customEventData){
this.playSound("sound/click", false);
//显示游戏界面
cc.log("startBtnCallBack");
cc.director.preloadScene('playScene', function () {
cc.director.loadScene('playScene');
});
},
//选择英雄按钮的回调
selectHeroCallBack : function(event, customEventData){
this.playSound("sound/select", false);
let tag = parseInt(customEventData);
for(let i = 0; i < 4; i++){
let hero = this.heroBtn[i];
hero.interactable = true;
}
let hero = this.heroBtn[tag];
hero.interactable = false;
//保存当前选择的英雄
cc.sys.localStorage.setItem("gunHeroType", tag);
},
//播放音效
playSound : function(name, isLoop){
cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
if(err){
return;
}
let audioID = cc.audioEngine.playEffect(clip, isLoop);
});
},
// called every frame
update: function (dt) {
},
});
//-------------spriteFrameAni.js------------------
cc.Class({
extends: cc.Component,
properties: {
bigImg : cc.SpriteAtlas,
},
onLoad () {
},
playAni(nameStr, count, dt, isLoop){
this.stopAni();
this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + 0);
let array = [];
for(let i = 0; i < count; i++){
array.push(cc.delayTime(dt));
array.push(cc.callFunc(() =>{
this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + i);
}));
}
if(isLoop){
this.node.runAction(cc.repeatForever(cc.sequence(array)));
}
else{
this.node.runAction(cc.sequence(array));
}
},
stopAni(){
this.node.stopAllActions();
},
onDestroy () {
},
});
感谢:
本文转载自 https://mp.weixin.qq.com/s/K932G6FvIE-5foQGgKraug 这篇文章,这里感谢原作者对于技术的分享。
下载: