egret制作猜拳游戏

fingerGuessing


项目介绍

fingerGuessing:一款有趣的猜拳游戏,基于egret白鹭游戏引擎开发(ps:游戏中试玩榜后台数据均为随机虚假)。

演示视频

演示视频地址

部分截图

image.png

项目功能结构

猜拳游戏.png

项目运行


$ egret build xxx(项目名)

$ egret startserver xxx(项目名) -a

项目搭建教程

该项目主要分为4个页面

1. 开始页面

创建bitmap对象,做背景图和位图的绘制,涉及到2个按钮(开始游戏按钮、试玩榜按钮)的事件监听(touch_begin、touch_end、touch_release_outside)。

startBtn涉及dispatchEvent,下面篇幅会有详解

2.游戏页面

  • 背景和相关位图绘制
    • 出拳tween动画处理 + random出拳
    • 根据所剩时间,动态调整出拳动画频率
  • timerPanel.ts 用于控制游戏倒计时
    • 倒计时栏目UI绘制
    • listen TimerEvent中的timer和timer——complete,做倒计时数字的update
    • 将default_time存入localStorage中,用于game页面使用
  • 猜况按钮逻辑处理
    • 根据出拳情况,用户判断那边赢(左边赢、打平、右边赢)
    • 为了精简代码,抽象一个commonCallback,用于left、middle和right使用

3.结束页面

  • 位图绘制
    • 抽象出commonImgConf函数,来绘制多个按钮
  • 按钮事件派发、处理
    • 抽出commonCallback,分别控制3个gameEvent

4.试玩榜页面

  • 返回按钮事件派发
  • 文本绘制
  • 抽出commonTxt用于控制多段文本绘制
    private commonTxt(size: number, isCenter: boolean, isAssignment: boolean ,y: number, x?: number) {
        const txt = new egret.TextField();
        txt.width = egret.MainContext.instance.stage.stageWidth;
        this.addChild(txt);
        txt.y = y;
        if (x) txt.x = x;
        txt.textAlign = isCenter == true ? egret.HorizontalAlign.CENTER : egret.HorizontalAlign.LEFT;
        txt.size = size;
        txt.textColor = 0xffffff;
        isAssignment ? this.txt = txt : txt.text = "试玩榜";
    }
  • 请求发送和请求解析
    • onComplete() + onGetComplete()
    private onComplete(): void {
        const url: string = "xxxx";
        const loader: egret.URLLoader = new egret.URLLoader();

        loader.dataFormat = egret.URLLoaderDataFormat.TEXT;
        loader.addEventListener(egret.Event.COMPLETE, this.onGetComplete, this);

        const request: egret.URLRequest = new egret.URLRequest(url);
        request.method = egret.URLRequestMethod.GET;
        loader.load(request);
    }
    private onGetComplete(event: egret.Event):void {
        const loader:egret.URLLoader = <egret.URLLoader> event.target;
        let data:egret.URLVariables = loader.data;
        // 采用js解析方法
        let res = eval("("+data.toString()+")");
        ... // TODO: 其他处理
}
  • easy-mock数据格式:
{
  "data": {
    "array|5-9": [{
      "score": "@integer(1,100)",
      "name": "@cname"
    }]
  }
}

3.发布游戏

当整个游戏制作完成后,我们需要将它进行发布,这里只涉及H5方面发布。

一句命令行而已的事:

参数说明:

egret publish [project_name] [--version [version]] [--runtime html5|native] [--passWorld]


$ egret publish xxx(项目名) --version 0.03(版本号)

发布项目,如果是在项目文件夹下编译,可以不加项目名称

打包成功后,会出现一个bin-release的文件夹

image.png

然后把我框出来的1903....这个文件夹里面的东西,拖到服务器上,然后对应访问,就可以啦。

敲黑板划重点

如果说,我们平时在自我测试环节,起一个本地服务,然后手机在同一个网络下访问本机ip地址就可以

这样应该会比较方便,简单介绍一下这个步骤:

简单的http服务

首先安装http-server模块。


$ npm i -g http-server

运行发布完成的包


$ cd bin-release/web/190311152632

$ ls

index.html  js  manifest.json  resource

$ hs -p 8088

Starting up http-server, serving ./

Available on:

 http://127.0.0.1:8088

 http://192.168.1.100:8088

Hit CTRL-C to stop the server

最后一级文件夹名字其实是时间戳。

这样我们便可以在pc浏览器或者手机浏览器中查看游戏了。


项目细究

>=2次使用,或有大部分common的,都抽象出来使用,尽量尝试用新语法来简化代码量

今日给自己灌的鸡汤:代码应该是一日写的比一日优雅才行,一个需求应思考多种写法,再找到最优解

精简繁琐for循环

在判断猜况的时候,需要使用到多重嵌套for循环,看着特别恶心,后面采用了这种方法用于简化:

        const actions = () => {
            const answerFalse = () => { this.answer_type = false };
            const addScore = () => { this.score++; this.answer_type = true };
            return new Map([
                [{ left_type: 0, right_type: 0 }, answerFalse],
                [{ left_type: 0, right_type: 1 }, answerFalse],
                [{ left_type: 0, right_type: 2 }, addScore],
                [{ left_type: 1, right_type: 0 }, addScore],
                [{ left_type: 1, right_type: 1 }, answerFalse],
                [{ left_type: 1, right_type: 2 }, answerFalse],
                [{ left_type: 2, right_type: 0 }, answerFalse],
                [{ left_type: 2, right_type: 1 }, addScore],
                [{ left_type: 2, right_type: 2 }, answerFalse]
            ])
        }
            let action = [...actions()].filter(([key, value]) => (
                key.left_type == this.left_type && key.right_type == this.right_type
            ));
            action.forEach(([key, value]) => value.call(this));

