zoukankan      html  css  js  c++  java
  • CocosCreator入门之《摘星星》-完全学习记录(三)

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

    星星模块涉及内容:

    • 使用对象池
    • 使用进度条
    • 文字的简单显/隐/变

    完成态预览:

    写在前面: 原来的坐标随机逻辑,测试100次还是10万次,前后两颗星星近乎重叠的概率都是10%,也就是每得十分、就有一次莫名其妙吃了一颗甚至几颗星星的负体验。

    为突出目标,仅附上在完成主角模块(点击开始,主角能跳、动,屏幕有边界)基础上的新增内容,并不能直接运行

      1 // Game.js
        const Player = require('Player'); 2 3 cc.Class({ 4 extends: cc.Component, 5 6 properties: { 7 minStarDuration: 0, 8 maxStarDuration: 0, 9 starPrefab: { 10 default: null, 11 type: cc.Prefab 12 }, 13 progressBarOfStar: { 14 default: null, 15 type: cc.ProgressBar 16 }, 17 scoreAudio: { 18 default: null, 19 type: cc.AudioClip 20 }, 21 nameAndScore: cc.Label, 22 instructionGoal: cc.Label, 23 controlHint: cc.Label, 24 isMobile: { 25 default: '', 26 multiline: true 27 }, 28 isPC: { 29 default: '', 30 multiline: true 31 }, 32 }, 33 34 onLoad () { 35 this.enabled = false; 36 this.controlHint.string = cc.sys.isMobile ? this.isMobile : this.isPC; 37 // 保存当前星星,失败时放不到对象池,手动销毁 38 this.currentStar = null; 39 // 保存当前星星X坐标与下个X坐标作比较,防止前后两颗星星距离过近造成负体验 40 this.currentStarX = 0; 41 this.starPool = new cc.NodePool('StarPrefab'); 42 this.starDuration = 0; 43 /** 44 * 初始化进度值,1.0为从满倒带,0.0为从空到满 45 * progress(进度值)只能是0-1之间的浮点数 46 * 组件默认progress就是1,不设置也可,但误触了属性检查器的progress会出错 47 */ 48 this.progressBarOfStar.progress = 1.0; 49 }, 50 51 start() { 52 this.score = 0; 53 this.starTimer = 0; 54 }, 55 56 onStartBtnClicked() { 57 this.nameAndScore.string = 'Score: 0'; 58 // 隐藏(active)是node下面的属性,这里声明Label就要调其下的node 59 this.instructionGoal.node.active = false; 60 this.controlHint.node.active = false; 61 this.score = 0; 62 this.spawnNewStar(); 63 }, 64 65 spawnNewStar() { 66 let newStar = this.starPool.get(); 67 68 if (!newStar) { 69 newStar = cc.instantiate(this.starPrefab); 70 } 71 72 this.node.addChild(newStar); 73 newStar.setPosition(this.randStarPosition()); 74 // 初始化必须在加入主节点之后,先有节点再初始化它 75 newStar.getComponent('StarPrefab').init(this); 76 this.setStarLife(); 77 this.currentStar = newStar; 78 this.progressBarOfStar.progress = 1.0; 79 }, 80 81 /** 82 * @param {cc.Prefab} star star节点 83 */ 84 despawnStar(star) { 85 this.starPool.put(star); 86 this.spawnNewStar(); 87 }, 88 89 /** 90 * @returns {cc.Vec2} 随机坐标 91 */ 92 randStarPosition() { 93 let randX = 0; 94 // 子节点最大、最小坐标绝对值是父节点宽度的一半 95 let absMaxX = this.node.width / 2; 96 97 // 新X坐标与旧X坐标至少间隔2颗星星的宽度,否则继续随机 98 do { 99 randX = (Math.random() - 0.5) * 2 * absMaxX; 100 } while (Math.abs(randX - this.currentStarX) < 120) 101 102 // 收集半径是60,不加配数可能星星一半穿帮地面,加太多可能碰不到星星,故加50 103 let randY = this.groundY + Math.random() * this.player.getComponent('Player').jumpHeight + 50; 104 this.currentStarX = randX; 105 106 return cc.v2(randX, randY); 107 }, 108 109 setStarLife() { 110 this.starTimer = 0; 111 this.starDuration = this.minStarDuration + Math.random() * (this.maxStarDuration - this.minStarDuration); 112 }, 113 114 getStarRatio() { 115 return 1 - this.starTimer / this.starDuration; 116 }, 117 118 gainScore() { 119 this.score += 1; 120 this.nameAndScore.string = 'Score: ' + this.score; 121 cc.audioEngine.playEffect(this.scoreAudio, false); 122 }, 123 124 _updateProgressBar() { 125 this.progressBarOfStar.progress = this.getStarRatio(); 126 }, 127 128 update(dt) { 129 this._updateProgressBar(); 130 131 if (this.starTimer > this.starDuration) { 132 this.gameOver(); 133 return; 134 } 135 136 this.starTimer += dt; 137 }, 138 139 gameOver() { 140 this.enabled = false; 141 this.btnNode.x = 0; 142 this.controlHint.node.active = true; 143 this.instructionGoal.node.active = true; 144 this.currentStar.destroy(); 145 this.player.stopMove(); 146 this.saySomeThing(); 147 }, 148 149 saySomeThing() { 150 let score = this.score; 151 let string = this.instructionGoal.string; 152 153 if (score <= 10) { 154 string = 'Are you kidding me?'; 155 } else if (score > 10 && score <= 30) { 156 string = 'Good job, One more try!'; 157 } else if (score > 30) { 158 string = 'Great job!' 159 } 160 161 this.instructionGoal.string = string; 162 } 163 });
     1 // StarPrefab.js
     2 
     3 cc.Class({
     4   extends: cc.Component,
     5 
     6   properties: {
     7     pickRadius: 0,
     8   },
     9 
    10   init(game) {
    11     this.enabled = true;
    12     this.game = game;
    13     this.node.opacity = 255;
    14   },
    15 
    16   onLoad() {
    17     // onLoad是节点初始化时调用,对象池是对象复用,故只在第一颗星星调用。
    18     // cc.log('Star_onLoad()');
    19     this.enabled = false;
    20   },
    21 
    22   getStarPosition() {
    23     return this.node.position;
    24   },
    25 
    26   getPlayerDistance() {
    27     let Player = this.game.player;
    28     let playerPosition = Player.getCenterPos();
    29     let starPosition = this.getStarPosition();
    30 
    31     return starPosition.sub(playerPosition).mag();
    32   },
    33 
    34   onPicked() {
    35     let Game = this.game;
    36     Game.gainScore();
    37     Game.despawnStar(this.node);
    38   },
    39 
    40   update(dt) {
    41     if (this.getPlayerDistance() < this.pickRadius) {
    42       this.onPicked();
    43       // 此情况就是单纯的将控制权转交给主调函数继续执行
    44       return;
    45     }
    46 
    47     let opacityRatio = this.game.getStarRatio();
    48     let minOpacity = 50;
    49     this.node.opacity = minOpacity + (255 - minOpacity) * opacityRatio;
    50   }
    51 });

    这次没什么插曲,除了拼写错误引发的Bug。但还是想说:

    1. 对象池概念初探——https://forum.cocos.org/t/cocoscreator/67879

    2. 进度条组件上手——新建一个示例项目,搜progressBar。

    复刻这两个练习项目,直到不觉得盲人摸象。

  • 相关阅读:
    说说Java中的代理模式
    一个奇怪的异常
    JDBC第二次学习
    浅谈事务
    JDBC第一次学习
    Firebug & Chrome Console 控制台使用指南
    js 事件创建发布
    vue ui之 iview 事件拦截
    fetch获取json的正确姿势
    js对象通过属性路径获取属性值
  • 原文地址:https://www.cnblogs.com/ForrestCui94/p/12779690.html
Copyright © 2011-2022 走看看