用Cocos制作一个射击游戏的过程及代码是什么
Admin 2022-06-15 群英技术资讯 844 次浏览
这篇文章给大家分享的是用Cocos制作一个射击游戏的过程及代码是什么。小编觉得挺实用的,因此分享给大家做个参考,文中的介绍得很详细,而要易于理解和学习,有需要的朋友可以参考,接下来就跟随小编一起了解看看吧。


机制与之前手柄实例的小车相同,使用touchmove监听触摸事件,

onLoad(){
//初始化为90度
this.node.angle=90;
this.node.on('touchstart',this.onTouchStart,this);
this.node.on('touchmove',this.onTouchMove,this);
this.node.on('touchend',this.onTouchEnd,this);
this.node.on('touchconcel',this.onTouchConcel,this);
}
onTouchStart(e:cc.Event.EventTouch){
//获取开始的位置
this.starPos=this.node.parent.convertToNodeSpace(e.getLocation());
//获取炮口的初始角度
this.starAngle=this.node.angle;
}
onTouchEnd(e:cc.Event.EventTouch){
}
onTouchMove(e:cc.Event.EventTouch){
//获取触点当前的位置
let pos:cc.Vec2=this.node.parent.convertToNodeSpace(e.getLocation());
//获取角度
//angle顺时针为负逆时针为正
let sweep_radian=pos.signAngle(this.starPos);//pos相对于starPose的角度p相对s顺时针为正
let sweep_angle=sweep_radian*180/Math.PI;//弧度制换算角度
//让炮塔的角度指向最终的角度
let angle=this.starAngle-sweep_angle;
//将角度限制在45~135之间
if(angle<45)angle=45;
if(angle>135)angle=135;
cc.log("炮口摆动:"+sweep_angle+"最终角度位置:"+angle);
this.node.angle=angle;
}

onTouchEnd(e:cc.Event.EventTouch){
this.fire();
}
onTouchConcel(e:cc.Event.EventTouch){
}
fire(){
if(this.bulleteicon==null)return;
let bullet:cc.Node=new cc.Node();
let sprite:cc.Sprite=bullet.addComponent(cc.Sprite);
sprite.spriteFrame=this.bulleteicon;
//挂载到射击系统节点下
bullet.parent=this.node.parent;
//设置相对父节点位置
let ration=this.node.angle*Math.PI/180;
let direction=cc.v2(Math.cos(ration),Math.sin(ration));
bullet.angle=this.node.angle;
let r=100;
bullet.setPosition(cc.v3(r*direction.x,r*direction.y,0));
//附加脚本组件
let script=bullet.addComponent(Buletet);
script.explodeImg=this.explodeImg;
script.direction=direction;
}
start () {
this.schedule(this.onTimer,0.01);
}
onTimer(){
if(this.node.y>300){
this.unschedule(this.onTimer);
this.explode();
return;
}
let dx=this.direction.x*5;
let dy=this.direction.y*5;
this.node.y+=dy;
this.node.x+=dx;
}
explode(){
let sp:cc.Sprite=this.getComponent(cc.Sprite);
sp.spriteFrame=this.explodeImg;
//将子弹缩小
this.node.scale=0.1;
//爆炸动画效果缓动系统
let self=this;
cc.tween(this.node)
.to(0.5,{scale:1,opacity:0})
.call(function(){
self.afterExplode();
})
.start();
}
afterExplode(){
this.node.destroy();
}
本次bug:

