JavaScript简单贪吃蛇,基本面向对象
没有写博客的习惯,这篇算心血来潮,算篇近几天编写的小程序纪实.
以编写此程序的方式结束Javascript的本阶段的学习.编写的目的在于熟悉javascript的编程方式,包括代码风格,面向对象的运用等.
回到程序,说说Snake的移动的实现方法.其实很简单,向头部添加Unit,然后删除尾部.其他,参见注释.
程序包括一个html文件:snake.html和一个js文件:snake.js
snake.html:
$s(function(){
$s.SnakeContext.init();
});
snake.js:
/*
* JavaScript简单贪吃蛇.基本面向对象.
* 规则:
* 1.没有墙,左与右连接,上与下连接.
* 2.当蛇头碰撞到自身时死亡.
* 兼容性:
* 完全支持Firefox,Chrome
* 基本支持IE(除了调试部分)
*
* 作者:pcenshao
* 转载请注明来自:
* http://blog.csdn.net/pywepe
* http://pcenshao.taobao.com
*/
(function(){
$s = function(){
if(arguments.length == 1){
if(typeof arguments[0] == "string"){
return document.getElementById(arguments[0]);
}else if(typeof arguments[0] == "function"){
window.onload = arguments[0];
}
}
};
$s.UNIT_WIDTH = 10; // 单元的宽度
$s.UNIT_HEIGHT = 10;
$s.PANEL_WIDTH = 30; // 逻辑宽度
$s.PANEL_HEIGHT = 20; // 逻辑高度
$s.STEP = 250 ; // 每一步的时间
$s.HEAD_COLOR = "red"; // 蛇头颜色
$s.BODY_COLOR = "black"; // 蛇体颜色
/*
* 食物的颜色
*/
$s.COLORS = ["blue","green","#494e8f","#905d1d","#845538","#77ac98","#8552a1"];
/*
* 调试相关
* $s.DEBUG 调试信息显示开关
* $s.KEY_UP_DIR_ID 监视方向键的结点id,若不存在,则不显示
* $s.HEAD_LOCATION_ID 监视蛇头位置的结点id,若不存在,则不显示
*/
$s.DEBUG = false;
$s.KEY_UP_DIR_ID = "keyup";
$s.HEAD_LOCATION_ID = "headLocation";
$s.Dir = { // 代表方向,强制以$s.Dir.UP方法调用,避免参数错误
UP : {},
DOWN : {},
LEFT : {},
RIGHT : {},
NONE : {}
};
$s.State = { // 代表状态
STOP : {},
RUNNGIN : {},
PAUSE : {}
};
$s.Unit = function(){ // 一个单元格,用MVC的眼光看,Unit是模型,UnitView是视图
this.x = 0;
this.y = 0;
this.view = new $s.UnitView();
this.view.unit = this;
this.color = $s.BODY_COLOR;
};
$s.Unit.prototype.repaint = function(){
if(this.view != null){
this.view.repaint(); // 通知重绘
}
};
$s.Snake = function(){
this.units = [];
};
$s.Snake.prototype.init = function(dir,count){
var x = 5;
var y = 5;
for(var i = 0 ; i < count ; i ++){
var u = new $s.Unit();
u.x = x ;
u.y = y ++;
this.units.push(u);
if(i == (count - 1 )){
u.color = $s.HEAD_COLOR;
}
u.repaint();
}
};
$s.Snake.prototype.crash = function(x,y){ // 传入头部的位置,返回true表示碰撞自身
for(var i = this.units.length - 2 ; i >= 0 ; i --){ // 不包括头自身
var u = this.units[i];
if(u.x == x && u.y == y){
return true;
}
}
return false;
};
$s.Snake.prototype.go = function(){
// 判断前方是否有食物
// 是否撞墙
var _x = 0 , _y = 0;
var head = this.units[this.units.length - 1];
_x = head.x;
_y = head.y;
var dir = $s.SnakeContext.dir;
if(this.crash(_x,_y)){ // 判断是否碰撞到自身
$s.SnakeContext.stop();
$s.SnakeContext.ondead(); // 触发dead事件
return;
}
if(dir == $s.Dir.LEFT){
_x --;
}else if(dir == $s.Dir.RIGHT){
_x ++;
}else if(dir == $s.Dir.UP){
_y --;
}else if(dir == $s.Dir.DOWN){
_y ++;
}
// 实现左右连接,上下连接
if(_x >= $s.PANEL_WIDTH){
_x = 0;
}
if(_x < 0){
_x = $s.PANEL_WIDTH - 1;
}
if(_y >= $s.PANEL_HEIGHT){
_y = 0;
}
if(_y < 0){
_y = $s.PANEL_HEIGHT - 1;
}
var h = new $s.Unit(); // 新头
if($s.SnakeContext.hasFood(_x,_y)){ // 下一步碰到食物
this.eat(_x,_y);
head = this.units[this.units.length - 1]; // 因为eat方法可以改变头部,所以重新获取
_x = head.x;
_y = head.y;
if(dir == $s.Dir.LEFT){
_x --;
}else if(dir == $s.Dir.RIGHT){
_x ++;
}else if(dir == $s.Dir.UP){
_y --;
}else if(dir == $s.Dir.DOWN){
_y ++;
}
head.color = $s.HEAD_COLOR;
head.repaint();
var oldHead = this.units[this.units.length - 2];
oldHead.color = $s.BODY_COLOR;
oldHead.repaint();
return;
}
var tail = this.units.shift();
$s.NodePool.releaseNode(tail);
h.x = _x;
h.y = _y;
this.units.push(h);
for(var i = this.units.length - 1; i >= 0; i --){
var u = this.units[i];
if(i == (this.units.length - 1)){ // 头
u.color = $s.HEAD_COLOR;
}else{
u.color = $s.BODY_COLOR;
}
u.repaint();
}
};
$s.Snake.prototype.eat = function(x,y){
var food = $s.SnakeContext.food;
if(food != null){
food.alive = false;
this.units.push(food.unit);
$s.SnakeContext.oneat();
}else{
alert("error:no food on (" + x + "," + y + ")");
}
}
/*
* 随机数产生器,提供简便的方法
*/
$s.Random = {
randomNumber : function(lower,upper){ // 返回区间[lower,upper]的整数
var choices = upper - lower + 1;
return Math.floor(Math.random() * choices + lower); // value = Math.floor(Math.random() * 可能值的个数+ 第一个可能的值)
},
randomLocation : function(maxX,maxY){
var x = $s.Random.randomNumber(0,maxX);
var y = $s.Random.randomNumber(0,maxY);
return {x:x,y:y};
}
};
$s.Food = function(x,y){ // 代表食物,由一个Unit表示
this.unit = new $s.Unit();
this.unit.x = x;
this.unit.y = y;
var color = $s.COLORS[$s.Random.randomNumber(0,$s.COLORS.length - 1)];
this.unit.color = color;
this.alive = true;
this.unit.repaint();
};
$s.Food.prototype.locateOn = function(x,y){
return this.unit.x == x && this.unit.y == y;
};
/*
* HTML结点池,主要目的是提高效率
* 因为snake的移动是通过删除尾部结点并向头部添加结点实现的,
* 在这个过程中会有大量的结点创建操作,为了操作效率,所以对结点进行池化管理.
* 尾部的结点不删除,而是隐藏,需要结点时可以重用之
*/
$s.NodePool = {
nodes : []
};
$s.NodePool._findHideNode = function(){ // 查找隐藏的div结点
for(var i = 0 ; i < this.nodes.length ; i ++){
var n = this.nodes[i];
if(n.style.display == "none"){
return n;
}
}
return null;
};
$s.NodePool.createNode = function(){
var pooledNode = this._findHideNode();
if(pooledNode != null){
return pooledNode;
}else{
var newNode = document.createElement("div");
this.nodes.push(newNode);
return newNode;
}
};
$s.NodePool.releaseNode = function(node){
if(node != undefined && node != null){
if(node instanceof $s.Unit){
var view = node.view;
if(view != null){
var div = view.node;
div.style.display = "none";
}
}
}
}
$s.UnitView = function(){ // Unit的视图
this.unit = null;
this.node = null;
};
$s.UnitView.prototype.repaint = function(){
if(this.node == null){ // 初始化
var tag = $s.NodePool.createNode();
tag.style.width = $s.UNIT_WIDTH + "px";
tag.style.height = $s.UNIT_HEIGHT + "px";
tag.style.borderStyle = "dotted";
tag.style.borderWidth = "1px";
tag.style.borderColor = "white";
tag.style.margintLeft = "1px";
tag.style.marginRight = "1px";
tag.style.marginTop = "1px";
tag.style.marginBottom = "1px";
tag.style.backgroundColor = this.unit.color; // 颜色由模型Unit指定
tag.style.position = "absolute"; //容器的position指定为relative,孩子的position指定为absolute时,表示孩子相对容器绝对定位.
tag.style.display = "block"; // 重要,因为从NodePool取现的结点是隐藏状态的
var x = this.unit.x * $s.UNIT_WIDTH;
var y = this.unit.y * $s.UNIT_HEIGHT;
tag.style.top = y + "px";
tag.style.left = x + "px";
this.node = tag;
$s.SnakeContext.panelView.append(this);
}else{
var tag = this.node;
var x = this.unit.x * $s.UNIT_WIDTH;
var y = this.unit.y * $s.UNIT_HEIGHT;
tag.style.top = y + "px";
tag.style.left = x + "px";
tag.style.backgroundColor = this.unit.color;
}
};
$s.PanelView = function(){ // 整个游戏区域,包括按钮区
var panel = document.createElement("div");
panel.style.width = ($s.PANEL_WIDTH * $s.UNIT_WIDTH ) + "px";
panel.style.height = ($s.PANEL_HEIGHT * $s.UNIT_HEIGHT ) + "px";
panel.style.borderStyle = "dotted";
panel.style.borderColor = "red";
panel.style.borderWidth = "1px";
panel.style.marginLeft = "auto";
panel.style.marginRight = "auto";
panel.style.marginTop = "50px";
panel.style.position = "relative"; // 容器的position指定为relative,孩子的position指定为absolute时,表示孩子相对容器绝对定位.
panel.style.marginBottom = "auto";
this.node = panel;
document.body.appendChild(panel);
var len = document.createElement("div");
len.style.marginLeft = "auto";
len.style.marginRight = "auto";
len.style.marginBottom = "20px";
len.style.color = "gray";
len.style.fontSize = "12px";
len.innerHTML = "长度:";
document.body.appendChild(len);
$s.SnakeContext._len = len;
var startBn = document.createElement("button");
startBn.innerHTML = "开始";
startBn.style.marginLeft = "10px";
startBn.onclick = function(){
$s.SnakeContext.run();
};
$s.SnakeContext._startBn = startBn;
document.body.appendChild(startBn);
var pauseBn = document.createElement("button");
pauseBn.innerHTML = "暂停";
pauseBn.style.marginLeft = "10px";
pauseBn.onclick = function(){
$s.SnakeContext.pause();
};
$s.SnakeContext._pauseBn = pauseBn;
document.body.appendChild(pauseBn);
/*
var stopBn = document.createElement("button");
stopBn.innerHTML = "停止";
stopBn.style.marginLeft = "10px";
stopBn.onclick = function(){
$s.SnakeContext.stop();
};
$s.SnakeContext._stopBn = stopBn;
document.body.appendChild(stopBn);
*/
var restartBn = document.createElement("button");
restartBn.innerHTML = "重新开始";
restartBn.style.marginLeft = "10px";
restartBn.onclick = function(){
window.location.href = window.location.href;
};
$s.SnakeContext._restartBn = restartBn;
document.body.appendChild(restartBn);
var line = document.createElement("div");
line.style.height = "10px";
document.body.appendChild(line);
var span = document.createElement("span");
span.style.color = "gray";
span.style.fontSize = "12px";
span.innerHTML = "调试";
document.body.appendChild(span);
var debug = document.createElement("input");
debug.type = "checkbox";
debug.checked = $s.DEBUG;
debug.onchange = function(){
$s.SnakeContext.setDebug(debug.checked);
};
document.body.appendChild(debug);
};
$s.PanelView.prototype.append = function(unitView){
try{
this.node.appendChild(unitView.node);
}catch(e){
alert(e);
}
};
/*
* 全局环境类,代表应用
* 约定以_开头的成员为私有成员
* 启动程序的方法:
* window.onload = function(){
* $s.SnakeContext.init();
* }
*/
$s.SnakeContext = {
dir : $s.Dir.NONE,
state : $s.State.STOP,
goTimer : null,
run : function(){
if(this.state != $s.State.RUNNGIN){
this.state = $s.State.RUNNGIN;
this.goTimer = window.setInterval(function(){
$s.SnakeContext.updateFood();
$s.SnakeContext.snake.go();
},$s.STEP);
}
},
stop : function(){
this._setState($s.State.STOP);
},
pause : function(){
this._setState($s.State.PAUSE);
},
_setState : function(s){
if(this.state != s && this.goTimer != null){
window.clearInterval(this.goTimer);
this.goTimer = null;
this.state = s;
}
},
getFood : function(x,y){
for(var f in this.foods){
if(f.x == x && f.y == y){
return f;
}
}
return null;
},
init : function(){
this.panelView = new $s.PanelView();
this.snake = new $s.Snake();
this.dir = $s.Dir.DOWN;
this.snake.init($s.Dir.UP,3);
this._len.innerHTML = "长度:" + 3;
document.body.onkeyup = function(e){
var code = null;
if(window.event){ // fuck的IE
code = window.event.keyCode;
}else{
code = e.keyCode;
}
var str = "";
var oldDir = $s.SnakeContext.dir;
switch(code){
case 37: // left
if($s.SnakeContext.dir != $s.Dir.RIGHT){
$s.SnakeContext.dir = $s.Dir.LEFT;
}
str = "left";
break;
case 38 : // up
if($s.SnakeContext.dir != $s.Dir.DOWN){
$s.SnakeContext.dir = $s.Dir.UP;
}
str = "up";
break;
case 39: // right
if($s.SnakeContext.dir != $s.Dir.LEFT){
$s.SnakeContext.dir = $s.Dir.RIGHT;
}
str = "right";
break;
case 40: // down
if($s.SnakeContext.dir != $s.Dir.UP){
$s.SnakeContext.dir = $s.Dir.DOWN;
}
str = "down";
break;
}
if($s.SnakeContext.dir != oldDir){
if($s.DEBUG){
var v = $s($s.KEY_UP_DIR_ID);
if(v){
v.innerHTML = "方向键:" + str;
}
}
if($s.SnakeContext.goTimer != null){
window.clearInterval($s.SnakeContext.goTimer);
$s.SnakeContext.goTimer = null;
}
$s.SnakeContext.snake.go();
$s.SnakeContext.goTimer = window.setInterval(function(){
$s.SnakeContext.updateFood();
$s.SnakeContext.snake.go();
},$s.STEP);
}
};
var loc = $s.Random.randomLocation($s.PANEL_WIDTH - 1, $s.PANEL_HEIGHT - 1);
this.food = new $s.Food(loc.x,loc.y);
},
snake : null,
foods : [],
panelView : null,
food : null,
updateFood : function(){
if(this.food.alive){ // 当前Food还存活
return;
}
var loc = null;
do{
// 随机产生一个点,直到不Snake重叠
loc = $s.Random.randomLocation($s.PANEL_WIDTH - 1,$s.PANEL_HEIGHT - 1);
}while(this.overlap(loc));
this.food = new $s.Food(loc.x,loc.y);
},
overlap : function(loc){ // 检查是否与Snake重叠,当重叠时返回true
var x = loc.x;
var y = loc.y;
for(var i = 0 ; i < this.snake.units.length ; i ++ ){
var u = this.snake.units[i];
if(u.x == x && u.y == y){
return true;
}
}
return false;
},
hasFood : function(x,y){
if($s.DEBUG){
var xt = $s($s.HEAD_LOCATION_ID);
if(xt){
xt.innerHTML = "头部位置:(" + x + "," + y + ")";
}
}
return this.food.locateOn(x,y);
},
setDebug : function(enable){
if(enable != $s.DEBUG){
$s.DEBUG = enable;
if($s.DEBUG){ // 显示
var i = $s($s.KEY_UP_DIR_ID);
$s.SnakeContext._show(i);
i = $s($s.HEAD_LOCATION_ID);
$s.SnakeContext._show(i);
}else{ // 隐藏
var i = $s($s.KEY_UP_DIR_ID);
$s.SnakeContext._hide(i);
i = $s($s.HEAD_LOCATION_ID);
$s.SnakeContext._hide(i);
}
}
},
_show : function(tag){
if(tag){
tag.style.display = "block";
}
},
_hide : function(tag){
if(tag){
tag.style.display = "none";
}
},
ondead : function(){ // Snake死亡时回调
if(this._startBn){
this._startBn.disabled = true;
}
if(this._pauseBn){
this._pauseBn.disabled = true;
}
if(this._stopBn){
this._stopBn.disabled = true;
}
alert("挂了");
},
oneat : function(){ // Snake长度增加时回调
this._len.innerHTML = "长度:" + this.snake.units.length;
},
_startBn : null,
_pauseBn : null,
_stopBn : null,
_restartBn : null,
_len : null
};
})();

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Cara menggunakan WebSocket dan JavaScript untuk melaksanakan sistem pengecaman pertuturan dalam talian Pengenalan: Dengan perkembangan teknologi yang berterusan, teknologi pengecaman pertuturan telah menjadi bahagian penting dalam bidang kecerdasan buatan. Sistem pengecaman pertuturan dalam talian berdasarkan WebSocket dan JavaScript mempunyai ciri kependaman rendah, masa nyata dan platform merentas, dan telah menjadi penyelesaian yang digunakan secara meluas. Artikel ini akan memperkenalkan cara menggunakan WebSocket dan JavaScript untuk melaksanakan sistem pengecaman pertuturan dalam talian.

