• 售前

  • 售后

热门帖子
入门百科

CocosCreator入门教程之用TS制作第一个游戏

[复制链接]
雪域蓝眸蓝nz 显示全部楼层 发表于 2021-10-26 13:45:24 |阅读模式 打印 上一主题 下一主题
目次


  • 条件
  • TypeScript VS JavaScript
  • 代码编辑器选择
  • 学习 TypeScript
  • TypeScript 情况配置
  • 配置自己的声明文件
  • 属性类型声明
  • 用 TypeScript 写一个游戏

条件

无论学什么技术知识,官方文档都应该是你第一个教程,所以请先至少阅读新手上路这一节 http://docs.cocos.com/creator/manual/zh/getting-started/ 再来看这篇文章。
这里假设你已经安装乐成了 Cocos Creator

TypeScript VS JavaScript

这里固然只会讲优点:
1. ts 是 js 的超集,全部 js 的语法 ts 都支持。
2. ts 支持靠近完美的代码提示,js 代码提示靠近于没有。
3. ts 有类型定义,编译时就可以排除许多无意义的错误。
4. ts 可以重构,适合大型项目。
5. ts 可以使用 es6 async之类的全部新语法。而 js Cocos Creator 还没有完全支持es6。
6. 最重要的一点:我以后的教程都会用 ts 写,如果你不用 ts,你就会永远失去我了

代码编辑器选择

这里只推荐两个:
       
  • Visual Studio Code   
  • WebStorm
vs code 的优点是快,与cocos creator 联合的好,一些功能必要自己安装插件。
webstorm 的优点是全部你想要的功能都天赋内置了,缺点是占内存,个人感觉另有点丑。
对于我自己来说,我在公司用 WebStorm,在家用 VS Code。
如果你还是不知道用哪个,我只能先推荐你用VS Code 因为下面的内容是面向VS Code。

学习 TypeScript

既然要用ts开发游戏,肯定要知道ts的语法,我这一篇文章不可能把全部ts的语法都讲完,所以https://www.tslang.cn/docs/home.html,固然,不肯定要一次性全看完,你可以先看个大概,遇到问题再补习。

TypeScript 情况配置

任意打开一个项目,把这几个都点一遍

控制台会输出

打开编辑器,你会发现一个名字为 creator.d.ts 的脚本

 creator 的提示都依靠这个脚本,引擎的api变更也要实时更新这个脚本,所以每次更新引擎的时候都要重新点一次上面谁人“更新VS Code只能提示数据“来重新天生creator.d.ts。
资源管理器右键新建一个ts脚本,点开后你会发现有许多没用的东西,而且还会有一个提示错误(1.81)。。。
  1. //  - [English] http://www.cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/typescript/index.html
  2. // Learn Attribute:
  3. //  - [Chinese] http://www.cocos.com/docs/creator/scripting/reference/attributes.html
  4. //  - [English] http://www.cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/reference/attributes/index.html
  5. // Learn life-cycle callbacks:
  6. //  - [Chinese] http://www.cocos.com/docs/creator/scripting/life-cycle-callbacks.html
  7. //  - [English] http://www.cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/life-cycle-callbacks/index.html
  8. const {ccclass, property} = cc._decorator;
  9. @ccclass
  10. export default class NewClass extends cc.Component {
  11.     @property(cc.Label)
  12.     label: cc.Label = null;
  13.     @property
  14.     text: string = 'hello';
  15.     // LIFE-CYCLE CALLBACKS:
  16.     // onLoad () {},
  17.     start () {
  18.     },
  19.     // update (dt) {},
  20. }
复制代码
编辑器右上角“打开步伐安装路径“,

static-》template-》new-script.ts
这个脚本就是新建ts脚本的默认样式,我们来重新编辑一下,编辑后的脚本如下
  1. const {ccclass, property} = cc._decorator;
  2. @ccclass
  3. export class NewClass extends cc.Component {
  4. }
复制代码
重新新建一个ts脚本,你会发现跟刚才编辑的默认脚本是一个样子了。

配置自己的声明文件

以d.ts为后缀名的文件,会被辨以为声明文件,creator.d.ts是引擎的声明文件,我们也可以定义自己的声明文件,必要注意的是声明文件要放在assets文件外,因为assets文件里的脚本都会被引擎编译,而声明文件的作用就是写代码时提示一下,编译之后就不必要了。
举个栗子
在项目的根目次添加一个global.d.ts文件

 然后在项目里的脚本就可以得到对应的提示


