1. 程式人生 > >原生JavaScript實現彈球遊戲

原生JavaScript實現彈球遊戲


開始後的html遊戲介面

開始後可按滑鼠左右鍵移動

擋板,當球擊中磚塊後,磚塊裡面可能藏有魔法棒,當掉落黃色魔法棒時擋板會變短,當掉落綠色魔法棒時擋板會變長。


html頁面佈局,即index.html檔案原始碼如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
		<title>彈球遊戲</title>
		<link rel="stylesheet" type="text/css" href="css/index.css"/>

	</head>
	
	<body>
		<center>
			<div id="gamePanel" tabindex="0">
				<div class="score">分數:
					<span id="score">0</span>
				</div>
				<div id="startBtn" onclick="Start()"></div>				
			</div>
		</center>
		<script type="text/javascript" src="js/magic.js"></script>
		<script type="text/javascript" src="js/brick.js"></script>
		<script type="text/javascript" src="js/ball.js"></script>
		<script type="text/javascript" src="js/stick.js"></script>
		<script type="text/javascript" src="js/game.js"></script>
	</body>
</html>


index.css檔案原始碼如下:

#gamePanel{
				
	width:504px;
	height:504px;
	background:Black;
	position:relative;
				
}
			
#gamePanel .score{
				
	font-size:20px;
	color:White;
	position:absolute;
	left:0;
	top:0;
	z-index:9999;
				
}
			
#gamePanel .bullet{
				
	width:5px;
	height:15px;
	position:absolute;
	background:url(../img/bullet.png);
	overflow:hidden;
				
}
			
#gamePanel .stick{
				
	width:80px;
	height:18px;
	position:absolute;
	background:blue;
				
}
			
#gamePanel .ball{
				
	width:15px;
	height:15px;
	position:absolute;
	background:url(../img/ball.gif);
				
}

#gamePanel .brick {

	width : 28px;
	height : 28px;
	position : relative;
	background : url(../img/brick.gif);
	float : left;

}

#gamePanel .hideBrick {

	width : 28px;
	height : 28px;
	position : relative;
	background : black;
	float : left;

}

#gamePanel .magic {

	width : 27px;
	height : 11px;
	position : absolute;
	background : green;

}

#gamePanel .shortMagic {

	width : 28px;
	height : 12px;
	position : absolute;
	background : yellow;

}
			
#gamePanel .bingo{
				
	width:18px;
	height:18px;
	position:absolute;
	background:url(../img/bingo2.png);
				
}
			
#startBtn{
				
	border-width:20px;
	border-style:solid;
	border-color:Black Black Black Green;
	position:absolute;
	left:240px;
	top:240px;
	cursor:pointer;
	width:0px;
	height:0px;
	overflow:hidden;
				
}

JavaScript部分分為5個原始檔,即ball.js(球類)、brick.js(磚類)、game.js(遊戲類)、magic.js(魔法棒類)、stick.js(擋板類)

球類程式碼實現如下:

// 球類
var Ball = function() {

	// 彈球dom元素
	this.dom = null;
	
	// 是否啟用
	this.isFirst = true;
			
	// 彈球移動方向
	this.direction = null;
	
	this.init();

}

