最近突然又想去学习下怎么写游戏了,所以呢,这篇博客是来水的。。。顺便记录一下设计模式中命令模式的典型用法,以及推荐一个学习游戏的教程,说到写游戏那最好的教程肯定是萧大的啦,萧井陌-B站直播视频库,初始的几个游戏都是比较简单的游戏,但最重要的是要看它的重构过程,重要的事情说3遍,要看重构过程,要看重构过程 ,要看重构过程,你会认识到什么叫函数式编程、什么叫命令模式、什么叫工厂模式等等,好的,下面是一个我的粗糙例子,请不要模仿~
// replay.html
<canvas class="box" id="canvas" width="500" height="500"></canvas>
<div>
<button type="button" id="start">start</button>
<button type="button" id="over">over</button>
<button type="button" id="replay">replay</button>
</div>
// replay.js
// 初始化相关数据
var rect = {
x: 225,
y: 225,
w: 50,
h: 50
},
delay = 0,
commandStack = [],
ctx = document.getElementById('canvas').getContext('2d');
// 创建角色动作集合
var role = {
clear: function (x, y, w, h) {
ctx.clearRect(x, y, w, h);
},
drawInit: function (x, y, w, h) {
rect = {
x: x,
y: y,
w: w,
h: h
};
this.clear(0, 0, 500, 500);
ctx.fillStyle = "#bcf";
ctx.strokeStyle = "#888";
ctx.fillRect(x, y, w, h);
},
up: function (range) {
rect.y -= range;
this.drawInit(rect.x, rect.y, rect.w, rect.h);
},
down: function (range) {
rect.y += range;
this.drawInit(rect.x, rect.y, rect.w, rect.h);
},
left: function (range) {
rect.x -= range;
this.drawInit(rect.x, rect.y, rect.w, rect.h);
},
right: function (range) {
rect.x += range;
this.drawInit(rect.x, rect.y, rect.w, rect.h);
}
}
// 创建任务集合, 抽象为可携带参数
var commands = {
'119': {
fn: 'up',
args: [2]
},
'115': {
fn: 'down',
args: [2]
},
'97': {
fn: 'left',
args: [2]
},
'100': {
fn: 'right',
args: [2]
},
'drawInit': {
fn: 'drawInit',
args: [rect.x, rect.y, rect.w, rect.h]
},
'clear': {
fn: 'clear',
args: [0, 0, 500, 500]
}
}
// 利用闭包存储任务并赋予角色动作
var makeCommand = function (receiver, state) {
return function () {
receiver[state].apply(role, arguments)
}
}
// 执行角色任务及将存储的任务压入回放任务队列
function runAndPushStack (key) {
var command = makeCommand(role, commands[key]['fn']),
args = commands[key]['args'];
if (command) {
commandStack.push({
fn: command,
args: args || [],
delay: (new Date()).getTime() - delay // 传入每次动作距离开始时间延迟
});
command.apply(role, args);
}
}
// 初始化数据函数
function initConfig () {
delay = (new Date()).getTime();
commandStack = [];
rect = {
x: 225,
y: 225,
w: 50,
h: 50
};
}
// 监控键盘事件
document.onkeypress = function (e) {
var keyCode = e.keyCode;
runAndPushStack(keyCode);
}
// 开始录制
document.getElementById('start').onclick = function () {
initConfig();
document.getElementById('over').disabled = false;
runAndPushStack('drawInit');
}
// 结束录制
document.getElementById('over').onclick = function () {
this.disabled = true;
commandStack.push({
fn: function () {
alert('Thanks your watch, this play have over!');
},
delay: (new Date()).getTime() - delay // 传入每次动作距离开始时间延迟
});
}
// 开始回放
document.getElementById('replay').onclick = function () {
if (!document.getElementById('over').disabled) {
alert('请先停止录制');
return 0;
}
var command;
for (var i = 0; i < commandStack.length; i++) {
(function (command) {
setTimeout(function () {
command.fn.apply(role, command.args);
}, command.delay || 0);
})(commandStack[i]);
}
}