更多类型定义戳 https://www.tslang.cn/docs/handbook/declaration-files/introduction.html

属性类型声明
  1. const LEVEL = cc.Enum({EASY:1,HARD:2});
  2. @ccclass
  3. export class Game extends cc.Component {
  4.     // 整型
  5.     @property(cc.Integer)
  6.     intVar: number = 0;
  7.     // 浮点型
  8.     @property(cc.Float)
  9.     floatVar: number = 0;
  10.     // 布尔型
  11.     @property(cc.Boolean)
  12.     boolVar: boolean = false;
  13.     // 节点
  14.     @property(cc.Node)
  15.     nodeVar: cc.Node = null;
  16.     // 节点数组
  17.     @property([cc.Node])
  18.     nodeArrVar: Array<cc.Node> = [];
  19.     // Label
  20.     @property(cc.Label)
  21.     labelVar: cc.Label = null;
  22.     // 预制体
  23.     @property(cc.Prefab)
  24.     prefabVar: cc.Prefab = null;
  25.     // 点
  26.     @property(cc.Vec2)
  27.     vec2Var: cc.Vec2 = cc.v2();
  28.     // 自定义节点
  29.     @property(Player)
  30.     palyerVar: Player = null;
  31.     // 重点来了,自定义枚举
  32.     /**
  33.      * 全局变量
  34.      * const LEVEL = cc.Enum({EASY:1,HARD:2});
  35.      */
  36.     @property({
  37.         type:LEVEL
  38.     })
  39.     enumVa = LEVEL.EASY;
  40. }
复制代码


用 TypeScript 写一个游戏

末了我们来切身了解一下TypeScript的柔软丝滑。
挑一个熟悉的游戏来写,官方文档里有一个摘星星的游戏,我们用Ts重新写一下。
第一步:新建一个工程

第二步:写几个脚本
Game.ts
  1. import { Player } from "./Player";
  2. const { property, ccclass } = cc._decorator;
  3. @ccclass
  4. export class Game extends cc.Component {
  5.     // 这个属性引用了星星的预制资源
  6.     @property(cc.Prefab)
  7.     private starPrefab: cc.Prefab = null;
  8.     // 星星产生后消失时间的随机范围
  9.     @property(cc.Integer)
  10.     private maxStarDuration = 0;
  11.     @property(cc.Integer)
  12.     private minStarDuration = 0
  13.     // 地面节点,用于确定星星生成的高度
  14.     @property(cc.Node)
  15.     private groundNode: cc.Node = null;
  16.     // player 节点,用于获取主角弹跳的高度,和控制主角行动开关
  17.     @property(cc.Node)
  18.     public playerNode: cc.Node = null;
  19.     // score label 的引用
  20.     @property(cc.Label)
  21.     private scoreLabel: cc.Label = null;
  22.     // 得分音效资源
  23.     @property(cc.AudioClip)
  24.     private scoreAudio: cc.AudioClip = null;
  25.     // 地面节点的Y轴坐标
  26.     private groundY: number;
  27.     // 定时器
  28.     public timer: number;
  29.     // 星星存在的持续时间
  30.     public starDuration: number;
  31.     // 当前分数
  32.     private score: number;
  33.     protected onLoad() {
  34.         // 获取地平面的 y 轴坐标
  35.         this.groundY = this.groundNode.y + this.groundNode.height / 2;
  36.         // 初始化计时器
  37.         this.timer = 0;
  38.         this.starDuration = 0;
  39.         // 生成一个新的星星
  40.         this.spawnNewStar();
  41.         // 初始化计分
  42.         this.score = 0;
  43.     }
  44.     // 生成一个新的星星
  45.     public spawnNewStar() {
  46.         // 使用给定的模板在场景中生成一个新节点
  47.         let newStar = cc.instantiate(this.starPrefab);
  48.         // 将新增的节点添加到 Canvas 节点下面
  49.         this.node.addChild(newStar);
  50.         // 为星星设置一个随机位置
  51.         newStar.setPosition(this.getNewStarPosition());
  52.         // 将 Game 组件的实例传入星星组件
  53.         newStar.getComponent('Star').init(this);
  54.         // 重置计时器
  55.         this.starDuration = this.minStarDuration + cc.random0To1() * (this.maxStarDuration - this.minStarDuration);
  56.         this.timer = 0;
  57.     }
  58.     // 新星星的位置
  59.     public getNewStarPosition() {
  60.         let randX = 0;
  61.         // 根据地平面位置和主角跳跃高度,随机得到一个星星的 y 坐标
  62.         let randY = this.groundY + cc.random0To1() * this.playerNode.getComponent('Player').jumpHeight + 50;
  63.         // 根据屏幕宽度,随机得到一个星星 x 坐标
  64.         let maxX = this.node.width / 2;
  65.         randX = cc.randomMinus1To1() * maxX;
  66.         // 返回星星坐标
  67.         return cc.p(randX, randY);
  68.     }
  69.     // called every frame
  70.     protected update(dt: number) {
  71.         // 每帧更新计时器,超过限度还没有生成新的星星
  72.         // 就会调用游戏失败逻辑
  73.         if (this.timer > this.starDuration) {
  74.             this.gameOver();
  75.             return;
  76.         }
  77.         this.timer += dt;
  78.     }
  79.     // 得分
  80.     public gainScore() {
  81.         this.score += 1;
  82.         // 更新 scoreDisplay Label 的文字
  83.         this.scoreLabel.string = 'Score: ' + this.score.toString();
  84.         // 播放得分音效
  85.         // 不加as any就会报错,不信你试试
  86.         cc.audioEngine.play(this.scoreAudio as any, false, 1);
  87.     }
  88.     // gg
  89.     private gameOver() {
  90.         this.playerNode.stopAllActions(); //停止 player 节点的跳跃动作
  91.         cc.director.loadScene('game');
  92.     }
  93. }
