1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Document</title>
    8. <style type="text/css">
    9. .container{
    10. width: 200px;
    11. height: 360px;
    12. background-color: antiquewhite;
    13. position: relative;
    14. }
    15. .activity_model{
    16. width: 20px;
    17. height: 20px;
    18. background-color: cornflowerblue;
    19. border: .3px solid rgb(148, 170, 218);
    20. box-sizing: border-box;
    21. position: absolute;
    22. }
    23. .fixed_model{
    24. width: 20px;
    25. height: 20px;
    26. background-color: rgb(75, 79, 92);
    27. border: .3px solid rgb(162, 167, 177);
    28. box-sizing: border-box;
    29. position: absolute;
    30. }
    31. </style>
    32. </head>
    33. <body onload="init();">
    34. <!-- 背景容器 -->
    35. <div id="container" class="container">
    36. <!-- 块元素 -->
    37. </div>
    38. <script>
    39. //创建一个常量控制步长
    40. const STEP = 20;
    41. //定义常量分割容器
    42. const ROW_COUNT = 18,COL_COUNT = 10;
    43. //创建每个模型的数据源(L型)
    44. const MODELS = [
    45. {
    46. 0:{
    47. row:2,
    48. col:0
    49. },
    50. 1:{
    51. row:2,
    52. col:1
    53. },
    54. 2:{
    55. row:2,
    56. col:2
    57. },
    58. 3:{
    59. row:1,
    60. col:2
    61. }
    62. }
    63. ];
    64. //创建变量,存放当前使用的模型
    65. var currentModel = {};
    66. //创建变量标记16宫格的位置
    67. var currentX = 0,currentY = 0;
    68. //记录所有块元素的位置
    69. //k=行_列 : v=块元素
    70. var fixedBlocks = {};
    71. //入口方法
    72. function init(){
    73. createModel();
    74. onKeyDown();
    75. }
    76. //根据模型的数据创建对应的块元素
    77. function createModel(){
    78. //确定当前使用哪一个模型
    79. currentModel = MODELS[0];
    80. //重新初始化16宫格的位置
    81. currentX = 0;
    82. currentY = 0;
    83. //生成对应数量的块元素
    84. for (var key in currentModel){
    85. var divEle = document.createElement("div");
    86. divEle.className = "activity_model";
    87. document.querySelector("#container").appendChild(divEle);
    88. }
    89. //定位块元素的位置
    90. locationBlock();
    91. }
    92. //根据数据源定位块元素的位置
    93. function locationBlock(){
    94. //判断块元素的越界行为
    95. checkBound();
    96. //1.拿到所有的块元素
    97. var eles = document.querySelectorAll(".activity_model");
    98. for (var i = 0;i<eles.length;i++){
    99. //单个块元素
    100. var activityModelEle = eles[i];
    101. //2.找到每个块元素对应的数据
    102. var blockModel = currentModel[i];
    103. //3.根据每个块元素对应的数据来指定块元素的位置
    104. //每个块元素的位置由两个条件决定:1、16宫格所在的位置。 2、块元素在16宫格中的位置
    105. activityModelEle.style.left = (currentX + blockModel.col) * STEP + "px";
    106. activityModelEle.style.top = (currentY + blockModel.row) * STEP + "px";
    107. }
    108. }
    109. //监听用户键盘事件
    110. function onKeyDown(){
    111. document.onkeydown = function(evnet){
    112. switch(event.keyCode){
    113. case 38:
    114. console.log("上");
    115. rotate();
    116. break;
    117. case 39:
    118. console.log("右");
    119. move(1,0);
    120. break;
    121. case 40:
    122. console.log("下");
    123. move(0,1);
    124. break;
    125. case 37:
    126. console.log("左");
    127. move(-1,0);
    128. break;
    129. }
    130. }
    131. }
    132. //控制块元素移动
    133. function move(x,y){
    134. if (isMeet(currentX + x,currentY+y,currentModel)){
    135. //底部的触碰发生在移动16宫格的时候,并且这次移动是因为Y轴的变化引起的
    136. if (y!=0){
    137. //模型之间底部发生触碰
    138. fixedBottomModel();
    139. }
    140. return;
    141. }
    142. //16宫格在动
    143. currentX += x;
    144. currentY += y;
    145. //根据16宫格来重新定位块元素
    146. locationBlock();
    147. }
    148. //控制模型的旋转
    149. function rotate(){
    150. //克隆一下currentModel,这里利用JSON方法完全复制一个currentModel
    151. var json_obj = JSON.stringify(currentModel);
    152. var cloneCurrentModel = JSON.parse(json_obj);
    153. //算法
    154. //旋转后的行 == 旋转前的列
    155. //旋转后的列 == 3-旋转前的行
    156. //遍历我们当前的 模型数据源
    157. for (var key in cloneCurrentModel){
    158. //块元素数据源
    159. var blockModel = cloneCurrentModel[key];
    160. //实现算法
    161. var temp = blockModel.row;
    162. blockModel.row = blockModel.col;
    163. blockModel.col = 3-temp;
    164. }
    165. //如果旋转之后会发生触碰,那么就不需要进行旋转了
    166. if (isMeet(currentX,currentY,cloneCurrentModel)){
    167. return;
    168. }
    169. //接受这次旋转
    170. currentModel = cloneCurrentModel;
    171. locationBlock();
    172. }
    173. //控制模型只能在容器中移动
    174. function checkBound(){
    175. //定义模型活动的边界
    176. var leftBound = 0,rightBound = COL_COUNT,bottomBound = ROW_COUNT;
    177. //当块元素超出边界,让16宫格向后退一步
    178. for (var key in currentModel){
    179. var blockModel = currentModel[key];
    180. //判断左侧越界
    181. if (blockModel.col + currentX < leftBound) {
    182. currentX++;
    183. }
    184. //判断右侧越界
    185. if (blockModel.col + currentX >= rightBound) {
    186. currentX--;
    187. }
    188. //判断底部越界
    189. if (blockModel.row + currentY >= bottomBound){
    190. currentY--;
    191. //把模型固定在底部
    192. fixedBottomModel();
    193. }
    194. }
    195. }
    196. //把模型固定在底部
    197. function fixedBottomModel() {
    198. //1.改变模型(中块元素)的样式
    199. //2.让模型不可以再进行移动
    200. var activityModelEles = document.querySelectorAll(".activity_model");
    201. for (var i = activityModelEles.length - 1;i >= 0;i--){
    202. //更改每个块元素的类名
    203. //由于类名被更改,我们模型移动依靠的就是修改activity_model类的定位,现在不是原类名,自然就无法移动了
    204. activityModelEles[i].className = "fixed_model";
    205. //记录块元素的位置
    206. var blockModel = currentModel[i];
    207. fixedBlocks[(currentY + blockModel.row) + "_" + (currentX + blockModel.col)] = activityModelEles[i];
    208. }
    209. //3.创建新的模型
    210. createModel();
    211. }
    212. //判断模型之间的触碰问题
    213. //X,Y表示16宫格<将要>移动到的位置
    214. //model 表示当前数据源<将要>完成的变化
    215. function isMeet(x,y,model){
    216. //所谓模型之间的触碰,在一个固定位置已经存在一个被固定的元素块时,那么活动中的模型不可以再占用该位置
    217. //判断触碰,就是判断活动中模型<将要移动到的位置>是否已经存在被固定的模型(块元素)了
    218. //如果存在返回true,表示将要移动到的位置会发送触碰,反之返回false
    219. for (var k in model) {
    220. var blockModel = model[k];
    221. //该位置是否已经存在块元素?
    222. if (fixedBlocks[(y + blockModel.row) + "_" + (x + blockModel.col)]){
    223. return true;
    224. }
    225. }
    226. return false;
    227. }
    228. </script>
    229. </body>
    230. </html>