CocosCreator入门之《摘星星》-完全学习记录(二)

完整版:https://quqi.gblhgk.com/s/184718/ykolFXd1LYL9mzQE

我按一个个模块来记录学习过程,比如“主角干什么”“星星干什么”,按大概的分析去完成功能,最后需要新增什么的话再用“添油加醋”的方法也不迟。

作为初学者官方添油加醋式的的教学十分必要,延续这种盲人摸象的编程十分没必要。

本篇是主角模块:

先记录想法:

代码:

  1 // Player.js
  2 
  3 cc.Class({
  4   extends: cc.Component,
  5 
  6   properties: {
  7     jumpDuration: 0,
  8     squashDuration: 0,
  9     jumpHeight: 0,
 10     maxMoveSpeed: 0,
 11     accel: 0,
 12     jumpAudio: {
 13       default: null,
 14       type: cc.AudioClip
 15     }
 16   },
 17 
 18   onLoad() {
 19     // enabled: Boolean, 是否每帧执行该组件的 update 方法
 20     this.enabled = false;
 21     // 算上一半身体以完全不穿帮
 22     this.borderLeft = (-this.node.parent.width / 2) + (this.node.width / 2);
 23     this.borderRight = (this.node.parent.width / 2) - (this.node.width / 2);
 24     this.registerInputControl();
 25   },
 26 
 27   start() {
 28     // 加速度方向开关
 29     this.accLeft = false;
 30     this.accRight = false;
 31     // 移动即X坐标变动 
 32     this.xSpeed = 0;
 33   },
 34 
 35   /**
 36    * @param {cc.Vec2} pos X为0(原点),y为地平面实际高度的起始坐标,由上层脚本传递
 37    */
 38   startMove(pos) {
 39     this.enabled = true;
 40     this.node.setPosition(pos);
 41     this.runJumpAction();
 42   },
 43 
 44   stopMove() {
 45     this.enabled = false;
 46     this.node.stopAllActions();
 47     // 本游戏没有销毁场景操作,重置速度让重新开始的主角静止,否则重新开始的主角带着旧数值自己动。
 48     this.xSpeed = 0;
 49   },
 50 
 51   runJumpAction() {
 52     let t = cc.tween;
 53     // 'position' 把 x 算进去,虽然x是0,主角移动(x变化时)会出问题
 54     let jumpUp = t().by( this.jumpDuration, { y: this.jumpHeight }, { easing: 'cubicOut' });
 55     let jumpDown = t().by( this.jumpDuration, { y: -this.jumpHeight }, { easing: 'cubicIn' });
 56     // scale 是整体缩放(x、y一起缓动),scaleX/scaleY 独立控制
 57     let squash = t().to( this.squashDuration, { scaleX: 1.1, scaleY: 0.8 }, { easing: 'smooth' });
 58     let stretch = t().to( this.squashDuration, { scaleX: 0.9, scaleY: 1.2 }, { easing: 'smooth' });
 59     let squashBack = t().to( this.squashDuration, { scaleX: 1, scaleY: 1 }, { easing: 'smooth' });
 60 
 61     let callAudio = t().call(() => { cc.audioEngine.playEffect(this.jumpAudio, false); });
 62 
 63     return t(this.node).repeatForever(
 64       t().sequence(squash, stretch, jumpUp, squashBack, jumpDown, callAudio)
 65     ).start();
 66   },
 67 
 68   registerInputControl() {
 69     const KEY_EVENT = cc.SystemEvent.EventType;
 70     cc.systemEvent.on(KEY_EVENT.KEY_DOWN, this.onKeyDown, this);
 71     cc.systemEvent.on(KEY_EVENT.KEY_UP, this.onKeyUp, this);
 72 
 73     const TOUCH_EVENT = cc.Node.EventType;
 74     // Warning: event should register on Canvas node! 遗漏 .parent 会出错
 75     this.node.parent.on(TOUCH_EVENT.TOUCH_START, this.onTouch, this);
 76     this.node.parent.on(TOUCH_EVENT.TOUCH_END, this.offTouch, this);
 77   },
 78 
 79   onKeyDown(event) {
 80     this._switchKeycode(event.keyCode, true);
 81   },
 82 
 83   onKeyUp(event) {
 84     this._switchKeycode(event.keyCode, false);
 85   },
 86 
 87   /**
 88    * @param {Enumerator} keyCode 按键的枚举值
 89    * @param {Boolean} condition 条件是按下还是松开
 90    */
 91   _switchKeycode(keyCode, condition) {
 92     const KEY = cc.macro.KEY;
 93 
 94     switch (keyCode) {
 95       case KEY.a:
 96         if (condition === true) {
 97           this.accLeft = true;
 98         } else if (condition === false) {
 99           this.accLeft = false;
100         } else {
101           cc.log('傻屌没传布尔值!');
102         }
103         break;
104       case KEY.d:
105         if (condition === true) {
106           this.accRight = true;
107         } else if (condition === false) {
108           this.accRight = false;
109         } else {
110           cc.log('傻屌没传布尔值!');
111         }
112         break;
113       default:
114         break;
115     }
116   },
117 
118   onTouch(event) {
119     let touchLocation = event.getLocation();
120     // touchLocation是Vec2,忘记.x会出错
121     if (touchLocation.x <= cc.winSize.width / 2) {
122       this.accLeft = true;
123     } else {
124       this.accRight = true;
125     }
126     // es6完成版说这一步是“不要捕捉事件”,还不懂
127     return true;
128   },
129 
130   offTouch(event) {
131     [this.accLeft, this.accRight] = [false, false];
132   },
133 
134   /** 向上层模块传递自身坐标 */
135   getCenterPos() {
136     // 锚点是(0.5, 0),故加高度的一半为中心
137     return cc.v2(this.node.x, this.node.y + this.node.height / 2);
138   },
139 
140   update(dt) {
141     // 速度刷新模块,根据加速度方向
142     if (this.accLeft) {
143       this.xSpeed -= this.accel * dt;
144     } else if (this.accRight) {
145       this.xSpeed += this.accel * dt;
146     }
147 
148     // 限制极速
149     if (Math.abs(this.xSpeed) > this.maxMoveSpeed) {
150       this.xSpeed = this.maxMoveSpeed * this.xSpeed / Math.abs(this.xSpeed);
151     }
152 
153     let nodeX = this.node.x;
154     nodeX += this.xSpeed * dt;
155 
156     // 屏幕限制模块
157     if (nodeX < this.borderLeft) {
158       nodeX = this.borderLeft;
159       /**
160        * 撞墙是强制坐标不动,但速度刷新模块一直在跑
161        * 不清零则反向运动时xSpeed会先减去“根据之前加速开关刷新着的数值”
162        * 表现是撞墙后反向运动时,主角像“吸”在边界一段时间
163        */
164       this.xSpeed = 0;
165     } else if (nodeX > this.borderRight) {
166       nodeX = this.borderRight;
167       this.xSpeed = 0;
168     }
169 
170     this.node.x = nodeX;
171   },
172 });

