视频操作地址:https://www.bilibili.com/video/BV1NN4y1V7Jy/?vd_source=0a0b591838e1a4cda6ec55da0e1c9019
源码地址:https://gitee.com/OnlyOneW/cocos-study/tree/master/cocos-cow
0 前提
cococs官方脚本指南
已安装Cocos Creator 3.5.2
1 新建2D项目
2 新建文件夹
在资源管理器中新建文件夹
用来保存对应的资源
- scenes : 保存场景
- scripts : 保存脚本资源
- res : 保存图片等资源
- framework : 保存自定义类文件
- clips : 保存动画文件
- prefacs : 保存自定义预制文件
3 拖入图片等资源至res文件夹
会提供资源文件:res下的res-cow
4 搭建主页面
-
- 项目,项目设置里,调整尺寸为
竖屏
(适配屏幕高度):640*960,
- 项目,项目设置里,调整尺寸为
-
- 选中层级管理器,保存场景至,scenes文件夹下,命名:Main (ctrl+s 保存)
-
- 搭建背景
新建2D对象
,sprite(精灵):spt_bg
设置背景图、尺寸:640*960 (默认的)
- 搭建背景
-
- 搭建按钮
在spt_bg下,新建UI组件
,Button(按钮):btn_capture
删除btn_capture下的Label
设置4种状态下的图片:初始、按下,设置给的图片,其余2个删掉
设置大小:173*129
拖动到合适位置
- 搭建按钮
-
- 搭建牛儿
把第一张牛儿图片拖到
层级管理器spt_bg
下,重命名为:cow
- 搭建牛儿
5 奔跑的牛
5.1 代码实现
在framework新建TypeScript,命名:CowSkin
- 牛的皮肤类
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('CowSkin')
export class CowSkin {
@property(cc.SpriteFrame)
public cows : [cc.SpriteFrame] = [];
}
在scripts新建TypeScript,命名:cow
2. 牛的类型数组
import { CowSkin } from '../framework/CowSkin';
@property(CowSkin)
public cow_sets : [CowSkin] = [];
private _intervalTime = 0;
private _randomType = Math.floor(Math.random()*3);
- update回调函数实现帧动画,更换皮肤
update(deltaTime: number) {
let dt = deltaTime ;
// 间隔时间
this._intervalTime += dt;
let index = Math.floor(this._intervalTime / 0.2);
index = index%3;
// 获取一种牛的类型
let cowSet = this.cow_sets[this._randomType];
// 获取精灵组件
let sprite = this.node.getComponent(cc.Sprite);
sprite.spriteFrame = cowSet.cows[index];
}
5.2 定义一个数组实现奔跑动画
在clips 文件夹下新建动画剪辑:runClip,层级管理器,选中cow,选择动画编辑器,关联新建的runClip文件,编辑动画,设置播放模式,加入尾帧事件,runCallback
cow.ts加入下面函数:
runCallback() {
cc.log("一个轮回结束!");
this._randomType = Math.floor(Math.random()*3);
}
选择Play on load
保存
退出
动画编辑
5.3 属性检查器按顺序拖入图片
层级管理器,选中cow,关联cow.ts,设置参数,并按顺序拖入图片
5.4 将整个cow节点作为预制体
把cow节点拖到prefabs文件夹下,删除cow节点,把cow预制节点,拖到
spt_bg下
选择Play on load
至此随机不同种的牛奔跑,已实现
6 新建game.ts
新建game.ts当做全局脚本文件,挂载到Canvas
下
7 套绳
拖动套绳图片:rope,至背景图片spt_bg
下,默认不显示
7.1 改锚点
-
- 改预制体cow的锚点
选中,选矩形变化,移至牛头下,用于方便判断牛头是否套住,删除原来的cow,重新拖一下
-
- 调整绳子的锚点至,圆圈中央
7.2 game.ts新建属性
@property(cc.Node)
public rope_node : cc.Node = null;
@property(cc.Node)
public cow_ins : cc.Node =null;
@property(cc.SpriteFrame)
public rope_imgs : [cc.SpriteFrame] = [];
@property(cc.Prefab)
public cow_prefab : cc.Prefab = null;
@property
public time = 0;
private _mainScene = 'Main';
并在Canvas
里绑定
- rope_node(rope)
- cow_ins(cow)
- rope_imgs(4张绳子图片按顺序拖动)
- cow_prefab(cow预制体)
- time(60)
保存
注:此处容易忽略初始化绑定
7.3 按钮事件绑定代码,
start() {
let btn_capture_node = cc.find("Canvas/spt_bg/btn_capture");
btn_capture_node.on(NodeEventType.TOUCH_START, this._touchStart_btn_capture, this);
}
并定义
_touchStart_btn_capture (touch: Touch, event: EventTouch) {
}
具体请见最后
8 计分器和倒计时
8.1 第一步:界面添加Label
-
分数显示
在spt_bg下,新建2D对象
,Label(文本):lb_score
,来显示得分
设置初始值 : Score:0
设置大小 : 50
拖动到合适位置 -
倒计时
在spt_bg下,新建2D对象
,Label(文本):lb_count_down
,来显示倒计时
设置初始参数:60s
设置大小 : 50
并添加位图字体样式和字体颜色:#EB78E6
拖动到合适位置
8.2 第二步:用位图字体让显示更美观
去掉勾选:UseSystemFont
拖入已备好的字体资源,至Font
8.3 第三步:编写逻辑代码
此步片段代码可忽略,直接查看总代码
- 分数显示
start () {
// 定义初始化得分为0
this.scoreNum = 0;
}
// 捕捉成功,分数+1
this.scoreNum++;
let lb_score = cc.find("Canvas/spt_bg/lb_score").getComponent(cc.Label);
lb_score.string = "Score: " + this.scoreNum;
- 倒计时
start () {
// 获得计时器组件
let countDownLabel = cc.find("Canvas/spt_bg/lb_count_down").getComponent(cc.Label);
let time = 60;
// 倒计时
this.schedule(function () {
time--;
countDownLabel.string = "Time: " + time + " s";
},1);
},
9 背景音效
9.1 导入模块
import { AudioSource, assert} from 'cc';
9.2 添加组件:AudioSource
在Canvas
里,添加组件 按钮,选择 Audio -> AudioSource
设置文件
设置播放方式
9.3 属性
@property(cc.AudioClip)
public audio_clip : cc.AudioClip = null;
@property(AudioSource)
public audioSource: AudioSource = null!;
在Canvas
里绑定属性 audio_clip
9.4 初始化audioSource属性
start() {
// 获取 AudioSource 组件
const audioSource_set = this.node.getComponent(AudioSource)!;
// 检查是否含有 AudioSource,如果没有,则输出错误消息
assert(audioSource_set);
// 将组件赋到全局变量 audioSource 中
this.audioSource = audioSource_set;
}
9.5 播放套中音效
// 音效
this.audioSource.playOneShot(this.audio_clip, 1);
10 粒子
10.1 导入模块
import { ParticleSystem2D} from 'cc';
10.2 新建ParticleSystem2D(粒子)
在rope下,新建2D对象
,ParticleSystem2D(粒子):pc2d_fireworks
10.3 设置粒子参数
不勾选 PlayOnLoad
勾选 Custom
设置 SpriteFrame
10.4 显示粒子效果
套中牛,显示粒子效果
// 粒子
let pc2d_fireworksNode = cc.find("Canvas/spt_bg/rope/pc2d_fireworks");
this.fireworks = pc2d_fireworksNode.getComponent(ParticleSystem2D)
this.fireworks.resetSystem()
11 最终成就系统
倒计时为0时游戏结束,并根据玩家的最终得分显示成就;比如小于等于3分就是套牛青铜,大于三分小于6分就是套牛高手,大于6分以上就是套牛王者。
11.1 制作一个显示用的弹窗
包含一个关闭按钮,标题和称号。
-
spt_result
Canvas
下,新建2D对象
,sprite(精灵):spt_result
设置背景图、尺寸、九宫格(Sliced)模式,
(九宫格编辑得选中图片去编辑)
默认不显示
-
close
拖入关闭按钮至spt_result 背景下,,命名为close
调整参数
调整位置:182 182 -
lb_title
在spt_result下,新建2D对象
,Label(文本):lb_title
,来显示等级
设置初始参数:60 #252323
调整位置 -
lb_content
在spt_result下,新建2D对象
,Label(文本):lb_content
,来显示分数
设置初始参数:80 #252323
调整位置
11.2 最终代码
11.2.1 game.ts导入模块
import { _decorator, Component, Node ,Vec3 , NodeEventType,Tween, AudioSource, assert,ParticleSystem2D} from 'cc';
11.2.2 套绳逻辑代码
_touchStart_btn_capture (touch: Touch, event: EventTouch) {
let bgNode = touch.currentTarget._parent;
let currentTarget = touch.currentTarget;
this.rope_node.active = true;
// 设置绳子在当前父节点的顺序
this.rope_node.setSiblingIndex(100);
let rope_node_p = this.rope_node.getPosition();
let rope_node_y_start = - 600 ;
let rope_node_y_up = 115 ;
let rope_node_y_down = -600 ;
// 设置绳子起始位置
this.rope_node.setPosition(rope_node_p.x,rope_node_y_start);
rope_node_p = this.rope_node.getPosition();
let that = this ;
let tao_num: number = 100;
let tween_node :cc.Node = this.rope_node ;
let tweenDuration: number = 0.5;
let t1 = cc.tween(tween_node)
.to(tweenDuration, { position: new Vec3(rope_node_p.x,rope_node_y_up,0) }
,{
onUpdate:(target:Vec3, ratio:number)=>{
this.rope_node = target;
}
}
)
// to 动作完成后会调用该方法
.call( ()=>{
// 获取当前牛儿的x点
let cow_ins_p = that.cow_ins.getPosition()
let currentX = cow_ins_p.x;
if (currentX > -tao_num && currentX < tao_num){
cc.log("捕捉成功!");
// 音效
this.audioSource.playOneShot(this.audio_clip, 1);
// 粒子
let pc2d_fireworksNode = cc.find("Canvas/spt_bg/rope/pc2d_fireworks");
this.fireworks = pc2d_fireworksNode.getComponent(ParticleSystem2D)
this.fireworks.resetSystem()
// 移除
bgNode.removeChild(that.cow_ins);
// 获取牛儿的类型
let cowType = that.cow_ins.getComponent("cow")
let ropeType = cowType._randomType +1;
that.rope_node.getComponent(cc.Sprite).spriteFrame = that.rope_imgs[ropeType];
// 生成新的牛节点
that.cow_ins = cc.instantiate(that.cow_prefab);
that.cow_ins.setPosition(cow_ins_p.x,0);
bgNode.addChild(that.cow_ins);
//
that.success = true;
// 分数+1
that.scoreNum ++;
} else {
cc.log("捕捉失败!")
}
})
let t2 = cc.tween(tween_node)
.to(tweenDuration, { position: new Vec3(rope_node_p.x,rope_node_y_down,0) }
,{
onUpdate:(target:Vec3, ratio:number)=>{
this.rope_node = target;
}
}
)
// to 动作完成后会调用该方法
.call( ()=>{
that.rope_node.getComponent(cc.Sprite).spriteFrame = that.rope_imgs[0];
// 判断是否捕捉成功
if (that.success == true) {
let scoreLabel = cc.find("Canvas/spt_bg/lb_score").getComponent(cc.Label);
scoreLabel.string = "Score:" + that.scoreNum;
that.success = false;
}
})
cc.tween(tween_node).sequence(t1, t2).start(); // 将 t1 和 t2 两个缓动加入到新的缓动队列内
}
11.2.3 游戏结束,展示结果弹窗
start() {
// 获取 AudioSource 组件
const audioSource_set = this.node.getComponent(AudioSource)!;
// 检查是否含有 AudioSource,如果没有,则输出错误消息
assert(audioSource_set);
// 将组件赋到全局变量 audioSource 中
this.audioSource = audioSource_set;
let btn_capture_node = cc.find("Canvas/spt_bg/btn_capture");
btn_capture_node.on(NodeEventType.TOUCH_START, this._touchStart_btn_capture, this);
this.success = false;
// 初始分数
this.scoreNum = 0;
let countDownLabel = cc.find("Canvas/spt_bg/lb_count_down").getComponent(cc.Label);
countDownLabel.string = this.time + "s";
this.schedule(function () {
this.time --;
countDownLabel.string = this.time + "s";
if (this.time == 0) {
cc.log("游戏结束!");
// 获取弹窗节点
let resultNode = cc.find("Canvas/spt_result");
//绑定关闭事件
let closeNode = cc.find("Canvas/spt_result/close");
closeNode.on(NodeEventType.TOUCH_START, this._touchStart_close, this);
// 获取title和content两个节点
let titleNode = resultNode.getChildByName("lb_title");
let contentNode = resultNode.getChildByName("lb_content");
// 展示分数
titleNode.getComponent(cc.Label).string = "最终得分 " + this.scoreNum;
// 获取组件
let contentLabel = contentNode.getComponent(cc.Label);
switch (true) {
case this.scoreNum <= 3:
contentLabel.string = "套牛新手";
break;
case this.scoreNum < 6:
contentLabel.string = "套牛神手";
break;
case this.scoreNum >= 6:
contentLabel.string = "套牛圣手";
break;
}
resultNode.active = true;
let score = this.scoreNum;
cc.director.pause();
}
},1);
}
11.2.4 关闭按钮
// 关闭按钮,继续游戏
_touchStart_close(touch: Touch, event: EventTouch) {
cc.log("继续游戏");
cc.director.resume();
cc.director.loadScene(this._mainScene);
}
错误:因为函数后有逗号
index.js:1 Error: Unable to resolve bare specifier ‘__unresolved_2’ from http://localhost:7456/scripting/x/chunks/34/341ab3341f38daa5d6eb502f45f16e9d150576f5.js (SystemJS Error#8 https://git.io/JvFET#8)
参考
补充说明
资源来源于网络各种免费分享,及自身学习总结,
若有不当可评论指正