用html+js写一个简单的游戏

入驻博客园后的第一篇技术博客,这次来聊聊前端js技术应用。

 

最近接触一款手机游戏:PopStar(消灭星星),第一次在手机上玩就被深深吸引了。玩了几局后发现,想要一路过关斩将,就要想方设法得到更高的分数,所以要么一次消灭更多的星星,要么每一局剩下更少的星星(10个以下有奖励分数,挺可观的)(具体信息上网找攻略,这里不做详述)。

到此,技术宅有了一个自己写PopStar的计划,想到就开始动手 —— 这次选择html页面+js来实现。

GO ...

 

首先,需要知道这款游戏的各种规则,最基本的就是,消灭x个星星,得到(x2 * 5)分数,最后剩下星星数和得分:10(0)、9(380)、8(720)、7(1020) ... 1(1980)、0(2000)[神!星星眼仰望]

好了,首先需要有一个界面,这里就直接参照PopStar的游戏界面,简化了一番,用html写出:

 1 <style type="text/css">

 2 body {

 3  margin: 0;

 4  padding: 0;

 5  font-size: 14px;

 6  font-family: Arial;

 7 }

 8 

 9 .container {

 10  width: 600px;

 11  margin: 10px auto;

 12  border: 1px solid #aaaaaa;

 13  padding: 10px;

 14 }

 15 

 16 .label {

 17  display: inline-block;

 18  padding: 2px 9px;

 19  background-color: rgba(58, 135, 173, 0.75);

 20  color: #ffffff;

 21  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);

 22  white-space: nowrap;

 23  vertical-align: baseline;

 24  -webkit-border-radius: 3px;

 25  -moz-border-radius: 3px;

 26  border-radius: 3px;

 27 }

 28 

 29 .row:after,  30 .box:after {

 31  display: table;

 32  content: "";

 33  line-height: 0;

 34  clear: both;

 35 }

 36 

 37 .stage,  38 .difficulty,  39 .target {

 40  float: left;

 41  width: 33.33333333%;

 42  padding: 5px 0 15px;

 43 }

 44 

 45 .score {

 46  text-align: center;

 47 }

 48 

 49 .message {

 50  height: 30px;

 51  line-height: 30px;

 52  margin: 15px 0 20px;

 53  text-align: center;

 54 }

 55 

 56  .message .selected {

 57  font-size: 10px;

 58  color: #999999;

 59     }

 60 

 61  .message .encourage {

 62  font-size: 16px;

 63  font-weight: bold;

 64     }

 65 

 66 .box {

 67  position: relative;

 68 }

 69 

 70  .box div {

 71         /*position: absolute;*/

 72  cursor: pointer;

 73  -webkit-border-radius: 3px;

 74  -moz-border-radius: 3px;

 75  border-radius: 3px;

 76 

 77         /* for text */

 78  float: left;

 79  width: 58px;

 80  height: 58px;

 81  margin: 1px;

 82     }

 83 

 84 .star-red {

 85  background-color: rgba(255, 0, 0, 0.5);

 86 }

 87 

 88 .star-green {

 89  background-color: rgba(0, 255, 0, 0.5);

 90 }

 91 

 92 .star-blue {

 93  background-color: rgba(0, 0, 255, 0.5);

 94 }

 95 

 96 .star-yellow {

 97  background-color: rgba(255, 255, 0, 0.5);

 98 }

 99 

100 .star-lightblue {

101  background-color: rgba(0, 255, 255, 0.5);

102 }

103 </style>

104 

105 <div class="container">

106     <div class="row">

107         <div class="stage">

108  级数 109             <label id="stage" class="label">1</label>

110         </div>

111         <div class="difficulty">

112  难度 113             <label id="difficulty" class="label">1</label>

114         </div>

115         <div class="target">

116  目标分数 117             <label id="target" class="label">1</label>

118         </div>

119     </div>

120     <div class="score">

121  分数 122         <label id="score" class="label">1</label>

123     </div>

124     <div class="message">

125         <label id="message_selected" class="selected"></label>

126         <label id="message_encourage" class="encourage"></label>

127         <label id="message_failed" class="encourage"></label>

128     </div>

129 

130     <div id="box" class="box">

131         <!-- 100个div标签 -->

132     </div>

133 </div>

用html+js写一个简单的游戏

这里仅聊聊实现逻辑,所以只是用代码简单的设置了5种颜色的星星,也可以用图片做得再漂亮一点。

 

有了界面接下来开始用js来操作。