插曲1:本打算主角运动的同时注册监听,在 startMove(pos)里调 registerInputControl(),是我不理解监听机制,虽没影响游戏运行,控制台报了重复注册监听警告:

插曲2:不理解cc.Tween时,改变主角高度用了“position”:

插曲3:限制屏幕模块如果不归零速度参数:

测试本模块还需要在主脚本里做点事:

代码:

 1 // Game.js
 2 
 3 const Player = require('Player');
 4 
 5 cc.Class({
 6   extends: cc.Component,
 7 
 8   properties: {
 9     // 获取地平面实际高度
10     ground: cc.Node,
11     // 改变按钮节点坐标以显示/隐藏
12     btnNode: cc.Node,
13     // 控制主角行动
14     player: {
15       default: null,
16       type: Player
17     }
18   },
19 
20   onLoad () {
21     this.enabled = false;
22     this.groundY = this.ground.y + this.ground.height / 2;
23   },
24 
25   onStartBtnClicked() {
26     this.enabled = true;
27     this.btnNode.x = 3000;
28     this.player.startMove(cc.v2(0, this.groundY));
29   }
30 });

一切顺利就是酱紫的:

ps: 萌新可能不熟悉节点的属性,所以例如Canvas节点的node一览:

推荐安装辅助调试工具以完成查看以上信息等:

1.论坛大神自制版,会更新,能实时显示节点(比如确认一下吃星星后旧的星星预制和特效预制是不是没了,如果取出逻辑写错,它们很可能挂在主节点上,成百上千...)

https://forum.cocos.org/t/ccc-devtools/91496

2.官方弃婴版(最近一次更新在N年前) ,谷歌商店搜 "Cocos Creator Devtool”,虽然它垃圾,但有重载场景的按钮啊。

以上。

原文地址:https://www.cnblogs.com/ForrestCui94/p/12772791.html