WebSocket dan JavaScript: Teknologi utama untuk merealisasikan sistem pemantauan masa nyata Pengenalan: Dengan perkembangan pesat teknologi Internet, sistem pemantauan masa nyata telah digunakan secara meluas dalam pelbagai bidang. Salah satu teknologi utama untuk mencapai pemantauan masa nyata ialah gabungan WebSocket dan JavaScript. Artikel ini akan memperkenalkan aplikasi WebSocket dan JavaScript dalam sistem pemantauan masa nyata, memberikan contoh kod dan menerangkan prinsip pelaksanaannya secara terperinci. 1. Teknologi WebSocket

Cara menggunakan WebSocket dan JavaScript untuk melaksanakan sistem tempahan dalam talian Dalam era digital hari ini, semakin banyak perniagaan dan perkhidmatan perlu menyediakan fungsi tempahan dalam talian. Adalah penting untuk melaksanakan sistem tempahan dalam talian yang cekap dan masa nyata. Artikel ini akan memperkenalkan cara menggunakan WebSocket dan JavaScript untuk melaksanakan sistem tempahan dalam talian dan memberikan contoh kod khusus. 1. Apakah itu WebSocket? WebSocket ialah kaedah dupleks penuh pada sambungan TCP tunggal.

Pengenalan kepada cara menggunakan JavaScript dan WebSocket untuk melaksanakan sistem pesanan dalam talian masa nyata: Dengan populariti Internet dan kemajuan teknologi, semakin banyak restoran telah mula menyediakan perkhidmatan pesanan dalam talian. Untuk melaksanakan sistem pesanan dalam talian masa nyata, kami boleh menggunakan teknologi JavaScript dan WebSocket. WebSocket ialah protokol komunikasi dupleks penuh berdasarkan protokol TCP, yang boleh merealisasikan komunikasi dua hala masa nyata antara pelanggan dan pelayan. Dalam sistem pesanan dalam talian masa nyata, apabila pengguna memilih hidangan dan membuat pesanan