计算子弹和靶标的相对位置,若小于范围,则判断为命中靶,执行命中的操作,否则判断为没有命中,执行没有命中的操作。
脚本需传入靶子节点,增加target属性
@property(cc.SpriteFrame)
explodeImg: cc.SpriteFrame = null;
direction: cc.Vec2 = null;
target: cc.Node = null;
onLoad() {
}
start() {
this.schedule(this.onTimer, 0.01);
}
onTimer() {
if (this.node.y > 350) {
if (this.isHit()) {
//播放爆炸效果
this.explode();
console.log("命中靶");
}
else {
console.log("脱靶");
this.disMiss();
}
this.unschedule(this.onTimer);
return;
}
let dx = this.direction.x * 5;
let dy = this.direction.y * 5;
this.node.y += dy;
this.node.x += dx;
}
//判断是否命中
isHit(): boolean {
let targetPos: cc.Vec2 = this.geWorldLocation(this.target);
let selfPos: cc.Vec2 = this.geWorldLocation(this.node);
let distance = Math.abs(targetPos.x - selfPos.x);
console.log("靶标x=" + targetPos.x + " , 子弹x=" + selfPos.x);
if (distance < 50) {
return true;
}
else {
return false;
}
}
explode() {
let sp: cc.Sprite = this.getComponent(cc.Sprite);
sp.spriteFrame = this.explodeImg;
//将子弹缩小
this.node.scale = 0.1;
//爆炸动画效果缓动系统
let self = this;
cc.tween(this.node)
.to(0.5, { scale: 1, opacity: 0 })
.call(function () {
self.disMiss();
})
.start();
}
geWorldLocation(node: cc.Node): cc.Vec2 {
let pos = node.getPosition();
//注意这里是node.parent。方法的调用者要是当前节点的坐标系
return node.parent.convertToWorldSpaceAR(pos);
}
disMiss() {
this.node.destroy();
}
本次bug:
获取世界坐标时,没有调用其父节点的坐标系,用了当前节点的坐标系,所以返回的依然是自身当前坐标系的值。记得转换世界坐标的方法调用者是当前节点的坐标系,一般为其父节点 return node.parent.convertToWorldSpaceAR(pos);(以锚点为原点)

在靶子的节点下增加脚本,控制移动,左右来回移动
同时,当子弹命中后增加文字提示效果。
文字提示:
cheer() {
//创建节点并挂载
let node: cc.Node = new cc.Node();
node.parent = this.node.parent;//两者同一级,同一个父对象
let label: cc.Label = node.addComponent(cc.Label);
label.string = "+10分";
//设置位置、透明度等
node.setPosition(cc.v3(0, 250, 0));
node.opacity = 200;
node.color = new cc.Color(255, 0, 0);
//动效
cc.tween(node)
.to(0.5, { scale: 1.5 })
.to(0.2, { opacity: 0 })
.call(function () {
node.destroy();
})
.start();
}
update (dt) {
let speed=3;
if(this.isLeft){
speed=-speed;
}
this.node.x+=speed;
if(this.isLeft&&this.node.x<-350){
this.isLeft=false;
}
if(!this.isLeft&&this.node.x>350){
this.isLeft=true;
}
}

调用方法有两种,一种为在炮塔脚本中获取弹药库节点在调用,另一种为设置公共类,(静态变量),在onLoad()方法中就初始化该节点,然后直接调用。用后者。
@property(cc.SpriteFrame)
bulleteIcon: cc.SpriteFrame = null;
capacity: number = 10;
stockNumber: number = 10;
onLoad() {
let space: number = this.node.width / this.capacity;
for (let i = 0; i < this.capacity; i++) {
//生成图片
let bulleteNode: cc.Node = new cc.Node();
let bulleteSprite: cc.Sprite = bulleteNode.addComponent(cc.Sprite);
bulleteSprite.spriteFrame = this.bulleteIcon;
this.node.addChild(bulleteNode);
//设置位置
bulleteNode.x += space * i + 10;
bulleteNode.y = 0;
}
}
start() {
}
consum(num: number) {
this.stockNumber -= num;
if (this.stockNumber < 0) {
this.stockNumber = 0;
}
this.display();
}
display() {
let nodes: cc.Node[] = this.node.children;
console.log(nodes.length);
for(let i=0;i<nodes.length;i++){
if(i>=this.stockNumber){
nodes[i].active=false;
}
}
}
//静态类,全局变量,将所有会公用的变量、类定义在Common类中
static ammo:Ammo=null;
onLoad() {
Common.ammo=cc.find('Canvas/弹药').getComponent('Ammo');
console.log(Common.ammo);
}
此处bug:
cc.find()方法中记得用除法的斜杠。
子弹耗尽提示分数

