没有写博客的习惯,这篇算心血来潮,算篇近几天编写的小程序纪实.
以编写此程序的方式结束Javascript的本阶段的学习.编写的目的在于熟悉javascript的编程方式,包括代码风格,面向对象的运用等.
回到程序,说说Snake的移动的实现方法.其实很简单,向头部添加Unit,然后删除尾部.其他,参见注释.
程序包括一个html文件:snake.html和一个js文件:snake.js
snake.html:
$s(function(){
$s.SnakeContext.init();
});
snake.js:
/*
* JavaScript는 기본 객체 지향입니다.
* 규칙:
* 1. 벽이 없습니다. 바로연결, 상하연결.
* 2. 뱀머리가 스스로 충돌하면 사망.
* 호환성:
* 파이어폭스, 크롬 완벽지원
* IE 기본 지원(디버깅 부분 제외)
*
* 작성자: pcenshao
* 전재할 경우 출처를 밝혀주세요:
* http: //blog.csdn.net/pywepe
* http://pcenshao.taobao.com
*/
(function(){
$s = function(){
if(arguments.length == 1){
if(typeof 인수[0] == "string "){
return document.getElementById(arguments[0]); 0];
🎜>
$s.UNIT_HEIGHT = 10; $s .PANEL_WIDTH = 30; // 논리적 너비 $s.PANEL_HEIGHT = 20; // 논리적 높이 $s.STEP = 250; // 각 단계의 시간 $s.HEAD_COLOR = "빨간색"; // 뱀 머리 색상 $s.BODY_COLOR = "검은색" / / 뱀 몸 색상 /* * 식용 색소 */ $s.COLORS = ["파란색","녹색"," #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 메소드를 강제 호출, 매개변수 오류 방지 위 : {}, 아래 : {}, 왼쪽 : {}, 오른쪽 : {},없음 : {} }; $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.prototype.init = function(dir,count){
var x = 5;
var y = 5;
for(var i = 0 ; i < 개수 ; 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) {
; 🎜>
$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;
$s.SnakeContext.stop();
> 왼쪽){ _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;
~
_y --;
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);
This.units.push (h);
~ 단위[i];
If(i == (this.units.length - 1)){ // 머리
u.color = $s.HEAD_COLOR;
🎜>
} }; $s.Snake.prototype.eat = function(x,y){ var food = $s.SnakeContext.food; if(food != null){ food.alive = false; this.units .push(food.unit);~ >
임의번호 : 함수(하위,상위) { // [lower,upper] 범위의 정수를 반환합니다.
varChoices = 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); 🎜>
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 노드 풀, 효율성 향상이 주목적 * 꼬리 노드를 삭제하고 머리 노드를 추가하여 뱀의 움직임을 구현하기 때문에 * 이 과정에서 다수의 노드 생성 작업이 발생하게 됩니다. 작업 효율을 위해 노드를 모아서 관리합니다. * 테일 노드는 삭제되지 않지만, 노드가 필요할 때 재사용할 수 있습니다. */ $s.NodePool = { 노드 : [] }; $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 != undefine && node , >
var div = view.node;
div.style.display = "none" ;
}
}
}
$s.UnitView = function(){ // 유닛적용
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.borderColor = "흰색"; tag.style.margintLeft = "1px"; tag.style.marginRight = "1px"; tag.style.marginTop = "1px"; tag.style.marginBottom = "1px"; tag.style.BackgroundColor = this.unit.color; // 颜color由模型Unit指정 tag.style.position = "absolute"; //기준 위치는 상대 위치, 상대 위치는 절대 위치, 절대 위치, 表示孩子 상대 위치는 tag.style.display = " 차단"; // 큼, 因为从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 태그 = 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 = "자동"; panel.style.marginRight = "자동";
panel.style.marginTop = "50px";
panel.style.position = "relative"; //컨테이너의 위치를 상대값으로 지정하고, 자식의 위치를 지정한 경우 절대적이라는 것은 자식이 컨테이너에 상대적이라는 것을 의미합니다. 절대 위치 지정.
panel.style.marginBottom = "auto";
this.node = panel;
document.body.appendChild(panel);
";
len.style.marginBottom = "20 px";
len.style.color = "회색";
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 = startB n ;
document.body.appendChild(startBn);
"일시 중지";
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 ; >
restartBn.innerHTML = "다시 시작";restartBn.style.marginLeft = "10px"; restartBn.onclick = function(){ window .location.href = window.location.href; }; }; $s.SnakeContext._restartBn = restartBn; document.body.appendChild(restartBn); ~ (줄);
span.style.color = "회색";
span.style.fontSize = "12px";
span.innerHTML = "调试";
문서 .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){
시도{
this.node.appendChild(unitView.node);
}catch(e){
경고(e);
}
};
/*
*
* 约결정以_开头的成员为私有成员
* 启动程序적 방법:
* window.onload = function(){
* $s.SnakeContext.init() ;
* }
*/
$s.SnakeContext = {
dir : $s.Dir.NONE,
상태 : $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);
}
},
중지: function(){
this._setState($s.State.STOP);
},
일시 중지: function(){
this._setState($s.State.PAUSE);
},
_setState : 함수{
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;
}
}
null 반환;
},
init : function(){
이 .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;
문서 ... .이벤트 .keyCode;
}else{
코드 = e.keyCode;
}
var str = "";
var oldDir = $s.SnakeContext.dir;
스위치(코드){
사례 37: // 왼쪽
if($s .SnakeContext.dir != $s .Dir.RIGHT){
$s.SnakeContext.dir = $s.Dir.LEFT;
}
str = "왼쪽";
브레이크;
사례 38 : // up
if($s. SnakeContext.dir != $s.Dir.DOWN){
$s.SnakeContext.dir = $s.Dir.UP;
}
str = "up";
휴식;
사례 39: // 맞음
if($s.SnakeContext.dir != $s.Dir.LEFT){
$s.SnakeContext.dir = $s.Dir.RIGHT;
}
str = "맞아";
break;
사례 40: // down
if($s. SnakeContext.dir != $s.Dir.UP){
$s.SnakeContext.dir = $s.Dir.DOWN;
}
str = "아래로";
휴식;
}
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(); > 🎜>
var loc = $s.Random.randomLocation($s.PANEL_WIDTH - 1, $s.PANEL_HEIGHT - 1);
this.food = new $s.Food(loc .x,loc.y);
},
뱀 : null,
음식 : [],
panelView : null,
food : null,
updateFood : function(){
if(this.food.alive){ // 当前Food还存活
반품;
}
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);
},
중첩: 기능(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){
true를 반환합니다.
}
}
false 반환,
},
hasF ood : 함수(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 : 함수( 활성화){
if(활성화 != $s.DEBUG){
$s.DEBUG = 활성화;
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 : 함수(태그){
if(태그){
태그. style.display = "블록";
}
},
_hide : 기능(태그){
if(태그){
tag.style.display = "없음";
}
},
ondead : function(){ // Snake死亡时回调
if(this._start 대){
this._startBn.disabled = true;
}
if(this._pauseBn){
this._ PauseBn.disabled = true;
}
if(this._stopBn){
this._stopBn.disabled = true;
}
경고("걸림"); "길이:" + this.snake.units.length;
},
_startBn : null,
_pauseBn : null ,
_stopBn : null ,
_restartBn : null,
_len : null
};
})();