复制代码
Player.ts
  1. const { ccclass, property } = cc._decorator;
  2. @ccclass
  3. export class Player extends cc.Component {
  4.     // 主角跳跃高度
  5.     @property(cc.Integer)
  6.     private jumpHeight: number = 0;
  7.     // 主角跳跃持续时间
  8.     @property(cc.Integer)
  9.     private jumpDuration: number = 0;
  10.     // 最大移动速度
  11.     @property(cc.Integer)
  12.     private maxMoveSpeed: number = 0;
  13.     // 加速度
  14.     @property(cc.Integer)
  15.     private accel: number = 0;
  16.     // 跳跃音效资源
  17.     @property(cc.AudioClip)
  18.     private jumpAudio: cc.AudioClip = null;
  19.     private xSpeed: number = 0;
  20.     private accLeft: boolean = false;
  21.     private accRight: boolean = false;
  22.     private jumpAction: cc.Action = null;
  23.     private setJumpAction() {
  24.         // 跳跃上升
  25.         let jumpUp = cc.moveBy(this.jumpDuration, cc.p(0, this.jumpHeight)).easing(cc.easeCubicActionOut());
  26.         // 下落
  27.         let jumpDown = cc.moveBy(this.jumpDuration, cc.p(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());
  28.         // 添加一个回调函数,用于在动作结束时调用我们定义的其他方法
  29.         let callback = cc.callFunc(this.playJumpSound, this);
  30.         // 不断重复,而且每次完成落地动作后调用回调来播放声音
  31.         return cc.repeatForever(cc.sequence(jumpUp, jumpDown, callback));
  32.     }
  33.     private playJumpSound() {
  34.         // 调用声音引擎播放声音
  35.         cc.audioEngine.play(this.jumpAudio as any, false, 1);
  36.     }
  37.     private addEventListeners() {
  38.         cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
  39.         cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
  40.         cc.find("Canvas").on(cc.Node.EventType.TOUCH_START, this.onScreenTouchStart,this);
  41.         cc.find("Canvas").on(cc.Node.EventType.TOUCH_CANCEL, this.onScreenTouchEnd, this);
  42.         cc.find("Canvas").on(cc.Node.EventType.TOUCH_END, this.onScreenTouchEnd,this);
  43.     }
  44.     private moveLeft() {
  45.         this.accLeft = true;
  46.         this.accRight = false;
  47.     }
  48.     private moveRight() {
  49.         this.accLeft = false;
  50.         this.accRight = true;
  51.     }
  52.     private stopMove() {
  53.         this.accLeft = false;
  54.         this.accRight = false;
  55.     }
  56.     private onScreenTouchStart(event: cc.Event.EventTouch) {
  57.         if (event.getLocationX() > cc.winSize.width/2) {
  58.             this.moveRight();
  59.         } else {
  60.             this.moveLeft();
  61.         }
  62.     }
  63.     private onScreenTouchEnd() {
  64.         this.stopMove();
  65.     }
  66.     private onKeyDown(event: cc.Event.EventKeyboard) {
  67.         switch ((event as any).keyCode) {
  68.             case cc.KEY.a:
  69.             case cc.KEY.left:
  70.                 this.moveLeft();
  71.                 break;
  72.             case cc.KEY.d:
  73.             case cc.KEY.right:
  74.                 this.moveRight();
  75.                 break;
  76.         }
  77.     }
  78.     private onKeyUp(event: cc.Event.EventKeyboard) {
  79.         switch ((event as any).keyCode) {
  80.             case cc.KEY.a:
  81.             case cc.KEY.left:
  82.                 this.stopMove();
  83.                 break;
  84.             case cc.KEY.d:
  85.             case cc.KEY.right:
  86.                 this.stopMove();
  87.                 break;
  88.         }
  89.     }
  90.     // use this for initialization
  91.     protected onLoad() {
  92.         // 初始化跳跃动作
  93.         this.jumpAction = this.setJumpAction();
  94.         this.node.runAction(this.jumpAction);
  95.         // 加速度方向开关
  96.         this.accLeft = false;
  97.         this.accRight = false;
  98.         // 主角当前水平方向速度
  99.         this.xSpeed = 0;
  100.         // 初始化输入监听
  101.         this.addEventListeners();
  102.     }
  103.     // called every frame
  104.     protected update(dt: number) {
  105.         // 根据当前加速度方向每帧更新速度
  106.         if (this.accLeft) {
  107.             this.xSpeed -= this.accel * dt;
  108.         } else if (this.accRight) {
  109.             this.xSpeed += this.accel * dt;
  110.         }
  111.         // 限制主角的速度不能超过最大值
  112.         if (Math.abs(this.xSpeed) > this.maxMoveSpeed) {
  113.             // if speed reach limit, use max speed with current direction
  114.             this.xSpeed = this.maxMoveSpeed * this.xSpeed / Math.abs(this.xSpeed);
  115.         }
  116.         // 根据当前速度更新主角的位置
  117.         this.node.x += this.xSpeed * dt;
  118.         if (this.node.x <= -this.node.parent.width / 2) {
  119.             this.node.x = this.node.parent.width / 2;
  120.         }
  121.         if (this.node.x > this.node.parent.width / 2) {
  122.             this.node.x = -this.node.parent.width / 2;
  123.         }
  124.     }
  125. }
复制代码
Star.ts
  1. import { Game } from "./Game";
  2. const {ccclass,property} = cc._decorator;
  3. @ccclass
  4. export class Star extends cc.Component {
  5.     // 星星和主角之间的距离小雨这个数值时,就会完成收集
  6.     @property(cc.Integer)
  7.     private pickRadius: number = 0;
  8.     private game: Game = null;
  9.     public init(game:Game) {
  10.         this.game = game;
  11.     }
  12.     getPlayerDistance() {
  13.         // 根据 player 节点位置判断距离
  14.         let playerPos = this.game.playerNode.getPosition();
  15.         // 根据两点位置计算两点之间距离
  16.         let dist = cc.pDistance(this.node.position, playerPos);
  17.         return dist;
  18.     }
  19.     onPicked() {
  20.         // 当星星被收集时,调用 Game 脚本中的接口,生成一个新的星星
  21.         this.game.spawnNewStar();
  22.         // 调用 Game 脚本的得分方法
  23.         this.game.gainScore();
  24.         // 然后销毁当前星星节点
  25.         this.node.destroy();
  26.     }
  27.     // called every frame
  28.     update(dt:number) {
  29.         // 每帧判断和主角之间的距离是否小于收集距离
  30.         if (this.getPlayerDistance() < this.pickRadius) {
  31.             // 调用收集行为
  32.             this.onPicked();
  33.             return;
  34.         }
  35.         // 根据 Game 脚本中的计时器更新星星的透明度
  36.         let opacityRatio = 1 - this.game.timer/this.game.starDuration;
  37.         let minOpacity = 50;
  38.         this.node.opacity = minOpacity + Math.floor(opacityRatio * (255 - minOpacity));
  39.     }
  40. }
复制代码
以上就是CocosCreator入门教程之用TS制作第一个游戏的具体内容,更多关于CocosCreator TS制作游戏的资料请关注草根技术分享别的相干文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作