javascript 推箱子游戏介绍及问题
最近没什么事情,我的一个亲戚在学校学习PHP,课程中老师让他们编写一个javascript版本的推箱子小游戏,他没什么头绪,就来问我,我当时很闲,就随口答应他包在我身上。结果真正写的时候还是花了点时间,最后写出来的成品也有各种问题,在这里希望大家能一起探讨学习!(大神们请屏蔽鄙人的粗糙简单)
首先看一下最终的效果图,,不好意思,只是做了个简化版本,图中黄色的块是我们控制来推动的盒子,粉红色的块是被推的盒子,红色的块表示最终要被推到的位置,黑色的快表示墙,盒子不能穿过墙,游戏的方向控制使用wasd四个按键,分别表示上下左右,玩起来没有任何意思,这里简述一下盒子推动的思路:
首先,推箱子最少需要两个箱子,一个箱子a用键盘来控制移动,另外一个箱子则是被推动的箱子b,用键盘来控制箱子a移动很简单,使用键盘事件onkeydown,用keyCode来选择你要移动箱子所使用的键,一般常用 wasd这四个键,被推的箱子b如果要实现被推着走,需要两步来完成,第一步是判断两个箱子相碰撞,因为只有当两个箱子配到一起的时候才可能发生推着走的事情,当确定两个箱子碰到以后,我们再次按下前后左右键,我们需要把箱子a移动的距离与之对应的加到箱子b的身上,但这里要判断箱子a移动的方向,如果箱子a是从左边往右边移动20px,那么箱子b也应该向右边移动20px,如果是从箱子a是从上边往下边移动20px,那么箱子b也应该往下方移动20px,以此类推,从右边往左边推和从下边往上边推也是一样的,这样就有推箱子的效果。(大神有其他方法也请告诉小弟,多谢)
第二个问题就是游戏地图的创建,其实我使用的是很常见的一种创建方式,我自己给他取了个名字,叫做数组地图,主要是因为他很形象模拟地图,数组写成什么样子,最后生成的地图就是什么样子,比如
[
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,6,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,4,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,4,4,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,1,1,1,2,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,4,1,1,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
]
这个数组看起来像是一个矩形,实际上就是一个数组,只是我们人为的把他排列成一个矩形的样子,之所以这样做就是为了依照我们排列的样子来创建地图,首先我们看到这个数组里有很多1,还有3,4,2,他们分别表示不同的类型,比如说1表示可以行走的地方,4表示不能行走的地方,3表示箱子a初始化时候的位置,2表示箱子最终要被推到的地方,6表示被推的箱子b初始化的位置,我们在css表里面写好对应的样式,比如 .pos1{width:20px;height:20px;background:#666;float:left}, .pos2{width:20px;height:20px;background:red;float:left}, .pos3{width:20px;height:20px;background:yellow;float:left},.pos4{width:20px;height:20px;background:black;float:left},.pos6{width:20px;height:20px;background:pink;float:left},写好这些样式以后,开始用js循环整个数组,再循环的过程中不断创建div,而每一个div都要给他们一个class,至于这个class是什么则根据数组样式来赋值,比如数组里的第一个值是1,那么对应的样式就是.pos1,如果数组里的样式是2,那么对应的class就是.pos2,以此类推,每创建一个div就把它插入到父盒子里面,因为每一个小div都有浮动属性,他们自然会一个一个排开,最终就会平凑成数组展现出来的样式。这种地图创建方好处就是非常容易修改地图样式,并且可以很直观的修改地图,只要修改数组就等于修改了地图,简单的游戏中常用这种方式。
式。下面是代码:
this.gameBox = document.getElementById('game_box'); //父盒子
for(var i=0;i<this.map.length;i++){
this.litBox = document.createElement('div');
this.litBox.className = "pos"+this.map[i];
this.gameBox.appendChild(this.litBox);
}
第三个问题就是推箱子时候,当箱子遇到class为.pos4的div时候,也就是遇到墙的时候,不能把箱子推过去,这个问题肯定有更好的解决方法,因为我在这个例子中所有的障碍都是用div完成,所以我们看到的那一列或者一黑色竖障碍都是div,我原本希望使用上面说的碰撞检测的方法来处理,但是发现这个方法检测多个连续的元素时候不是很好用,不过也有可能是我用不对,我最终的使用的方法比较愚蠢,将所有的class为.pos4的div全部选中,用循环得到每个div的上下左右值,并把他们放到一个数组里,然后在我们每次按下按键的时候都检测一次当前箱子的位置。并把这个位置拿到数组里面的去循环比较,看看是否有一样的值,如果有一个一样的,那么表示箱子碰到了障碍,只是这种做法比较耗损性能,毕竟在不停的循环检测,所以不是很推荐,不过我暂时也没想出其他方法(求大神赐教!!!)
第四个问题就是,这个例子只是演示了推一个子箱子,实际的游戏中为了增加难度会有很多被推的箱子,至于如何实现,相信大家也有自己的想法了。
/*******以下是整个案例代码(因本人技术有限,大神就当成反面教材吧) 请大家多多指教***************/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Document</title>
<style>
*{margin:0px;padding:0px;}
#game_box{width:500px;height:500px;margin:150px auto;position:relative;}
.pos1{width:20px;height:20px;background: #666;float: left;}
.pos2{width:20px;height:20px;background: red;float: left;}
.pos3{width:20px;height:20px;background:#666;float: left;}
.pos4{width:20px;height:20px;background:black;float: left;}
.pos6{width:20px;height:20px;background: #666;float: left;}
.begin{width:20px;height:20px;background:yellow;position: absolute;top:0;left:0px;z-index:1000;}
.target{width:20px;height:20px;background:pink;position: absolute;top:0;left:0px;z-index:1000;}
</style>
</head>
<body>
<div id="game_box"></div>
</body>
<script>
var game = {
gameBox:0, //外层的大盒子
litBox:0, //里面的每一个小格子
beginLeft:0, //运动的盒子最开始距离左边的距离
beginRight:0, //运动的盒子最开始距离上边的距离
targetLeft:0, //将要推动的盒子最开始距离左边的距离
targetTop:0, //将要推动的盒子最开始距离上边的距离
mObj:0, //运动的盒子元素
mBox:0, //被推动的盒子
prevleft:0, //记录运动的盒子上一步距离左边的位置
prevtop:0, //记录运动的盒子上一步距离上边的位置
pushprevleft:0,
pushprevtop:0,
iftouch:false, //记录是否碰撞到目标盒子
prev:0, //保存之前按下的方向值
direct:0,
last:0,
//地图数组
map:[
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,4,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,4,4,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,1,1,1,2,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,1,1,4,1,1,4,4,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,6,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,4,4,4,4,4,4,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,4,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,4,1,1,1,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,4,4,4,4,1,
1,1,1,1,4,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,4,4,4,4,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
],
//创建地图
createMap:function(){
this.gameBox = document.getElementById('game_box');
for(var i=0;i<this.map.length;i++){
this.litBox = document.createElement('div');
this.litBox.className = "pos"+this.map[i];
this.gameBox.appendChild(this.litBox);
if(this.map[i]==3){
this.beginLeft = this.litBox.offsetLeft;
this.beginRight = this.litBox.offsetTop;
}
if(this.map[i]==6){
this.targetLeft = this.litBox.offsetLeft;
this.targetTop = this.litBox.offsetTop;
}
}
},
//获取class方法
getClass:function(classname,parent){
var par = parent||document;
var pele = par.getElementsByTagName('*');
var arr=[];
for(var i=0;i<pele.length;i++){
var pclass = pele[i].className.split(' ');
for(var j=0;j<pclass.length;j++){
if(pclass[j] == classname){
arr.push(pele[i]);
break;
}
}
}
if(arr.length == 1){
return arr[0];
}else{
return arr;
}
},
//创建将要移动的盒子
createObj:function(){
this.mObj = document.createElement('div');
this.mObj.className = "begin";
this.gameBox.appendChild(this.mObj);
this.mObj.style.left = this.beginLeft+'px';
this.mObj.style.top = this.beginRight+'px';
},
//创建将要被推的盒子
createMbox:function(){
this.mBox = document.createElement('div');
this.mBox.className = "target";
this.gameBox.appendChild(this.mBox);
this.mBox.style.left = this.targetLeft+'px';
this.mBox.style.top = this.targetTop+'px';
},
//控制盒子移动
move:function(obj){
_this = this;
document.onkeydown=function(ev){
_this.prevleft = obj.offsetLeft;
_this.prevtop = obj.offsetTop;
_this.pushprevleft = _this.mBox.offsetLeft;
_this.pushprevtop = _this.mBox.offsetTop;
var oev = ev || event;
var key = oev.keyCode;
if(key == 87){
obj.style.top=obj.offsetTop-20+'px';
}
else if(key == 68){
obj.style.left=obj.offsetLeft+20+'px';
}
else if(key == 83){
obj.style.top=obj.offsetTop+20+'px';
}
else if(key == 65){
obj.style.left=obj.offsetLeft-20+'px';
}
_this.rang(_this.mObj,1);
_this.current(_this.mObj,1);
_this.pushbox(_this.iftouch?key:0);
}
},
rang:function(obj,no2){
if(no2==1){
if(obj.offsetLeft<=0){
obj.style.left=0+'px';
}
if(obj.offsetLeft>=this.gameBox.offsetWidth-this.mObj.offsetWidth){
obj.style.left=this.gameBox.offsetWidth-this.mObj.offsetWidth+'px';
}
if(obj.offsetTop<=0){
obj.style.top=0+'px';
}
if(obj.offsetTop>=this.gameBox.offsetHeight-this.mObj.offsetHeight){
obj.style.top = this.gameBox.offsetHeight-this.mObj.offsetHeight+'px';
}
}
if(no2==2){
if(obj.offsetLeft<0){
obj.style.left=0+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
if(obj.offsetLeft>this.gameBox.offsetWidth-this.mObj.offsetWidth){
obj.style.left=this.gameBox.offsetWidth-this.mObj.offsetWidth+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
if(obj.offsetTop<0){
obj.style.top=0+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
if(obj.offsetTop>this.gameBox.offsetHeight-this.mObj.offsetHeight){
obj.style.top = this.gameBox.offsetHeight-this.mObj.offsetHeight+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
}
},
//不能触碰的区域
forbidden:function(){
var totalBox = this.getClass('pos4');
var arr=[];
for(var i=0;i<totalBox.length;i++){
var json = {};
json.left = totalBox[i].offsetLeft;
json.top = totalBox[i].offsetTop;
json.right = totalBox[i].offsetLeft+20;
json.bottom = totalBox[i].offsetTop+20;
arr.push(json);
}
return arr;
},
//盒子当前的位置判断
current:function(obj,no){
var notouch = this.forbidden();
var curleft = obj.offsetLeft;
var curright = obj.offsetLeft+20;
var curtop = obj.offsetTop;
var curbottom= obj.offsetTop+20;
for(var i =0;i<notouch.length;i++){
if(curleft == notouch[i].left && curtop == notouch[i].top){ //如果碰到黑色的墙就退回到前一步的位置
if(no==1){
obj.style.top = this.prevtop+'px';
obj.style.left = this.prevleft+'px';
}
if(no==2){
obj.style.top = _this.pushprevtop+'px';
obj.style.left = _this.pushprevleft+'px';
this.mObj.style.top = this.prevtop+'px';
this.mObj.style.left = this.prevleft+'px';
}
}
}
},
//检测碰撞
crash:function(){
if(this.mObj.offsetLeft==this.mBox.offsetLeft-20&&this.mObj.offsetTop==this.mBox.offsetTop){
//left
this.iftouch = true;
this.direct = 'left';
this.last=2;
}
else if(this.mObj.offsetLeft==this.mBox.offsetLeft+20&&this.mObj.offsetTop==this.mBox.offsetTop){
//right
this.iftouch = true;
this.direct = 'right';
this.last=2;
}
else if(this.mObj.offsetTop==this.mBox.offsetTop-20&&this.mObj.offsetLeft==this.mBox.offsetLeft){
//top
this.iftouch = true;
this.direct = 'top';
this.last=2;
}
else if(this.mObj.offsetTop==this.mBox.offsetTop+20&&this.mObj.offsetLeft==this.mBox.offsetLeft){
//bottom
this.iftouch = true;
this.direct = 'bottom';
this.last=2;
}
},
//推盒子方法
pushbox:function(key){
this.crash();
//判断回传的keycode是多少来检测用户往哪个方向推箱子
if(key){
if(this.direct == 'left'){ //检测到从左边往右边推箱子
if(key!=68){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.left=this.mBox.offsetLeft+20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
if(this.direct == 'top'){ //检测到从上往下推箱子
if(key!=83){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.top=this.mBox.offsetTop+20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
if(this.direct == 'bottom'){ //检测到从下往上推箱子
if(key!=87){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.top=this.mBox.offsetTop-20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
if(this.direct == 'right'){ //检测到从右往左推箱子
if(key!=65){
this.iftouch = false;
this.crash();
}else{
this.mBox.style.left=this.mBox.offsetLeft-20+'px';
this.current(this.mBox,2);
this.rang(this.mBox,2);
}
}
}
},
//初始化对象
init:function(){
this.createMap();
this.createObj();
this.createMbox();
this.move(this.mObj);
this.forbidden();
}
}
game.init();
</script>
</html>
javascript 推箱子游戏介绍及问题的更多相关文章
- JavaScript 推箱子游戏
推箱子游戏的 逻辑非常简单,但是如果不动手的话,还是不太清楚.我在这里讲一下自己的思路. 制作推箱子,首先要有自己的设计素材.如下我也是网上找的素材 第二步,理清游戏的规则. 游戏规则: 1.小人将箱 ...
- javascript --推箱子
<head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" ...
- JavaScript写一个小乌龟推箱子游戏
推箱子游戏是老游戏了, 网上有各种各样的版本, 说下推箱子游戏的简单实现,以及我找到的一些参考视频和实例: 推箱子游戏的在线DEMO : 打开 如下是效果图: 这个拖箱子游戏做了移动端的适配, 我使用 ...
- OC推箱子
#include<stdio.h> #include<stdlib.h> int main(void) { char sr;//存储用户输入的指令 //绘制地图 char a[ ...
- c语言游戏推箱子
前两天做了推箱子小游戏,看似简单的一个小游戏背后却 有巨大的秘密,这秘密就是一大堆逻辑. 自从学习了函数过后,的确是解决了很多问题,而且调用很方便,尽管我现在都不是很会调用. 写完一个函数,准备测试一 ...
- 用C#制作推箱子小游戏
思路分析: 一.制作一个地图 二.地图中放置墙.箱子.人.目标等 三.让小人动起来完成推箱子动作 游戏制作: 1.按照上述地图制作一个地图 (12行×13列) 地图可以看做是行和列组成的,即可以看做 ...
- hdu.1254.推箱子(bfs + 优先队列)
推箱子 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submis ...
- [游戏模版17] Win32 推箱子 迷宫
>_<:Here introduce a simple game: >_<:resource >_<:only can push a box and finally ...
- [转]Flash ActionScript2.0面向对象游戏开发-推箱子
本文转自:http://www.alixixi.com/Dev/W3C/Flash/2007/2007070868666.html 概述: Flash ActionScript2.0是一种面向对向的编 ...
随机推荐
- mysql之mysql_config_editor
本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn mysql_config_editor允许你把登录的身份验证信息存储 ...
- EF数据迁移,未将对象引用设置到对象实例
现象: 执行Enable-Migrations -force时就报"未将对象引用设置到对象实例"的异常: DbProviderServicesExtensions.GetProvi ...
- 《InsideUE4》UObject(六)类型系统代码生成重构-UE4CodeGen_Private
读的不如写的快 引言 在之前的<InsideUE4>UObject(四)类型系统代码生成和<InsideUE4>UObject(五)类型系统收集章节里,我们介绍了UE4是如何根 ...
- java多线程编程——锁优化
并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问.加锁会带来性能上的损坏,似乎是众所周知的事情.然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程.如 ...
- javascript selenium全套教程发布
为什么有这个系列 目前javascript生态非常丰富,越来越多的人开始用js去做前端的ui测试了.而selenium是web ui测试的标准解决方案,所以一套js的selenium教程是很有必要的. ...
- 剑指offer第三天
21.栈的压入.弹出序列 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3, ...
- hihoCoder 1015 KMP算法
题意:经典字符串匹配算法.给定原串和模式串,求模式串在原串中出现的次数.算法讲解 AC代码 #include <cstdio> #include <cmath> #includ ...
- CodeForces - 788B Weird journey 欧拉路
题意:给定n个点,m条边,问能否找到多少条符合条件的路径.需要满足的条件:1.经过m-2条边两次,剩下两条边1次 2.任何两条路的终点和起点不能相同. 欧拉路的条件:存在两个或者0个奇度顶点. 思路 ...
- poj 2230详解
题目链接 : poj2230 大致题意: 有一个人每晚要检查牛场,牛场内有m条路,他担心会有遗漏,就每条路检查两次,且每次的方向不同,要求你打印他行走的路径(必须从1开始),打印一条即可. 思路分析 ...
- 对于JAVA程序优化的一些想法,读书有感.治疗强迫症良药
在深入了解Java虚拟机里读到:在try{}块里面执行代码,比if(x!=null)效率要高,前提是被catch的几率很低的情况下. 但是 在Effective Java里读到:因为异常机制的设计初衷 ...