JavaScript dan WebSocket: Membina sistem ramalan cuaca masa nyata yang cekap Pengenalan: Hari ini, ketepatan ramalan cuaca sangat penting kepada kehidupan harian dan membuat keputusan. Apabila teknologi berkembang, kami boleh menyediakan ramalan cuaca yang lebih tepat dan boleh dipercayai dengan mendapatkan data cuaca dalam masa nyata. Dalam artikel ini, kita akan mempelajari cara menggunakan teknologi JavaScript dan WebSocket untuk membina sistem ramalan cuaca masa nyata yang cekap. Artikel ini akan menunjukkan proses pelaksanaan melalui contoh kod tertentu. Kami

Tutorial JavaScript: Bagaimana untuk mendapatkan kod status HTTP, contoh kod khusus diperlukan: Dalam pembangunan web, interaksi data dengan pelayan sering terlibat. Apabila berkomunikasi dengan pelayan, kami selalunya perlu mendapatkan kod status HTTP yang dikembalikan untuk menentukan sama ada operasi itu berjaya dan melaksanakan pemprosesan yang sepadan berdasarkan kod status yang berbeza. Artikel ini akan mengajar anda cara menggunakan JavaScript untuk mendapatkan kod status HTTP dan menyediakan beberapa contoh kod praktikal. Menggunakan XMLHttpRequest

Pengenalan kepada kaedah mendapatkan kod status HTTP dalam JavaScript: Dalam pembangunan bahagian hadapan, kita selalunya perlu berurusan dengan interaksi dengan antara muka bahagian belakang, dan kod status HTTP adalah bahagian yang sangat penting daripadanya. Memahami dan mendapatkan kod status HTTP membantu kami mengendalikan data yang dikembalikan oleh antara muka dengan lebih baik. Artikel ini akan memperkenalkan cara menggunakan JavaScript untuk mendapatkan kod status HTTP dan memberikan contoh kod khusus. 1. Apakah kod status HTTP bermakna kod status HTTP apabila penyemak imbas memulakan permintaan kepada pelayan, perkhidmatan tersebut

Penggunaan: Dalam JavaScript, kaedah insertBefore() digunakan untuk memasukkan nod baharu dalam pepohon DOM. Kaedah ini memerlukan dua parameter: nod baharu untuk dimasukkan dan nod rujukan (iaitu nod di mana nod baharu akan dimasukkan).
