CocosCreator微信小游戏入门实战《小猫钓鱼》(六):单例模式以及UI

分类栏目:cocos教程

240

经过上一节的碰撞系统,我们已经基本完成一个微信小游戏核心玩法部分的开发工作。接下来我们需要开发另一块重要的东西:UI

 

CocosCreator为我们提供了很多已封装好的UI组件,这些组件基本上可以满足我们正常的开发需求。当然针对一些项目中的特殊需求,我们也可以通过定制制作符合需求的自定义UI。针对目前我们这个小游戏来讲,Cocos本身提供的UI已经是绰绰有余了。

关于UI控件的使用,参考官方文档:

http://docs.cocos.com/creator/manual/zh/ui/ui-components.html

 

在第一节中,我们在Camera下面创建了一个widget节点作为HUD界面的父节点。这个HUD界面始终会在Camera的范围内,因此我们不用担心Camera的移动会导致我们的一些UI处于范围外而无法正常显示。

 

使用Widget,Sprite,Label,Button这些控件,我们可以很快速的在剪辑器中拼凑出下面的UI界面:

 

接下来我们先实现开始游戏按钮的功能。

关于Button控件的使用,参考官方文档:

http://docs.cocos.com/creator/manual/zh/components/button.html

 

由于我们的资源只有1张图片,并没有做按钮按下状态的资源。因此button的按钮按下状态过渡类型我们选择Scale。

在这个选项下,按钮按下时,按钮会进行缩放。缩放值以及切换时间可以通过Duration和ZoomScale去设定。

 

现在我们先看下开始游戏按钮按下后我们需要实现什么功能:

  1. 鱼钩开始下沉
  2. MainUI消失不显示,也就是隐藏开始游戏按钮,游戏logo,排行榜按钮。

 

之前我们处于便于调试的原因,让游戏一运行就自动开始,现在我们需要把开始的功能放在按钮的点击事件中。

首先在之前的Hook.js脚本的start方法中,把调试用的鱼钩开始运动的代码去掉。

 

在开始游戏按钮的属性检查器中,将ClickEvents设置为2。

点击事件有四个参数,1为点击事件的接收者节点,这个节点必须带有脚本,2为脚本组件的名称,3为指定的回调方法,4CustonEventData为回调方法的传入参数(可不填)

 

在层级管理器中,使用鼠标将Hook节点拖到ClickEvents,选择脚本Hook,回调方法为StartLine

这样在点击后就可以触发回调,调用鱼钩的StartLine方法,使鱼钩开始下沉

 

在第二个Event里,我们处理MainUi的不显示功能。先给MainUI挂载一个新的脚本MainUI.js。

脚本中我们实现一个叫Hide的方法,控制使MainUI不激活。


  1.     Hide () {
  2.         this.node.active = false;
  3.     },

然后再第二个ClickEvent中,接收节点选择MainUI,选择脚本MainUI.js,回调方法为Hide

 

OK,这样就实现了开始按钮的功能了。

排行榜按钮也是类似,至于微信排行榜的制作,我们放在后面来讲述。

 

这样主界面就OK了。

 

 

 

下一步我们要开始实现深度Label和得分Label的功能了。

这个功能很简单,只需要根据游戏进程,更换Label中显示的文字即可。更换显示字符,可以通过给label的string属性进行赋值即可完成。

 

不过有个问题我们需要重视一下:

虽然我们可以在鱼钩与鱼发生碰撞时,计算并增加得分,同时改变得分label的显示内容,这很简单。

但是假如我们的需求没这么简单,例如到达一定分数我们要更换label字体的颜色,特点分数我们让得分数字跳一下等等。

当在这种复杂的需求下,如果在碰撞回调方法中实现这些功能后。你会发现,功能没问题,可是:

UI与鱼钩的关系变得非常的紧密,也就是耦合性非常强,有些时候简单的UI改动会变得复杂,不经意间,你可能还会破坏原有正常的鱼钩代码。而且按照正常逻辑来看,UI的显示应该只与UI以及数据有关,但是控制UI的代码却是放在鱼钩的脚本里面,与常理不合。

 

为了预防这种的情况的发生,我们引入一个跨脚本的全局数据用来记录。玩法逻辑仅仅只会改变数据的值,而UI也只需要从数据获取值并且显示即可。

这其实也就是设计模式的一个粗浅应用,但在实际项目中带来的好处可不小。

 

 

用来作为跨脚本的数据载体实现有很多,在现在这个微信小游戏中,我们就任性一点,使用单例来作为跨脚本的数据记录载体。

 

下面我们来先写一个单例的脚本

GameData.js

var GameData = cc.Class({
 
    extends: cc.Component,
 
    statics: {
 
        instance : null
 
    },
 
    properties: {
 
        score : 0,//得分
 
        depth : 0//深度
 
    },
 
});
 
 
 
GameData.instance = new GameData();
 
 
 
module.exports = GameData;

使用时也很简单,在需要使用的脚本中require后,就可以通过GameData.instance获取到单例进行数据的读写。

 

例如HUD的脚本,HUD.js

var GameData = require("GameData");
 
 
 
cc.Class({
 
    extends: cc.Component,
 
 
 
    properties: {
 
        mScoreLabel : cc.Label,
 
        mDepthLabel : cc.Label
 
    },
 
 
 
    start () {
 
 
 
    },
 
 
 
    update (dt) {
 
        this.mScoreLabel.string = GameData.instance.score;
 
        this.mDepthLabel.string = "深度:" + GameData.instance.depth.toFixed(2);
 
    },
 
});


具体关于得分以及深度的数据读写我就不一一贴出来了,都比较简单,相信大家都能够实现出以下的效果:

      

 

OK,如法炮制,结束界面也可以很快就能够做好。需要注意的一点是,在玩家点击“再玩一局”时,需要重置一下场景数据,你可以在Scene.js中写一个reset方法,用于点击时调用。

reset () {
 
        GameData.instance.depth = 0;
 
        GameData.instance.score = 0;
 
        //清除鱼钩上挂着的鱼
 
        this.mFishPool.removeAllChildren(true);
 
        //清除海里面的所有鱼
 
        this.mController.removeAllChildren(true);
 
    },

最终效果如下: