You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
13 KiB
376 lines
13 KiB
4 years ago
|
# 鸟妈妈回家
|
||
|
|
||
|
# 运行步骤
|
||
|
1. git clone https://dd.tall.wiki/gitea/ccsens_fe/bird-go-home.git
|
||
|
2. 全局安装gulp npm i gulp -g
|
||
|
3. npm i 或者 yarn
|
||
|
4. 运行gulp
|
||
|
5. 运行vscode的Go Live
|
||
|
6. 部署服务器 dist目录
|
||
|
|
||
|
|
||
|
|
||
|
## 游戏介绍
|
||
|
|
||
|
“鸟妈妈回家”游戏用于 康复训练,上肢训练
|
||
|
|
||
|
游戏使用Adobe Animate制作,游戏包含如下几个模块:
|
||
|
|
||
|
+ 主体:鸟、背景(山、云朵、树木等)、成功次数(也能代表得分)
|
||
|
+ 开始倒计时:开始面板、倒计时文本
|
||
|
+ 返回按钮
|
||
|
+ 难度级别
|
||
|
+ 游戏计时
|
||
|
+ 结束modal:界面面板、得分文本
|
||
|
+ 测试模块
|
||
|
|
||
|
|
||
|
|
||
|
该游戏源文件,使用旧版的flash软件制作,转换成animate支持的canvas模式。
|
||
|
|
||
|
游戏原有动画均在图层中制作。包括游戏动作成功的字数,也在动画中制作。游戏动作设计调整难度较大,次数修改成本较高。目前是固定的20次,一般情况是够用。
|
||
|
|
||
|
|
||
|
|
||
|
## 目录结构说明
|
||
|
|
||
|
通过如下命令输出的目录结构:
|
||
|
|
||
|
```bash
|
||
|
tree -I "node_modules|package-lock.json|yarn.lock"
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
```bash
|
||
|
│ .gitignore
|
||
|
│ .prettierrc
|
||
|
│ .svrxrc.js
|
||
|
│ dist.zip
|
||
|
│ gulpfile.js
|
||
|
│ package-lock.json
|
||
|
│ package.json
|
||
|
│ README.md
|
||
|
│
|
||
|
├─dist
|
||
|
│ │ bird.js
|
||
|
│ │ index.html
|
||
|
│ │ main.js
|
||
|
│ │
|
||
|
│ ├─images
|
||
|
│ │ Bitmap1.png
|
||
|
│ │ Bitmap2.png
|
||
|
│ │ Bitmap3.png
|
||
|
│ │ Bitmap4.png
|
||
|
│ │ Bitmap5.png
|
||
|
│ │ level.png
|
||
|
│ │ stopDemo.png
|
||
|
│ │ suspend.png
|
||
|
│ │ _preloader.gif
|
||
|
│ │ 任务完成_.png
|
||
|
│ │ 倒计时_.png
|
||
|
│ │ 再来一次_.png
|
||
|
│ │ 树林前景_.png
|
||
|
│ │ 计时_.png
|
||
|
│ │ 返回按钮_.png
|
||
|
│ │
|
||
|
│ ├─libs
|
||
|
│ │ └─1.0.0
|
||
|
│ │ createjs.min.js
|
||
|
│ │
|
||
|
│ └─sounds
|
||
|
│ amazing.mp3
|
||
|
│ bgmMusic.mp3
|
||
|
│ excitationMusic.mp3
|
||
|
│ unbelievable.mp3
|
||
|
│
|
||
|
├─public
|
||
|
│ │ bird.html
|
||
|
│ │ bird.js
|
||
|
│ │ index.html
|
||
|
│ │ 鸟妈妈回家_HTML5 Canvas.fla
|
||
|
│ │
|
||
|
│ ├─images
|
||
|
│ │ Bitmap1.png
|
||
|
│ │ Bitmap2.png
|
||
|
│ │ Bitmap3.png
|
||
|
│ │ Bitmap4.png
|
||
|
│ │ Bitmap5.png
|
||
|
│ │ level.png
|
||
|
│ │ stopDemo.png
|
||
|
│ │ suspend.png
|
||
|
│ │ _preloader.gif
|
||
|
│ │ 任务完成_.png
|
||
|
│ │ 倒计时_.png
|
||
|
│ │ 再来一次_.png
|
||
|
│ │ 树林前景_.png
|
||
|
│ │ 计时_.png
|
||
|
│ │ 返回按钮_.png
|
||
|
│ │
|
||
|
│ ├─libs
|
||
|
│ │ └─1.0.0
|
||
|
│ │ createjs.min.js
|
||
|
│ │
|
||
|
│ └─sounds
|
||
|
│ amazing.mp3
|
||
|
│ bgmMusic.mp3
|
||
|
│ excitationMusic.mp3
|
||
|
│ unbelievable.mp3
|
||
|
│
|
||
|
└─src
|
||
|
│ custom.js
|
||
|
│ index.js
|
||
|
│ test.js
|
||
|
│
|
||
|
└─classes
|
||
|
again.js
|
||
|
back.js
|
||
|
count.js
|
||
|
demo.js
|
||
|
end.js
|
||
|
level.js
|
||
|
main.js
|
||
|
sound.js
|
||
|
suspend.js
|
||
|
time.js
|
||
|
```
|
||
|
|
||
|
| 文件 | 说明 | 备注 |
|
||
|
| ------------------- | ------------------------------------------------------------ | ----------------------------------------------- |
|
||
|
| bird.html | animate自动生成的html,不编辑使用index.html代替 | |
|
||
|
| bird.js | animate自动生成,index.html有引用 | |
|
||
|
| images/* | animate生成的图片资源 | 这里没有使用雪碧图,这个文件fla导出雪碧图就卡死 |
|
||
|
| index.html | 入口界面 | |
|
||
|
| js/custom.js | 自定义初始化整合js | **可作为模板复制修改**,config及initStage |
|
||
|
| js/index.js | animate生成的内嵌到bird.html中的js提取,并添加了初始化入口函数initStage | |
|
||
|
| js/test.js | 测试程序,正式版可删除 | |
|
||
|
| js/classes/* | 封装的各个模块类 | |
|
||
|
| js/classes/back.js | 返回按钮类封装 | **通用** |
|
||
|
| js/classes/bird.js | 游戏主体类封装 | 不通用 |
|
||
|
| js/classes/count.js | 开始时倒计时组件类封装 | **通用**,配合custom里的配置使用 |
|
||
|
| js/classes/end.js | 游戏结束,得分面板 | **通用**,配合custom里的config总分,总次数使用 |
|
||
|
| js/classes/level.js | 游戏级别组件封装类 | **通用**,配合custom里的config里的level使用 |
|
||
|
| js/classes/sound.js | 游戏音频封装类 | **通用**,资源可能需要替换 |
|
||
|
| js/classes/time.js | 游戏时长、计时组件封装类 | **通用**,配合custom里的config里的time使用 |
|
||
|
| libs/* | animate导出的createjs文件 | 不用动 |
|
||
|
| sounds/*.mp3 | 音频资源 | |
|
||
|
| *.fla | animate源文件 | |
|
||
|
|
||
|
|
||
|
|
||
|
## 具体代码说明
|
||
|
|
||
|
### index.html
|
||
|
|
||
|
入口界面,依据animate生成的 bird.html 修改而来。主要添加了测试功能区,以及js文件的整合引入。其他不动
|
||
|
|
||
|
```js
|
||
|
<script src="libs/1.0.0/createjs.min.js"></script>
|
||
|
<script src="bird.js"></script>
|
||
|
<script src="main.js"></script>
|
||
|
<!-- write your code here -->
|
||
|
</head>
|
||
|
<body onload="init();" style="margin: 0px;">
|
||
|
<div id="animation_container" style="background-color:rgba(255, 255, 255, 1.00); width:1280px; height:720px">
|
||
|
<canvas id="canvas" width="1280" height="720" style="position: absolute; display: none; background-color:rgba(255, 255, 255, 1.00);"></canvas>
|
||
|
<div id="dom_overlay_container" style="pointer-events:none; overflow:hidden; width:1280px; height:720px; position: absolute; left: 0px; top: 0px; display: none;">
|
||
|
</div>
|
||
|
</div>
|
||
|
<div id='_preload_div_' style='position:absolute; top:0; left:0; display: inline-block; height:720px; width: 1280px; text-align: center;'> <span style='display: inline-block; height: 100%; vertical-align: middle;'></span> <img src=images/_preloader.gif style='vertical-align: middle; max-height: 100%'/></div>
|
||
|
</body>
|
||
|
```
|
||
|
|
||
|
### index.js
|
||
|
|
||
|
将原bird.html中的内嵌js部分抽离,并添加initStage调用,如下:
|
||
|
|
||
|
```js
|
||
|
function handleComplete(evt, comp) {
|
||
|
//This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
|
||
|
var lib = comp.getLibrary();
|
||
|
var ss = comp.getSpriteSheet();
|
||
|
var queue = evt.target;
|
||
|
var ssMetadata = lib.ssMetadata;
|
||
|
// for循环 i=0; 前面需要加 let, 否则编译会报错
|
||
|
for (i = 0; i < ssMetadata.length; i++) {
|
||
|
ss[ssMetadata[i].name] = new createjs.SpriteSheet({ images: [queue.getResult(ssMetadata[i].name)], frames: ssMetadata[i].frames });
|
||
|
}
|
||
|
var preloaderDiv = document.getElementById('_preload_div_');
|
||
|
preloaderDiv.style.display = 'none';
|
||
|
canvas.style.display = 'block';
|
||
|
exportRoot = new lib.鸟妈妈回家_HTML5Canvas();
|
||
|
stage = new lib.Stage(canvas);
|
||
|
//Registers the "tick" event listener.
|
||
|
fnStartAnimation = function () {
|
||
|
stage.addChild(exportRoot);
|
||
|
|
||
|
initStage(lib);
|
||
|
|
||
|
createjs.Ticker.framerate = lib.properties.fps;
|
||
|
createjs.Ticker.addEventListener('tick', stage);
|
||
|
};
|
||
|
//Code to support hidpi screens and responsive scaling.
|
||
|
AdobeAn.makeResponsive(true, 'both', true, 1, [canvas, preloaderDiv, anim_container, dom_overlay_container]);
|
||
|
AdobeAn.compositionLoaded(lib.properties.id);
|
||
|
fnStartAnimation();
|
||
|
}
|
||
|
|
||
|
```
|
||
|
|
||
|
### custom.js
|
||
|
|
||
|
配置,全局变量 及initStage整个调用各个类,注意类的调用有先后顺序之分。图层顺序在上的后调用
|
||
|
|
||
|
```js
|
||
|
const config = {
|
||
|
count: 5, // 默认倒计时时长
|
||
|
duration: 60, // 总时长 s
|
||
|
level: 1, // 游戏难度级别
|
||
|
total: 100, // 总分
|
||
|
times: 20, // 动作次数
|
||
|
};
|
||
|
|
||
|
let library = null;
|
||
|
let state = 0; // 游戏状态 0->未开始 1->进行中 2->结束
|
||
|
|
||
|
function initStage(lib) {
|
||
|
library = lib;
|
||
|
|
||
|
window.main = Main.of(gameOver); // 初始化鸟等
|
||
|
window.timeInstance = Time.of(gameOver); // 初始化游戏时间
|
||
|
// window.soundInstance = Sound.of(); // 初始化音频
|
||
|
Level.of(2); // 游戏难度级别
|
||
|
Back.of(); // 返回按钮
|
||
|
}
|
||
|
|
||
|
// 游戏结束 显示结束得分面板
|
||
|
function gameOver() {
|
||
|
state = 2;
|
||
|
const times = main.times;
|
||
|
const score = parseInt((config.total / config.times) * times);
|
||
|
End.of(score);
|
||
|
}
|
||
|
|
||
|
```
|
||
|
|
||
|
### 游戏模块组件类说明
|
||
|
|
||
|
以time.js 游戏计时模块为例:
|
||
|
|
||
|
每个类除了自身的功能定义、调用之外,
|
||
|
|
||
|
+ 统一添加了 *of* 静态方法,封装了 new 操作(不喜欢看到new)、调用了初始化 init 函数、并返回示例,因此调用时只需要`Time.of(...)` 就可以
|
||
|
+ 如果有涉及到跟其他类的关联调用,如end方法中的 endCallback,以回调函数的形式传参使用
|
||
|
+ 尽最大可能减少全局变量,外部变量的引用,保证函数的引用透明,让他纯,减少副作用,提高复用性
|
||
|
|
||
|
```js
|
||
|
/**
|
||
|
* 游戏时长 计时
|
||
|
* @param {function} endCallback 倒计时结束的回调函数
|
||
|
* @param {number} duration 游戏时长
|
||
|
* @param {number} count 游戏倒计时时长
|
||
|
*
|
||
|
* @property {number} duration 游戏时长
|
||
|
* @property {number} count 游戏倒计时时长
|
||
|
* @property {number} startTime 游戏开始是ms
|
||
|
* @property {boolean} started 游戏是否开始
|
||
|
* @property {object} lib 资源库
|
||
|
* @property {object} bg 时间倒计时背景
|
||
|
* @property {object} text 倒计时文本
|
||
|
* @property {number} timerId 定时器id
|
||
|
* @property {function} endCallback 结束回调函数
|
||
|
*/
|
||
|
function Time(endCallback, duration, count) {
|
||
|
this.duration = duration;
|
||
|
this.count = count;
|
||
|
this.startTime = Date.now();
|
||
|
|
||
|
this.started = false; // 是否开始游戏
|
||
|
|
||
|
this.lib = library;
|
||
|
this.bg = null;
|
||
|
this.text = null;
|
||
|
this.timerId = null;
|
||
|
this.endCallback = endCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 静态方法 封装new init 返回实例
|
||
|
* @param {function} endCallback 倒计时结束的回调函数
|
||
|
* @param {number} duration 游戏时长
|
||
|
* @param {number} count 游戏倒计时时长
|
||
|
* @returns
|
||
|
*/
|
||
|
Time.of = function (endCallback, duration = config.duration || 60, count = config.count || 5) {
|
||
|
const instance = new Time(endCallback, duration, count);
|
||
|
instance.init();
|
||
|
return instance;
|
||
|
};
|
||
|
|
||
|
// 初始化
|
||
|
Time.prototype.init = function () {
|
||
|
this.renderBg();
|
||
|
this.renderText(this.duration);
|
||
|
};
|
||
|
|
||
|
// 开始游戏 开始倒计时
|
||
|
Time.prototype.start = function (startTime = Date.now()) {
|
||
|
this.started = true;
|
||
|
state = 1;
|
||
|
this.startTime = startTime;
|
||
|
this.update();
|
||
|
};
|
||
|
|
||
|
// 开始游戏 开始倒计时
|
||
|
Time.prototype.end = function () {
|
||
|
this.started = false;
|
||
|
this.timerId && clearTimeout(this.timerId);
|
||
|
this.timerId = null;
|
||
|
// 执行结束后的回调
|
||
|
this.endCallback();
|
||
|
};
|
||
|
|
||
|
// 渲染背景
|
||
|
Time.prototype.renderBg = function () {
|
||
|
const initX = this.lib.properties.width - 100;
|
||
|
const initY = 80;
|
||
|
const instance = new this.lib.timeBg();
|
||
|
instance.x = initX;
|
||
|
instance.y = initY;
|
||
|
this.bg = instance;
|
||
|
stage.addChild(instance);
|
||
|
};
|
||
|
|
||
|
// 渲染文本
|
||
|
Time.prototype.renderText = function (time) {
|
||
|
const text = new createjs.Text(time, 'bold 40px Arial', '#823d16');
|
||
|
text.x = this.lib.properties.width - 100;
|
||
|
text.y = 100;
|
||
|
text.textAlign = 'center';
|
||
|
text.textBaseline = 'alphabetic';
|
||
|
this.text = text;
|
||
|
stage.addChild(text);
|
||
|
};
|
||
|
|
||
|
// 更新文本
|
||
|
Time.prototype.update = function () {
|
||
|
if (this.timerId || !this.started) return;
|
||
|
// const endTime = this.startTime + this.count * 1000 + this.duration * 1000;
|
||
|
const endTime = this.startTime + this.duration * 1000;
|
||
|
// console.log('endTime: ', endTime);
|
||
|
this.timerId = setInterval(() => {
|
||
|
let leftTime = Math.round((endTime - Date.now()) / 1000);
|
||
|
console.log('leftTime: ', leftTime);
|
||
|
this.text && stage.removeChild(this.text);
|
||
|
if (leftTime <= 0) {
|
||
|
leftTime = 0;
|
||
|
this.end();
|
||
|
}
|
||
|
this.renderText(leftTime);
|
||
|
}, 1000);
|
||
|
};
|
||
|
|
||
|
```
|
||
|
|
||
|
**特别说明:**时间关系,还有很多需要完善的,比如上文中的endCallback就没有做类型判断。后续除了程序的健壮性优化提升之外,还须添加webpack工程化打包构建等,避免源代码暴露,代码体积、模块导入引用等都能得到好的提升
|