zoukankan      html  css  js  c++  java
  • 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”,虽然它垃圾,但有重载场景的按钮啊。

    以上。

  • 相关阅读:
    0508---字符串练习题
    0506--习题
    0503---练习题 punctuation isdigit() strip() upper()
    0505---练习题
    0504---习题str.swapcase() str. capitalize() str.title()
    0429---每日习题 菲薄纳西数列 正则ip匹配
    习题之---文件操作
    NOIP 模拟 $13; ext{工业题}$
    NOIP 模拟 $12; ext{简单的填数}$
    NOIP 模拟 $12; ext{简单的玄学}$
  • 原文地址:https://www.cnblogs.com/ForrestCui94/p/12772791.html
Copyright © 2011-2022 走看看