引入jquery.js文件(比较懒,直接在jq官网down了最新版的,没去比较更新了什么内容),接着设置几个值:

 1 var maps = {  2  xItemCount: 10, // 横排个数  3  yItemCount: 10, // 竖排个数  4  itemMargin: 1,  5  difficulty: 5, // 难度  6  braveScore: { value: 125, message: 'Brave!' }, // 超过125分,鼓励  7  failedMessage: 'Sorry, you are failed!'  8 }  9 var starClass = [ 10  'star-red', 11  'star-blue', 12  'star-yellow', 13  'star-green', 14  'star-lightblue' 15 ]; 16 

17 var Stage = 0, Target, Score = 0; 18 var $selecteditems = []; 19 

20 var $box = $('#box'); 21 $box.css({ height: $box[0].clientWidth }); 22 var boxWidth = $box[0].clientWidth; 23 var itemWidth = boxWidth / maps.xItemCount - maps.itemMargin * 2;

(因为css里只设置了5种星星样式,所以最高难度只到5)

 

接着,需要1个Array的自定义方法exists,用来判断星星Item是否在选择列表中;还需要3个计算分数的方法:_getTarget(获取目标级别的目标分数,原版中目标分数并非以一个相同的数字递增,这里为了方便就采取这种计算方法)、_getScore(根据选择、消灭的星星个数计算得分)、_getAdditionalScore(每局最后计算奖励分数)

 1 Array.prototype.exists = function ($item) {  2  var isIn = false;  3  this.forEach(function ($i) {  4  if ($i.attr('id') === $item.attr('id')) { isIn = true; }  5  });  6  return isIn;  7 };  8 

 9 

10 /* 获取目标分数 */ 11 var _getTarget = function (stage) { 12  if (stage === 1) { return 1000; } 13  else if (stage === 2) { return 2500; } 14  else { return (stage - 1) * 2500 } 15 }; 16 

17 /* 计算得分 */ 18 var _getScore = function () { 19  return $selecteditems.length * $selecteditems.length * 5; 20 } 21 

22 /* 计算奖励分数 */ 23 var _getAdditionalScore = function (count) { 24  if (count >= 10) return 0; 25  else return _getAdditionalScore(count + 1) + (380 - (9 - count) * 40); 26  /* 利用高中数列的计算方法可以得出正确的公式,偷个小懒直接用最简单递归计算得分 */ 27 }

 

然后,需要一个自动生成星星的方法:

随机获取一个大于等于0,小于maps.difficulty的整数

var val = Math.floor(Math.random() * maps.difficulty);

该数值作为每颗星星的值,并获取对应的星星样式(starClass),接着计算星星位置(top、left),这里排列方式为:

从右下角开始,往上堆入一列,再往右堆入第2列 ... ...

用html+js写一个简单的游戏

 1 var _newStage = function () {  2  $('#stage').html(++Stage);  3  Target = _getTarget(Stage);  4  $('#target').html(Target);  5 

 6     for (var x = 0; x < maps.xItemCount; ++x) {  7  for (var y = 0; y < maps.yItemCount; ++y) {  8  var val = Math.floor(Math.random() * maps.difficulty);  9  var top = boxWidth - (itemWidth + maps.itemMargin * 2) * (y + 1); 10  var left = (itemWidth + maps.itemMargin * 2) * x; 11  $box.append( 12  $('<div>', { id: x + '_' + y, 'class': starClass[val], css: { top: top, left: left, width: itemWidth, height: itemWidth } }) 13  .data({ x: x, y: y, value: val }) 14  .click(function () { 15  var $item = $(this); 16 

17  if ($selecteditems.length) { 18  if ($selecteditems.exists($item)) { 19  // 点击的方块在选中的方块列表里面 20  _clearSelectItems(); 21  return; 22  } else { 23  // 点击的方块不在选中的方块列表里面 24  _clearItemStatus(); 25  } 26  } 27 

28  _selectItems($item); 29  _setSelectedItemsStatus(); 30  }) 31  ); 32  } 33  } 34 }

 

试试效果!

用html+js写一个简单的游戏

 

当点击某一颗星星时,有3种情况:

1、原本什么都么有选择($selecteditems.length == 0)

则选择与之相邻(上下左右)的,数值一样的星星。若是数量为1,则取消该次选择;若数量大于等于2,则全部显示选择,并计算出可得分数。

这里通过当前星星Item的ID,依次检查左、右、上、下4颗星星的数值,用递归的方法,一层层寻找,最终取得所有相连且数值相同的星星Item,保存在$selecteditems中。

 1 /* 寻找相邻方块 */  2 var _selectItems = function ($item) {  3  $selecteditems.push($item);  4 

 5  var x = $item.data('x');  6  var y = $item.data('y');  7  var val = $item.data('value');  8 

 9  if (x - 1 >= 0) { 10  var $newItem = $('#' + (x - 1) + '_' + y, $box); 11  if ($newItem.length && $newItem.data('value') === val && !$selecteditems.exists($newItem)) { 12  _selectItems($newItem); 13  } 14  } 15     if (x + 1 < maps.xItemCount) { 16  var $newItem = $('#' + (x + 1) + '_' + y, $box); 17  if ($newItem.length && $newItem.data('value') === val && !$selecteditems.exists($newItem)) { 18  _selectItems($newItem); 19  } 20  } 21  if (y - 1 >= 0) { 22  var $newItem = $('#' + x + '_' + (y - 1), $box); 23  if ($newItem.length && $newItem.data('value') === val && !$selecteditems.exists($newItem)) { 24  _selectItems($newItem); 25  } 26  } 27     if (y + 1 < maps.yItemCount) { 28  var $newItem = $('#' + x + '_' + (y + 1), $box); 29  if ($newItem.length && $newItem.data('value') === val && !$selecteditems.exists($newItem)) { 30  _selectItems($newItem); 31  } 32  } 33 } 34 

35 /* 设置选中方块状态 */ 36 var _setSelectedItemsStatus = function () { 37  if ($selecteditems.length <= 1) { 38  $selecteditems = []; 39         $('#message_selected').empty(); 40  } else { 41  $.each($selecteditems, function () { 42  this.css({ width: itemWidth - 4, height: itemWidth - 4, border: '2px solid rgba(0, 0, 0, 0.6)' }); 43  }); 44 

45  $('#message_selected').html('个数:' + $selecteditems.length + ',分数:' + _getScore()); 46  $('#message_encourage').empty(); 47  } 48 }

用html+js写一个简单的游戏

 

2、原本已有选择($selecteditems.length >= 2),但本次点击的星星不在已选择的星星列表里

则清空已选择的星星状态、列表,并依照1重新检查、计算、选择。

1 /* 清除方块状态 */ 2 var _clearItemStatus = function () { 3  $box.children().css({ width: itemWidth, height: itemWidth, border: 'none' }); 4  $selecteditems = []; 5 }

 

3、原本已有选择($selecteditems.length >= 2),且本次点击的星星在已选择的星星列表里

则需要删除已选择的星星,并重新排列剩余的星星。

 1 /* 移除选中方块 */  2 var _clearSelectItems = function () {  3  var score = _getScore();  4  Score += score;  5  $('#score').html(Score);  6  $('#message_selected').empty();  7 

 8  if (score >= maps.braveScore.value) {  9  $('#message_encourage').html(maps.braveScore.message); 10 

11  setTimeout(function () { 12  $('#message_encourage').empty() 13  }, 2000); 14  } 15 

16  $selecteditems.forEach(function ($i) { 17  $i.fadeOut(0, function () { 18  $i.remove(); 19  }); 20  }); 21  $selecteditems = []; 22 

23  var setX = 0, setY = 0; 24     for (var x = 0; x < maps.xItemCount; ++x) { 25  for (var y = 0; y < maps.yItemCount;) { 26  var $item = $('#' + x + '_' + y, $box); 27 

28  if ($item.length) { 29  if (x != setX || y != setY) { 30  var top = boxWidth - (itemWidth + maps.itemMargin * 2) * (setY + 1); 31  var left = (itemWidth + maps.itemMargin * 2) * setX; 32  $item 33  .attr({ id: setX + '_' + setY }) 34  .data({ x: setX, y: setY }) 35  .animate({ top: top, left: left }, 300); 36  } 37 

38  ++setY; 39  ++y; 40  if (setY >= maps.yItemCount || y >= maps.yItemCount) { 41  ++setX; 42  setY = 0; 43  } 44  } else { 45  ++y; 46  if (y >= maps.yItemCount) { 47  if (setY > 0) { 48  ++setX; 49  } 50  setY = 0; 51  } 52  } 53  } 54  } 55 

56  _checkSingleItems(); 57 }

用html+js写一个简单的游戏

 

已经有效果了!(自己先得瑟一下 :D 玩多一会)

 

最后,在消灭了选择的星星后,需要判断剩余的星星是否是单独的。若不是单独的,则不做任何操作;若是,则需要计算奖励分为多少,算总分后,若不足目标分数,显示失败,否则,清除所有剩余星星,并重新开始下一级别。

 1 /* 检查单个的方块 */  2 var _checkSingleItems = function () {  3  var $items = $box.children();  4  var isSingle = true;  5     for (var i = 0, length = $items.length; i < length; ++i) {  6  _selectItems($($items[i]));  7  var count = $selecteditems.length;  8         $selecteditems = [];  9 

10         if (count > 1) { 11  isSingle = false; 12  break; 13  } 14  } 15 

16  if (isSingle) { 17  setTimeout(function () { 18  var additionalScore = _getAdditionalScore($items.length); 19  Score += additionalScore; 20  $('#score').html(Score); 21 

22  if (additionalScore) { 23  $('#message_encourage').html('Additional Score ' + additionalScore); 24  } 25 

26             if (Score < Target) { 27  $('#message_encourage').empty(); 28  $('#message_failed').html(maps.failedMessage); 29  } else { 30  setTimeout(function () { 31  $('#message_encourage').empty() 32  }, 2000); 33 

34  if ($items.length) { 35  $items.fadeOut(300, function () { 36  $items.remove(); 37  _newStage(); 38  }); 39  } else { 40  _newStage(); 41  } 42  } 43  }, 500); 44  } 45 }

用html+js写一个简单的游戏

 

完成!

基本可以玩了,当然,没有经过系统的测试,肯定会存在许多bug。

(截至博主发布时,已无意点到一个bug了  T-T  不过这里只是技术逻辑的讨论,不再做深层的检查修复)

 

附上下载路径:http://files.cnblogs.com/SugarLSG/PopStar.zip

 


[ 本次探讨只做技术研究,不用于任何商业目的;代码并非出自网络,许多不成熟的地方请各位多多见谅,虚心请教; ]

你可能感兴趣的:(html)