onLoad () {
let replay:cc.Node=cc.find('Canvas/结束提示框/再玩一局');
console.log(replay);
replay.on('touchstart',this.dismiss,this);
this.node.on('touchstart',this.onTouchdisable,this);
this.node.on('touchmove',this.onTouchdisable,this);
this.node.on('touchend',this.onTouchdisable,this);
}
//显示提示框
show(){
this.node.active=true;
let scoreNode : cc.Node = cc.find('分数框/分数', this.node);
let scoreLabel : cc.Label = scoreNode.getComponent(cc.Label);
scoreLabel.string = Common.score + '分';
}
//隐藏提示框
dismiss(){
this.node.active=false;
}
//遮罩显示时屏蔽
onTouchdisable(e:cc.Event.EventTouch){
e.stopPropagation();
}
start () {
}
//静态类,全局变量,将所有会公用的变量、类定义在Common类中
static ammo:Ammo=null;
static score : number = 0;
static resultdialog : ResultDialog = null;
onLoad() {
Common.resultdialog=cc.find('Canvas/结束提示框').getComponent('ResultDialog');
Common.ammo=cc.find('Canvas/弹药').getComponent('Ammo');
}
在Bullete方法中增加分数增加
if (this.isHit()) {
//播放爆炸效果
this.explode();
//显示+10分
this.cheer();
//总分数+10
Common.score += 10;
console.log("命中靶");
}

该小游戏比较简单,重开只需要重置弹药库节点即可,因此reset方法放在Ammo脚本中
在公共类中创建Ammo对象,设置静态方法,重置得分、以及调用Ammo的reset方法。
Ammo(弹药库类)脚本添加
reset(){
this.stockNumber=this.capacity;
this.display();
}
//静态类,全局变量,将所有会公用的变量、类定义在Common类中
static ammo:Ammo=null;
static score : number = 0;
static resultdialog : ResultDialog = null;
onLoad() {
Common.resultdialog=cc.find('Canvas/结束提示框').getComponent('ResultDialog');
Common.ammo=cc.find('Canvas/弹药').getComponent('Ammo');
console.log(Common.ammo);
}
static resetGame() {
Common.score=0;
Common.ammo.reset();
}

1.炮塔脚本增加属性
//音效
@property(cc.AudioClip)
audioFire: cc.AudioClip = null;
@property(cc.AudioClip)
audioExplode: cc.AudioClip = null;
//炮塔图片
@property(cc.SpriteFrame)
iconNormal: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
iconActive: cc.SpriteFrame = null;
onTouchStart(e: cc.Event.EventTouch) {方法最后添加
//炮塔图片切换至激活
this.node.getComponent(cc.Sprite).spriteFrame = this.iconActive;
onTouchEnd(e: cc.Event.EventTouch) {方法最后添加
//图片恢复
this.node.getComponent(cc.Sprite).spriteFrame = this.iconNormal;
}
fire(){ 方法后添加
//将子弹爆炸音频传送至子弹脚本
script.audioExplode = this.audioExplode;
if (this.audioFire != null) {
cc.audioEngine.play(this.audioFire, false, 1);
}
}
播放音频的方法:==cc.audioEngine.play(this.audioFire, false, 1);==第二个参数为是否循环播放,第三个参数为音量大小
//添加属性
@property(cc.SpriteFrame)
explodeImg: cc.SpriteFrame = null;
在判断子弹命中靶子的操作后添加
if(this.audioExplode!=null){
cc.audioEngine.play(this.audioExplode,false,1);
}
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍了promise封装wx.request的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
这篇文章主要介绍了JavaScript树结构深度优先算法,树结构可以说是前端中最常见的数据结构之一,比如说DOM树、级联选择、树形组件,更多相关内容需要的小伙伴可以参考一下
这篇文章主要介绍了vant picker+popup 自定义三级联动案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
文本给大家分享的是js中this和箭头函数,其中关于this关键字是很多新手学习JavaScript时,比较难理解。箭头函数是新增的,小编觉得比较有意思,因此下文给大家介绍一下。对js中this和箭头函数感兴趣的朋友就继续往下看吧。
目录前言动画的本质动画的实现动画的推导小结前言到目前为止我们的 fabric.js 雏形已经有了,麻雀虽小五脏俱全,我们不仅能够在画布上自由的添加物体,同时还实现了点选和框选,并且能够对它们做一些变换,不过只有变换这个操作还不够灵活,要是能够让物体动起来就好了,于是就引入了这个章节的主题:动画,以及动画最核心的一个问题
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008