Ball.prototype = {

	// 彈球橫向移動速度
	movepx : 3,
	
	// 彈球縱向移動速度
	movepy : 2,
	
	// 彈球移動頻率
	movesp : 20,	
	
	// 彈球移動頻率對映
	movespMap : {
	
		1 : 75,
		2 : 65,
		3 : 50,
		4 : 40
	
	},
	
	// 初始化
	init : function() {
	
		this.dom = document.createElement("div");
		this.dom.className = "ball";
	
	},
	
	// 設定彈球的初始化位置,x與y座標
	setPosition : function(x, y) {
	
		this.dom.style.left = x + "px";
		this.dom.style.top = y + "px";
			
	},
	
	// 彈球動畫,就是移動,傳入引數為遊戲背景的寬與高
	animation : function(gameWidth, gameHeight, stick) {
	
		var _this = this;
		
		// 實際的橫向移動速度,左或者右
		var _movepx = this.dom.offsetLeft > gameWidth/2 ? -1*this.movepx : this.movepx;
		var _movepy = this.dom.offsetTop > gameHeight/2 ? this.movepy : -1*this.movepy;
		
		// 處理移動函式
		var process = function() {
		
			// 彈球的x,y座標
			var left = _this.dom.offsetLeft;
			var top = _this.dom.offsetTop;
						
			// 是否要調轉方向
			if (left <= 0 || left >= gameWidth - _this.dom.clientWidth) {
			
				_movepx *= -1;
			
			}
			
			var isCrashStick = _this.OnCheckCrashStick();
			var isCrashBall = _this.OnCheckCrashBrick();
			
			// 判斷是否想上調轉方向
			if (top < 0 || isCrashStick || isCrashBall) {
				
				_movepy *= -1;
			
			} 
			
			// 向下移動
			top = top + _movepy;
			left = left + _movepx;
			
			// 設定彈球位置
			_this.dom.style.top = top + "px";
			_this.dom.style.left = left + "px";
			
			if(top > gameHeight) {
			
				_this.onend();
				alert("You Lose");
			
			} else {
				
				setTimeout(process, _this.movesp);			
			
			}
			
			// 判斷彈球移動方向
			if (_movepx > 0 && _movepy < 0) {
			
				_this.direction = "RightUp";
				
				return;
			
			}
			
			if (_movepx > 0 && _movepy > 0) {
			
				_this.direction = "RightDown";
				
				return;
			
			}
			
			if (_movepx < 0 && _movepy < 0) {
			
				_this.direction = "LeftUp";
				
				return;
			
			}
			
			if (_movepx < 0 && _movepy > 0) {
			
				_this.direction = "LeftDown";
				
				return;
			
			}
								
		};
		
		// 開始移動
		process();
	
	},
		
	// 外部介面,檢測是否撞到魔法棒
	OnCheckCrashStick : function() {},
	
	// 外部介面,檢測是否撞到磚塊
	OnCheckCrashBrick : function() {},
	
	// 彈球結束事件
	onend : function() {},
	
	// 遊戲結束
	gameover : function() {}

}

磚類程式碼如下brick.js原始檔:

// 磚類
var Brick = function(gamePanel) {

	// 磚的dom元素
	this.dom = null;
	
	// 磚塊所在的畫布
	this.gamePanel = gamePanel;
		
	// 是否啟用
	this.isLive = true;
	
	// 是否帶有魔法棒
	this.magic = null;
	
	this.width = 28;
	this.height = 28;
	
	this.left = 0;
	this.top = 0;
	
	this.init();

}

Brick.prototype = {

	// 初始化
	init : function() {
	
		this.dom = document.createElement("div");
		this.dom.className = "brick";
						
	},
	
	// 為position: relative的Brick初始化位置
	setPosition : function(x, y) {
	
		this.left = x;
		this.top = y;
	
	},
	
	// 為positon : relative的Brick初始化尺寸
	setSize : function(width, height) {
	
		this.width = width;
		this.height = height;
	
	},
	
	// 初始化生成魔法棒
	initMagic : function() {
	
		var _this = this;
		// 隨機數
		var random = parseInt(Math.random()*1000 + 1, 10);

		var type = random % 5 == 0 ? "good" : random % 4 == 0 ? "bad" : "none";

		// 新建一個魔法棒物件
		var magic = new Magic(type);
		
		this.magic = magic;
	
		magic.initPosition(this);
		
		// 將魔法棒新增進磚塊中
		this.gamePanel.appendChild(magic.dom);
		
		magic.onEnd = function() {
		
			_this.gamePanel.removeChild(magic.dom);
		
		};
		
		magic.animation(this.gamePanel.clientHeight);
		
	},
	
	// 擊中後的動作
	onEnd : function() {
	
		this.isLive = false;
		this.dom.className = "hideBrick";
		this.initMagic();
	
	}

}


魔法棒類程式碼即magic.js原始檔實現如下:

// 魔法棒類
var Magic = function(type) {

	// Magic的dom元素
	this.dom = null;
	
	// Magic的dom資訊
	this.left = 0;
	this.top = 0;
	this.width = 0;
	this.height = 0;
	
	this.type = type;
	
	this.init();

}

