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.
238 lines
5.4 KiB
238 lines
5.4 KiB
/*
|
|
author: leeenx
|
|
@ 贪吃蛇的 control 类
|
|
*/
|
|
|
|
// 游戏通用ticker
|
|
import ticker from "../lib/utils/ticker";
|
|
|
|
// timer
|
|
import timer from "../lib/utils/timer";
|
|
|
|
// 随机打散数组
|
|
import randomList from "../lib/utils/randomList";
|
|
|
|
// 事件
|
|
import Events from "../lib/utils/events";
|
|
|
|
// control 类
|
|
export default class control {
|
|
// 构建函数
|
|
constructor(model, view) {
|
|
this.model = model;
|
|
this.view = view;
|
|
|
|
// 挂载一个 speed 属性
|
|
Reflect.defineProperty(this, "speed", {
|
|
get: function () {
|
|
return this.speedScalar || 1;
|
|
},
|
|
set: function (value) {
|
|
if (this.speedScalar !== value) {
|
|
this.speedScalar = value;
|
|
this.interval = 300 / this.speedScalar;
|
|
|
|
// 更新 timer
|
|
timer.set(this.intervalID, { delay: this.interval });
|
|
this.view.setInterval(this.interval, timer);
|
|
}
|
|
},
|
|
});
|
|
|
|
// tickHandle 绑定当前 this
|
|
this.tickHandle = this.tickHandle.bind(this);
|
|
|
|
// this.update 绑定 this
|
|
this.update = this.update.bind(this);
|
|
|
|
// 挂载事件对象
|
|
this.event = new Events();
|
|
|
|
// 四个方向
|
|
this.fourDirections = ["left", "up", "right", "down"];
|
|
}
|
|
|
|
// 初始化
|
|
init(config = {}) {
|
|
// 添加 ticker
|
|
ticker.addEventListener("tick", this.tickHandle);
|
|
// 默认暂停 ticker
|
|
this.pause();
|
|
|
|
let {
|
|
width = 640,
|
|
height = 640,
|
|
row = 50,
|
|
column = 50,
|
|
border = 0x999999,
|
|
color = 0x000000, // 蛇的节点颜色
|
|
food = color, // 食物颜色
|
|
min = 3, // 初始长度
|
|
speed = 1, // 速度标量
|
|
} = config;
|
|
|
|
// 存一份 config 到 this
|
|
this.config = config;
|
|
|
|
// 初始化 model
|
|
this.model.init({ row, column, min });
|
|
|
|
// view.data
|
|
let data = {
|
|
zone: this.model.zone,
|
|
snake: this.model.snake,
|
|
food: this.model.food,
|
|
};
|
|
|
|
// 初始化 view
|
|
this.view.init({ width, height, row, column, border, color, food, data });
|
|
|
|
// interval 的间隔
|
|
this.interval = 300 / this.speedScalar;
|
|
|
|
// 定时更新view
|
|
this.intervalID = timer.setInterval(this.update, this.interval);
|
|
|
|
// 速度标量
|
|
this.speed = speed;
|
|
|
|
// 蛇长度
|
|
this.length = this.model.snake.length;
|
|
|
|
// 初始化食物
|
|
this.food = this.model.food;
|
|
|
|
// 用户操作的方向列表
|
|
this.directions = [];
|
|
|
|
// 总计时
|
|
if (config.time > 0) {
|
|
let time = config.time / 1000;
|
|
timer.setTimeout(() => this.gameover("timeout"), config.time);
|
|
// 倒数
|
|
timer.setInterval(() => this.event.dispatch("countdown", --time), 1000);
|
|
}
|
|
}
|
|
// 销毁
|
|
destroy() {
|
|
// 移除 ticker
|
|
ticker.removeEventListener("tick", this.tickHandle);
|
|
// 清空 timer
|
|
timer.clean();
|
|
// 销毁 model
|
|
this.model.destroy();
|
|
// 销毁 view
|
|
this.view.destroy();
|
|
// GAMEOVER
|
|
this.GAMEOVER = false;
|
|
}
|
|
|
|
// 转向
|
|
turn(direction) {
|
|
// 只保存第一次方向操作
|
|
if (this.fourDirections.indexOf[direction] === -1) return;
|
|
let directionA = direction,
|
|
directionB = this.directions[0] || this.direction;
|
|
// 给操作列表加个容积 5
|
|
if (
|
|
this.directions.length < 5 &&
|
|
directionA !== directionB &&
|
|
!this.isAdverse(directionA, directionB)
|
|
) {
|
|
this.directions.unshift(directionA);
|
|
}
|
|
}
|
|
|
|
// 判断两个方向是否相反
|
|
isAdverse(directionA, directionB) {
|
|
let indexA = this.fourDirections.indexOf(directionA),
|
|
indexB = this.fourDirections.indexOf(directionB);
|
|
if (Math.abs(indexA - indexB) === 2) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// 暂停
|
|
pause() {
|
|
if (this.GAMEOVER) return;
|
|
ticker.pause();
|
|
}
|
|
|
|
// 恢复
|
|
resume() {
|
|
if (this.GAMEOVER) return;
|
|
ticker.resume();
|
|
}
|
|
|
|
// start
|
|
start() {
|
|
if (this.GAMEOVER) return;
|
|
// 蛇的随机运动方向
|
|
let { leader, zone } = this.model;
|
|
// 控制方向的变量是 this.direction。this.nextDirection 表示下一个方向
|
|
this.directions.push(
|
|
randomList(
|
|
this.fourDirections.filter(
|
|
(item) => leader[item] !== -1 && zone[leader[item]].fill === undefined
|
|
),
|
|
1
|
|
)
|
|
);
|
|
|
|
this.update();
|
|
}
|
|
|
|
// 重新开始
|
|
restart() {
|
|
this.destroy();
|
|
this.init(this.config);
|
|
this.start();
|
|
this.event.dispatch("restart");
|
|
}
|
|
|
|
// gameover
|
|
gameover(type) {
|
|
if (this.GAMEOVER) return;
|
|
this.view.renderLose();
|
|
setTimeout(() => {
|
|
this.event.dispatch("gameover", type);
|
|
}, 500);
|
|
|
|
this.pause();
|
|
this.GAMEOVER = true;
|
|
}
|
|
|
|
// update
|
|
update() {
|
|
// this.direction 表示蛇头节点的运动方向
|
|
this.direction = this.directions.pop() || this.direction;
|
|
this.model.move(this.direction);
|
|
if (this.model.bar !== undefined) {
|
|
// gameover
|
|
this.gameover(this.model.bar);
|
|
}
|
|
let data = { snake: this.model.snake, food: this.model.food };
|
|
if (this.model.dirty) {
|
|
// model 有变化
|
|
let hasEatEvent = false;
|
|
if (this.food !== this.model.food) {
|
|
this.food = this.model.food;
|
|
hasEatEvent = true;
|
|
this.event.dispatch("before-eat");
|
|
this.length = this.model.snake.length;
|
|
}
|
|
this.view.update(data);
|
|
hasEatEvent && this.event.dispatch("eat");
|
|
this.model.cleanDirty();
|
|
}
|
|
}
|
|
|
|
// tickHandle
|
|
tickHandle() {
|
|
timer.update(ticker.paused, ticker.elapsedMS * 1000);
|
|
if (!ticker.paused) {
|
|
this.view.updateTicker();
|
|
}
|
|
}
|
|
}
|
|
|