Egret核心显示类

需要重新梳理一下这些类,以便下次写的时候,有点混

描述
DisplObject 显示对象基类,所有显示对象均继承自此类
DisplObjectContainer 显示对象容器接口,所有显示对象容器均实现此接口
Bitmap 位图,用来显示图片
Shape 用来显示矢量图,可以用里面的方法绘制矢量图形
TextField 文本类
BitmapText 位图文本类
Sprite 带有矢量绘制功能的显示容器
Stage 舞台类

这里面的startscene,使用继承sprite,而没用displaObjeContainer,在这里简单列出它们之间的继承关系:
egret.Sprite -> egret.DisplayObjectContainer -> egret.DisplayObject

同时,提一点:shape与sprite的diff:

  • shape:显示对象,一般用于绘制图形
  • sprite:显示容器,在此基础上可以添加子容器 + 显示对象,一般用于create可以装载content的游戏层或者游戏对象

http://blog.sina.com.cn/s/blog_6b80d2ca0102vjx4.html

Egret中事件处理

egret中的事件机制是一套比较标准的事件处理架构。

简单来说,数据的提供者只需要在意发出数据对象,以及确保数据对象是egret.event类或者子类的实例即可,这种数据对象,也就是事件event

我们在游戏中涉及到按钮的一些交互效果,比如:点击开始游戏,进入游戏页面;点击Rank icon,弹出rank的弹框。

以上这些都会涉及倒egret的事件处理,我先简单罗列事件处理的一个基本流程:

  • step1: 注册侦听器listener
  • step2:发送事件
  • step3:侦听事件
  • step4:移除事件侦听器

这里我用startScene中点击开始游戏的事件处理,做一个简单事例:

startscene .ts:

// init fn
private init(){
  ...
  // 注册listener 
  rank_btn.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.rank_btnCallback, this);
  ...
}

// start_btnCallback fn
private start_btnCallback(evt:egret.TouchEvent):void {
  ...
  //  派发事件
  let event:GameEvent = new GameEvent(GameEvent.GAME_GO);
  this.dispatchEvent(event);
  ...
}

main.ts:

private createGameScene() {
  ....   
  //侦听事件
  startScene.addEventListener(GameEvent.GAME_GO, this.go, this);
  startScene.addEventListener(GameEvent.GAME_BLEED, this.startrank, this);
}
private go(){
  // 手动回收侦听器
  this.removeEventListener(GameEvent.GAME_GO, this.go, this);
  this.removeChildren();
  ...
}

注意:这里存在一个问题:

在显示对象容器里的子显示对象上增加了事件侦听器(addEventListener),如果通过父级显示对象的removeChild移除了这个容器,那么有必要在egret.Event.REMOVED_FROM_STAGE事件里手动删除所有子对象注册的事件侦听器吗(removeEventListener)?还是说引擎会自动处理?

答案是:如果没有引用的话就会回收,但是为了保证一定回收最好手动移除,不然可能造成内存泄露

Egret支持ES6

在egret中默认设置是es5,所有很多es6的语法是不支持的,比如map这些...
yiwen那么如何更改配置项,让其支持es6语法呢?

step1:

找到根目录下的tsconfig.json文件,这是默认生成的:

{
    "compilerOptions": {
        "target": "es5",
        "outDir": "bin-debug",
        "experimentalDecorators": true,
        "lib": [
            "es5",
            "dom",
            "es2015.promise"
        ],
        "types": []
    },
    "include": [
        "src",
        "libs"
    ]
}

step2:

  • 将lib下的es5改成es2015,也就是es6
  • 在compilerOptions下加一行"downlevelIteration": true,,用于降级迭代器

更改后是这样:

{
    "compilerOptions": {
        "target": "es5",
        "outDir": "bin-debug",
        "experimentalDecorators": true,
        "downlevelIteration": true,
        "lib": [
            "es2015",
            "dom",
            "es2015.promise"
        ],
        "types":[]
    },
    "exclude": [
        "node_modules"
    ]
}

step 3:

由于配置项更改了,需要重新build和run,再次执行:

> $ egret build xxx
> $ egret startserver xxx -a

之前...由于一些原因,本地的lib和远程github上的lib冲突了,导致项目跑不起来,然而各种...奇怪的方法尝试,最后找到问题,本地解决了,发现...无法把本地的lib推到远程的lib上...然和各种奇怪,反正那啥最后就强制了一把:git push -f ... 唉唉 真是粗暴

项目源码

代码中写了很多注释,基本都能看懂就不再赘述啦~

源码地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 1.纹理集实际上就是将一些零碎的小图放到一张大图当中。游戏中也经常使用到纹理集。使用纹理集的好处很多,我们通过将大...
    别人家的程序员阅读 8,044评论 1 21
  • 启动 draw 1.draw 这里参数描述了当前画面渲染时候drawcall的次数2.cost 包含四个参数 en...
    zhangjingbibibi阅读 788评论 0 0
  • 有可选参数的函数 函数有两个形参,假设第一个必传、第二个可传可不传 有默认参数的函数 有剩余参数的函数 认识类与对...
    隔壁老王z阅读 2,674评论 0 3
  • iceBucketChallenge 项目介绍 iceBucketChallenge:类似打地鼠类的冰桶挑战游戏(...
    zhangjingbibibi阅读 1,358评论 0 0
  • 本文使用白鹭引擎版本是5.2.7 当前时间最新版 (截图时又出现了一版,迭代速度还是很快的) 1. 选择游戏开发模...
    Zszen阅读 14,467评论 0 48