Magic.prototype = {

	// 魔法棒型別
	magicType : {
	
		"good" : "magic",
		"bad" : "shortMagic",
		"none" : ""
	
	},
	
	// 每次移動位移
	movepy : 3,
	
	// 移動速度
	movespeed : 20,

	//  初始化魔法棒
	init : function() {
				
		this.dom = document.createElement("div");
				
		this.dom.className = this.magicType[this.type];
		//this.dom.style.display = "none";
		
		this.width = parseInt(this.dom.style.width, 10);
		this.height = parseInt(this.dom.style.height, 10);
	
	},
	
	// 魔法棒初始化位置
	initPosition : function(brick) {
	
		this.left = brick.left;
		this.top = brick.top;
		
		this.dom.style.left = this.left + "px";
		this.dom.style.top = this.top + "px";
	
	},
	
	// 更新位置
	update : function() {
	
		this.dom.style.left = this.left + "px";
		this.dom.style.top = this.top + "px";
	
	},
	
	// 魔法棒動畫,height為遊戲背景高度
	animation : function(height) {
	
		if (this.type == "none") {
		
			return;
		
		}
	
		var _this = this;
		
		// 向下移動函式
		var downMove = function() {

			_this.top = _this.top + _this.movepy;
			_this.update();

			// 判斷魔法棒下移是否越界,是否擊中stick
			if (_this.top < height && !_this.isBeatStick()) {
			
				setTimeout(downMove, _this.movespeed);
			
			} else {
			
				// 動畫結束觸發事件
				_this.onEnd();
			
			}
		
		};
		
		downMove();
	
	},
	
	// 動畫結束觸發事件,外部覆蓋
	onEnd : function() {},
	
	// 魔法棒是否擊中擋板以及擊中後處理事件,外部覆蓋
	isBeatStick : function() {}

}


擋板類程式碼即stick.js原始檔如下:

// 新建棒類
var Stick = function() {

	// 飛機對應的dom元素
	this.dom = null;
	
	// 是否移動中
	this.isMove = false;
	
	// 移動的ID
	this.moveId = null;
	
	// 是否彈球中
	this.isSend = false;
	
	// 變大標記
	this.bigCount = 0;
	
	// 變小標記
	this.smallCount = 0;
	
	// 接棒的寬度變大變小時做儲存
	this.width = 0;
	
	this.init();

}

Stick.prototype = {

	// 遊戲背景Dom
	gamePanel : null,
	
	// 遊戲背景寬度
	gameWidth : 0,
	
	// 遊戲背景高度
	gameHeight : 0,
	
	// 魔法棒移動速度
	movepx : 10,
	
	// 魔法棒移動頻率
	movesp : 30,
	
	// 方向鍵值對應
	keyCodeAndDirection : {
	
		37 : "left",
		39 : "right"
	
	},
	
	// 初始化
	init : function() {
	
		this.dom = document.createElement("div");
		this.dom.className = "stick";
	
	},
	
	// 設定位置
	setPosition : function(gamePanel, width, height) {
		
		// 將魔法棒新增進遊戲背景中
		this.gamePanel = gamePanel;
		this.gamePanel.appendChild(this.dom);
		
		// 設定飛機的初始位置
		this.dom.style.left = (width - this.dom.clientWidth)/2 + "px";
		this.dom.style.top = height - this.dom.clientHeight + "px";
		
		// 獲取到遊戲背景的寬和高
		this.gameWidth = width;
		this.gameHeight = height;
	
	},
	
	// 鍵盤按下事件
	keydown : function(e) {

		var keyCode = e.keyCode;
		
		if (!this.isMove) {
		
			this.move(keyCode);
		
		}
	
	},
	
	// 鍵盤釋放事件
	keyup : function(e) {
	
		// 判斷是否為鍵盤釋放
		if (this.keyCodeAndDirection[e.keyCode]) {
		
			// 停止移動
			this.stopMove();
		
		} else if (e.keyCode == 32) {
		
			// 設定為非發彈中
			this.isSend = false;
		
		}
	
	},
	
	// 移動
	move : function(keyCode) {
	
		// 設定為移動中
		this.isMove = true;
		var _this = this;
		
		// 判斷移動方向
		switch(this.keyCodeAndDirection[keyCode]) {
		
			case "left" : {
				
				this.moveId = setInterval(function() {_this.moveLeft();}, _this.movesp);
				break;
			
			}
			
			case "right" : {
				
				this.moveId = setInterval(function() {_this.moveRight();}, _this.movesp);
				break;
			
			}
			
			default : break;
		
		}
	
	},
	
	// 向左移動
	moveLeft : function() {
	
		var left = this.dom["offsetLeft"];
		left = left - this.movepx >= 0 ? left - this.movepx : 0;
		this.dom.style["left"] = left + "px";
		
		if (left == 0) {
		
			this.stopMove();
		
		}
	
	},
	
	// 向右移動
	moveRight : function() {
	
		var left = this.dom["offsetLeft"];
		var maxDistance = this.gameWidth - this.dom.clientWidth;
		left = left + this.movepx <= maxDistance ? left + this.movepx: maxDistance;
		this.dom.style["left"] = left + "px";
		
		if (left == maxDistance) {
		
			this.stopMove();
		
		}
	
	},
	
	// 變小
	changeSmall : function() {
	
		if (this.smallCount >= 1) {
		
			return;
		
		} else {
		
			this.dom.style.width = 80 + "px";
			this.smallCount ++;
			
			this.bigCount >= 1 ? this.bigCount -- : this.bigCount + 0;
		
		}
		
		this.dom.style.left = parseInt(this.dom.style.left, 10) + 20 + "px";
		this.dom.style.width = 40 + "px";
	
	},
	
	// 變大
	changeBig : function() {
	
		if (this.bigCount >= 1) {
		
			return;
		
		} else {
		
			this.dom.style.width = 80 + "px";
			this.bigCount ++;
			
			this.smallCount >= 1 ? this.smallCount -- : this.smallCount + 0;
		
		}
				
		if (parseInt(this.dom.style.left, 10) <= 75 ) {
						
			this.dom.style.width = parseInt(this.dom.style.width, 10) + 75 + parseInt(this.dom.style.left, 10)+ "px";
			this.dom.style.left = 0 + "px";
			
			return;
		
		} else if (this.dom.style.width + 150 + parseInt(this.dom.style.left, 10) >= this.gamePanel.clientWidth) {
		
			this.dom.style.left = parseInt(this.dom.style.left, 10) - 150 + "px";
			this.dom.style.width = this.dom.style.width + 150 + "px";
			
			return;
		
		} else {
		
			this.dom.style.left = parseInt(this.dom.style.left, 10) - 75 + "px";
			this.dom.style.width = 150 + "px";
		
		}
		
	},
	
	//	停止移動
	stopMove : function() {
	
		this.isMove = false;
		clearInterval(this.moveId);
	
	},
	
	// 發射彈球,外部介面,
	onSendBall : function() {},
	
	
	// 改分數外部介面
	onChangeScore : function() {}

}


部分難點技術實現

通過鍵盤左右方向鍵移動擋板的程式碼實現:

	// 鍵盤按下事件
	keydown : function(e) {

		var keyCode = e.keyCode;
		
		if (!this.isMove) {
		
			this.move(keyCode);
		
		}
	
	},
	
	// 鍵盤釋放事件
	keyup : function(e) {
	
		// 判斷是否為鍵盤釋放
		if (this.keyCodeAndDirection[e.keyCode]) {
		
			// 停止移動
			this.stopMove();
		
		} else if (e.keyCode == 32) {
		
			// 設定為非發彈中
			this.isSend = false;
		
		}
	
	},
	
	// 移動
	move : function(keyCode) {
	
		// 設定為移動中
		this.isMove = true;
		var _this = this;
		
		// 判斷移動方向
		switch(this.keyCodeAndDirection[keyCode]) {
		
			case "left" : {
				
				this.moveId = setInterval(function() {_this.moveLeft();}, _this.movesp);
				break;
			
			}
			
			case "right" : {
				
				this.moveId = setInterval(function() {_this.moveRight();}, _this.movesp);
				break;
			
			}
			
			default : break;
		
		}
	
	},
	
	// 向左移動
	moveLeft : function() {
	
		var left = this.dom["offsetLeft"];
		left = left - this.movepx >= 0 ? left - this.movepx : 0;
		this.dom.style["left"] = left + "px";
		
		if (left == 0) {
		
			this.stopMove();
		
		}
	
	},
	
	// 向右移動
	moveRight : function() {
	
		var left = this.dom["offsetLeft"];
		var maxDistance = this.gameWidth - this.dom.clientWidth;
		left = left + this.movepx <= maxDistance ? left + this.movepx: maxDistance;
		this.dom.style["left"] = left + "px";
		
		if (left == maxDistance) {
		
			this.stopMove();
		
		}
	
	},