├── .babelrc
├── .gitignore
├── README.md
├── build
└── doBuild.js
├── demo
└── tetris.html
├── dist
└── wzwTetirs.min.js
├── package.json
└── src
├── wzwTetirs.js
├── wzw_levels.js
├── wzw_stufs.js
└── wzw_util.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Kotlin template
3 | # Compiled class file
4 | *.class
5 | .idea/
6 | *.iml
7 | node_modules/
8 |
9 | # Log file
10 | *.log
11 |
12 | # BlueJ files
13 | *.ctxt
14 |
15 | # Mobile Tools for Java (J2ME)
16 | .mtj.tmp/
17 |
18 | # Package Files #
19 | *.jar
20 | *.war
21 | *.nar
22 | *.ear
23 | *.zip
24 | *.tar.gz
25 | *.rar
26 |
27 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
28 | hs_err_pid*
29 |
30 | ### Maven template
31 | target/
32 | pom.xml.tag
33 | pom.xml.releaseBackup
34 | pom.xml.versionsBackup
35 | pom.xml.next
36 | release.properties
37 | dependency-reduced-pom.xml
38 | buildNumber.properties
39 | .mvn/timing.properties
40 | .mvn/wrapper/maven-wrapper.jar
41 |
42 | ### Java template
43 | # Compiled class file
44 | *.class
45 |
46 | # Log file
47 | *.log
48 |
49 | # BlueJ files
50 | *.ctxt
51 |
52 | # Mobile Tools for Java (J2ME)
53 | .mtj.tmp/
54 |
55 | # Package Files #
56 | *.jar
57 | *.war
58 | *.nar
59 | *.ear
60 | *.zip
61 | *.tar.gz
62 | *.rar
63 |
64 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
65 | hs_err_pid*
66 |
67 | ### Linux template
68 | *~
69 |
70 | # temporary files which can be created if a process still has a handle open of a deleted file
71 | .fuse_hidden*
72 |
73 | # KDE directory preferences
74 | .directory
75 |
76 | # Linux trash folder which might appear on any partition or disk
77 | .Trash-*
78 |
79 | # .nfs files are created when an open file is removed but is still being accessed
80 | .nfs*
81 |
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wzwtetris 简介 - intro
2 | 俄罗斯方块 tetris,小时候玩的那种掌上王中王游戏机上就有俄罗斯方块,本项目还原了里面的俄罗斯方块的效果。游戏共有23关,随着游戏越往后进行关卡越高难度越大,下降速度越快。
3 |
4 | # 在线预览 - preview
5 |
6 | 
7 |
8 | [点击立即试玩](https://www.microanswer.cn/tetris.html)
9 |
10 | # 使用 - use
11 |
12 | 通过 jsdelivr,可以快速将 github 上的资源用于cdn公共资源,所以,你可以使用下方的连接将本游戏组件引入你的网页里:
13 |
14 | ```html
15 |
16 | ```
17 |
18 | 然后你就可以愉快的使用了:
19 |
20 | ```html
21 |
22 |
37 | ```
38 |
39 | # 选项配置 - option
40 |
41 | 游戏在外观上提供了许多可配置项,下面列出了`option`支持的所有参数及其默认值, 整个 `option` 都是选填的。
42 |
43 | ```javascript
44 | var option = {
45 | gameWidth: 320, /* 游戏视窗宽度。 */
46 | gameHeight: 430, /* 游戏视窗高度。 */
47 | splitPosition: 222, /* 左边面板和右边面板的分割点,数值以从左到右计算。 */
48 | drawColor1: '#010700', /* 画笔浓颜色 - 就是界面上很黑的那个。 */
49 | drawColor2: '#ccebce', /* 画笔浅颜色 - 就是点阵区域后面你感觉有一层灰色的那个。 */
50 | bgColor: '#dbffdd', /* 背景颜色。 */
51 | lineWidth: 1, /* 画笔粗细 - canvas 绘制时的 lineWidth 参数, 同时它也是 中间分割线的粗细。 */
52 | fontSize: 17, /* 文字大小。 */
53 | fontSpace: 17, /* 文字行间距。 */
54 | atomwidthCount: 10, /* 游戏区域,横向的点阵个数。 */
55 | atomheightCount: 20, /* 游戏区域,竖向的点阵个数。 */
56 | atomSpace: 5, /* 点阵间隙大小。 */
57 | atomBorder: 3, /* 点阵外轮廓粗细。 */
58 | atomInset: 1, /* 点阵中间的间隙大小。 */
59 | useInnerKeyBoardEvent: true /* 是否使用键盘支持。 */
60 | }
61 | ```
62 |
63 | # 方法列表 - methods
64 |
65 | ```javascript
66 |
67 | // 开始游戏。
68 | game.startGame();
69 |
70 | // 暂停游戏,再次调用则恢复游戏。
71 | game.pauseGame();
72 |
73 | // 开启极速模式,开启后会在下一个材料开始的时候自动关闭。你也可以手动调用turboModeOFF方法在当前材料还没下降到底部时提前关闭。
74 | game.turboModeON();
75 |
76 | // 关闭极速模式。
77 | game.turboModeOFF();
78 |
79 | // 旋转变换材料,当材料所处的空间不足以完成旋转时,不会旋转。
80 | game.rotateStuff();
81 |
82 | // 将材料左移动。
83 | game.left();
84 |
85 | // 将材料右移动。
86 | game.right();
87 |
88 | // 复位/重置游戏。
89 | game.resetGame();
90 |
91 | // 获取当前是否暂停状态。
92 | game.isPaused();
93 |
94 | // 获取当前成绩。
95 | game.getScore();
96 |
97 | // 获取当前等级。
98 | game.getLevel();
99 |
100 | // 获取当前正在下落的材料,可能是 null。
101 | game.getCuffStuf();
102 |
103 | ```
104 |
105 |
106 | # 博文 - blog
107 |
108 | [立即查看博文](https://www.microanswer.cn/blog/68)
109 |
110 | # 历史版本 - history
111 |
112 | - 1.0.3 公共文件已转为es5格式代码,之前版本的都是夹杂着部分es6语法可能运行不正常。
113 | - 1.0.2 修复暂停后还能左右移动、变型的BUG。优化代码结构。
114 | - 1.0.1 (1)修复堆砌到顶部后,再消一行,顶部的材料没有跟随下落。(2)加入一次消除4行则多加一分的加分逻辑。
115 | - 1.0.0 发布第一版本。
--------------------------------------------------------------------------------
/build/doBuild.js:
--------------------------------------------------------------------------------
1 | let webpack = require("webpack");
2 | let path = require("path");
3 |
4 | const webpackCfg = {
5 | entry: "./src/wzwTetirs.js",
6 | output: {
7 | path: path.resolve(__dirname, '../dist'),
8 | filename: 'wzwTetirs.min.js'
9 | },
10 | mode: 'production',
11 | module: {
12 | rules: [
13 | { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
14 | ]
15 | }
16 | };
17 |
18 | console.log("开始...");
19 | webpack(webpackCfg, function (er, stats) {
20 | if (er) {
21 | console.log("出错了:", er);
22 | } else {
23 | console.log("完成:", stats.toString());
24 | }
25 | });
--------------------------------------------------------------------------------
/demo/tetris.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 俄罗斯方块 - Microanswer
8 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | 开始
129 | 暂停
130 | 复位
131 |
132 |
133 |
134 |
135 | 玩法介绍:
136 | 1.点击[开始]按钮开始新游戏。
137 | 2.游戏过程可以点击[暂停]。
138 | 3.[复位]按钮可以重置游戏到初始状态。
139 | 4.如果你用电脑,可以使用方向键来控制。
140 | [W、↑]变型,[S、↓]下降,[A、←]左,[D、→]右
141 |
142 |
143 | 关于:
144 | 作者:Microanswer
145 | 首页:www.microanswer.cn
146 | 源码:查看源码
147 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/dist/wzwTetirs.min.js:
--------------------------------------------------------------------------------
1 | !function(n){var t={};function e(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return n[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}e.m=n,e.c=t,e.d=function(n,t,o){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(e.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var r in n)e.d(o,r,function(t){return n[t]}.bind(null,r));return o},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){var o=e(1),r=e(2),i=r.LEVELS,a=r.SCORE_LEVELS,l=e(3);window.WzwTetirs=function(n,t){(t=t||{}).hasOwnProperty("useInnerKeyBoardEvent")||(t.useInnerKeyBoardEvent=!0);var e,r,f=t.gameWidth||320,u=t.gameHeight||430,c=t.splitPosition||222,s=t.drawColor1||"#010700",h=t.drawColor2||"#ccebce",d=t.bgColor||"#dbffdd",m=t.lineWidth||1,v=t.fontSize||17,g=t.fontSpace||17,p=t.atomwidthCount||10,w=t.atomheightCount||20,y=null,S=null,b=t.atomSpace||5,x=t.atomBorder||3,T=t.atomInset||1,C=3,k=-3,E=null,P=null,O=null,A=null,F=null,L=!1,N=!1,q=!0,M=!1,j=0,R=0,_=0,W={87:function(){Q()},38:function(){Q()},83:function(){H()},40:function(){H()},65:function(){U()},37:function(){U()},68:function(){X()},39:function(){X()},32:function(){Q()}},I={83:function(){J()},40:function(){J()}};function B(){var n=Math.floor(Math.random()*o.length);return[].concat(o[n])}function D(n){if(O&&E&&A&&!M){for(var t=C+n,e=0;ep-1&&(t=p-o-1),!(k+e<0)&&1===A[k+e][t+o]))return;O=G(t,k,E),C=t}}function V(){for(var n=[],t=0;t=4&&(R+=1);var r=a[String(R)];r>_&&(_=r)}}var i=!1;l.each(n,(function(t,e){l.scroll(0,O[e].length-1,{goo:function(n){var t=O[e].length;n=n>=t?t:n;for(var o=0;o0;){var t=n.shift();l.eachNum(t,1,(function(n){var t=n-1;A[n]=[].concat(A[t]),0===t&&(A[t]=[],l.eachNum(0,p-1,(function(n){A[t][n]=0})))}))}N=!1,O=l.arrCopy(A)}),50))}},200)}))}function G(n,t,e){for(var o=l.arrCopy(A),r=0;r=w||1!==e[r][i]||(o[t+r][n+i]=e[r][i]);return o}function K(n,t,e,o,r,i){var a=n+e*(b+y)-y,l=t+o*(b+S)-S,f=r.strokeStyle,u=r.lineWidth,c=r.fillStyle;r.strokeStyle=i,r.fillStyle=i,r.lineWidth=x,r.beginPath(),r.rect(a,l,y,S),r.stroke(),r.fillRect(a+x+T,l+x+T,y-2*x-2*T,S-2*x-2*T),r.strokeStyle=f,r.lineWidth=u,r.fillStyle=c}function z(n){n.strokeStyle=s,n.fillStyle=d,n.lineCap="butt",n.lineWidth=m,n.clearRect(0,0,f,u),n.fillStyle=s,function(n){for(var t=1;t<=p;t++)for(var e=1;e<=w;e++)K(0,0,t,e,n,h);if(O)for(t=0;t=0;t--)if(F[t])for(e=F[t].length-1;e>=0;e--)1===F[t][e]&&K(0,0,e+1,t+1,n,s)}(n),n.beginPath(),n.moveTo(c,0),n.lineTo(c,u),n.stroke(),n.closePath(),function(n){var t=v;n.font="italic normal normal "+v+"px arial",n.fillText("Score",c+b,t),n.font="normal normal bold "+v+"px arial",t+=v,n.fillText(String(R),c+b,t),n.font="italic normal normal "+v+"px arial",t=t+v+g,n.fillText("Next",c+b,t);for(var e=1;e<=4;e++)for(var o=1;o<=4;o++)if(K(c,t,e,o,n,h),P){if(1!==P[o-1][e-1])continue;K(c,t,e,o,n,s)}n.font="italic normal normal "+v+"px arial",t=t+v+g+4*(S+b),n.fillText("Level",c+b,t),n.font="normal normal bold "+v+"px arial",t+=v,n.fillText(String(_),c+b,t),n.font="italic normal normal "+v+"px arial",t=t+v+g,n.fillText("Best",c+b,t),n.font="normal normal bold "+v+"px arial",t+=v,n.fillText(String(j),c+b,t),M&&(n.font="italic normal normal "+v+"px arial",t=t+v+g,n.fillText("Paused",c+b,t))}(n)}function H(){O&&E&&(L=!0)}function J(){L=!1}function Q(){if(O&&E&&!M){for(var n=[[],[],[],[]],t=0;t=w)return;if(C+r>=p||C+r<0)return;if(1===A[k+o][C+r])return}}O=G(C,k,E=n)}}function U(){D(-1)}function X(){D(1)}function Y(){var n;q||(q=!0,R>j&&(j=R,window.localStorage&&window.localStorage.setItem("bestscore",j)),n=function(){q=!0,O=null,A=null,E=null,P=null,N=!1,L=!1,R=0,_=0,C=3,k=-3},l.scroll(w,0,{goo:function(n){n=n>w-1?w-1:n,F||(F=new Array(w)),l.eachNum(n,w-1,(function(n){F[n]=[],l.eachNum(0,p-1,(function(t){F[n][t]=1}))}))},end:function(t){l.eachNum(0,w-1,(function(n){F[n]=[],l.eachNum(0,p-1,(function(t){F[n][t]=1}))})),n&&n(),setTimeout((function(){l.scroll(0,w-1,{goo:function(n){n=n>w-1?w-1:n,l.eachNum(0,n,(function(n){F[n]=void 0}))},end:function(n){F=null}})}),100)}}))}e=function(n){var t=document.createElement("canvas");t.width=f,t.height=u,n.appendChild(t);var e=t.getContext("2d");return e.width=f,e.height=u,e.canvas.width=f,e.canvas.height=u,e.translate(.5,.5),e}(function(n){var t=document.querySelector("#"+n);return t.style.width=f+"px",t.style.height=u+"px",t.style.border="1px solid gray",t.style.backgroundColor=d,t}(n)),function(){var n=c-m;y=(n-=b*(p+1))/p;var t=u;S=(t-=b*(w+1))/w,j=window.localStorage&&window.localStorage.getItem("bestscore")||0}(),t.useInnerKeyBoardEvent&&(document.onkeydown=function(n){var t=W[String(n.keyCode)];t&&(n.stopPropagation(),t())},document.onkeyup=function(n){var t=I[String(n.keyCode)];t&&(n.stopPropagation(),t())}),r=e,function n(){z(r),window.requestAnimationFrame?window.requestAnimationFrame(n):window.webkitRequestAnimationFrame?window.webkitRequestAnimationFrame(n):setTimeout(n,33)}(),this.startGame=function(){if(q){q=!1,O=[],A=[];for(var n=0;n=(L?3:i[_])){var t=!1;E||(E=P,P=null,t=!!E),E||(E=B(),P=null,t=!!E),P||(P=B(),t=!!E),t&&J();var o=function(n,t,e,o,r){var i=!1;n:for(var a=e.length-1;a>=0;a--)for(var f=e[a].length-1;f>=0;f--)if(1===e[a][f]){var u=t+a;if(!(u<0)){var c=n+f;if(!(c<0)){if(u!==w-1&&1!==r[u+1][c]||(i=!0),0===u&&i)return-1;if(i)break n}}}return i||(t=k=t+1,o=O=G(n,t,e)),i&&(A=l.arrCopy(o)),i?1:0}(C,k,E,O,A);1===o?(E=null,C=3,k=-3,V()):-1===o&&Y(),e=Date.now()}q||(window.requestAnimationFrame?window.requestAnimationFrame(n):window.webkitRequestAnimationFrame?window.webkitRequestAnimationFrame(n):setTimeout(n,5))}()}},this.pauseGame=function(){!q&&O&&A&&(M=!M)},this.turboModeON=H,this.turboModeOFF=J,this.rotateStuff=Q,this.left=U,this.right=X,this.resetGame=Y,this.isPaused=function(){return M},this.getScore=function(){return R},this.getLevel=function(){return R},this.getCuffStuf=function(){return E}}},function(n,t){n.exports=[[[0,0,0,0],[0,0,0,0],[1,1,1,1],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[1,1,1,1],[0,0,0,0]],[[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]],[[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]],[[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,0,0],[0,1,1,1],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[0,1,0,0],[0,1,0,0]],[[0,0,0,0],[0,1,1,1],[0,0,0,1],[0,0,0,0]],[[0,0,0,0],[0,0,1,0],[0,0,1,0],[0,1,1,0]],[[0,0,0,0],[0,1,1,1],[0,1,0,0],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[0,0,1,0],[0,0,1,0]],[[0,0,0,0],[0,0,0,1],[0,1,1,1],[0,0,0,0]],[[0,1,0,0],[0,1,0,0],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,1,1],[0,0,1,0],[0,0,0,0]],[[0,0,0,0],[0,0,1,0],[0,1,1,0],[0,0,1,0]],[[0,0,0,0],[0,0,1,0],[0,1,1,1],[0,0,0,0]],[[0,0,0,0],[0,0,1,0],[0,0,1,1],[0,0,1,0]],[[0,0,0,0],[0,1,1,0],[0,0,1,1],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[0,0,1,1],[0,0,0,0]],[[0,0,0,0],[0,0,1,0],[0,1,1,0],[0,1,0,0]],[[0,0,0,0],[0,0,1,0],[0,1,1,0],[0,1,0,0]],[[0,0,0,0],[0,0,1,1],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,0,1,1],[0,1,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,0,0],[0,1,1,0],[0,0,1,0]],[[0,0,0,0],[0,1,0,0],[0,1,1,0],[0,0,1,0]]]},function(n,t){n.exports={LEVELS:[800,700,600,550,500,450,400,350,300,250,200,150,130,100,90,80,70,60,50,40,30,20,10,5],SCORE_LEVELS:{50:1,100:2,150:3,200:4,250:5,300:6,350:7,400:8,450:9,500:10,550:11,600:12,700:13,850:14,1e3:15,1100:16,1300:17,1500:18,2e3:19,2500:20,3e3:21,4e3:22,5e3:23}}},function(n,t){n.exports=new function(){this.scroll=function(n,t,e,o){var r=n,i=r=r||0,a=t-i;if(0!==a){var l=!1,f=o||500,u=Date.now();!function n(){setTimeout((function(){var o=Date.now()-u,r=o/f,c=Math.ceil(i+r*a);l||e&&e.goo&&e.goo(c),f<=o?(l=!0,e.end(t)):setTimeout(n,1e3/60)}),1e3/60)}()}else e&&e.end&&e.end(t)},this.printArr=function(n){var t="";this.each(n,(function(n,e){t+=n+":"+e.join(" ")+"\n"})),console.log(t)},this.arrCopy=function(n){for(var t=[],e=0;et)for(var o=n;o>=t;o--)e&&e(o);else for(o=n;o<=t;o++)e&&e(o)},this.each=function(n,t){for(var e=0;e atomheightCount - 1) ? atomheightCount - 1 : val;
170 | if (!resetAtoms) {resetAtoms = new Array(atomheightCount);}
171 | Util.eachNum(val, atomheightCount - 1, function (row) {
172 | resetAtoms[row] = [];
173 | Util.eachNum(0, atomwidthCount - 1, function (num) {
174 | resetAtoms[row][num] = 1;
175 | });
176 | });
177 | },
178 | end: function (end) {
179 | Util.eachNum(0, atomheightCount - 1, function (row) {
180 | resetAtoms[row] = [];
181 | Util.eachNum(0, atomwidthCount - 1, function (num) {
182 | resetAtoms[row][num] = 1;
183 | });
184 | });
185 | cb && cb();
186 |
187 | setTimeout(function () {
188 | Util.scroll(0, atomheightCount - 1, {
189 | goo: function (val) {
190 | val = (val > atomheightCount - 1) ? atomheightCount - 1 : val;
191 |
192 | Util.eachNum(0, val, function (row) {
193 | resetAtoms[row] = undefined;
194 | });
195 | },
196 | end: function (end) {
197 | resetAtoms = null;
198 | }
199 | });
200 | }, 100);
201 | }
202 | })
203 | }
204 |
205 | /* 重置游戏。 */
206 | function _resetGame () {
207 | gameover = true;
208 | gameAtoms = null;
209 | staticStuffs = null;
210 | currStuff = null;
211 | nextStuff = null;
212 | succAniming = false;
213 | turbo = false;
214 | score = 0;
215 | level = 0;
216 | stuffOffsetX = STUFF_START_X_OFFSET;
217 | stuffOffsetY = STUFF_START_Y_OFFSET;
218 | }
219 |
220 | /* 移动当前正在掉落的材料。 count 为移动几格,负数则是左移。 */
221 | function _moveCurrStuff (count) {
222 | if (gameAtoms && currStuff && staticStuffs && (!pause)) {
223 | var targetOffsetX = stuffOffsetX + count;
224 |
225 | for (var i = 0; i < currStuff.length; i++) {
226 | for (var j = 0; j < currStuff[i].length; j++) {
227 | if (currStuff[i][j] !== 1) {
228 | continue;
229 | }
230 | if (targetOffsetX + j < 0) {
231 | /* 传入的目标位数会导致移动到屏幕左边的外面。则强制让其在屏幕内。 */
232 | targetOffsetX = -j;
233 | } else if (targetOffsetX + j > atomwidthCount - 1) {
234 | /* 传入的目标位数会导致移动到屏幕右边的外面。则强制让其在屏幕内。 */
235 | targetOffsetX = atomwidthCount - j - 1;
236 | }
237 |
238 | /* 材料还没完全下降到屏幕内 */
239 | if (stuffOffsetY + i < 0) continue;
240 |
241 | /* 判断新位置上是否有材料了,有就不能进行移动 */
242 | if (staticStuffs[stuffOffsetY + i][targetOffsetX + j] === 1) {
243 | return;
244 | }
245 |
246 | }
247 | }
248 |
249 | gameAtoms = _addStuffToGameAtoms(targetOffsetX, stuffOffsetY, currStuff);
250 | stuffOffsetX = targetOffsetX;
251 | }
252 | }
253 |
254 | /* 检查堆砌成功的行,并进行消除。 */
255 | function checkSuccessLine() {
256 |
257 | var successLine = [];
258 |
259 | for (var i = 0; i < staticStuffs.length; i++) {
260 |
261 | var isSuccess = true;
262 | for (var j = 0; j < staticStuffs[i].length; j++) {
263 | if (staticStuffs[i][j] !== 1){
264 | isSuccess = false;
265 | break;
266 | }
267 | }
268 |
269 |
270 | /* 成功一行就+1分*/
271 | if (isSuccess) {
272 | succAniming = true;
273 | score += 1;
274 | successLine.push(i);
275 |
276 | /* 如果一次消了4行,再加1分 */
277 | if (successLine.length >= 4) {
278 | score += 1;
279 | }
280 |
281 | /*提升等级*/
282 | var newLevel = SCORE_LEVELS[String(score)];
283 | if (newLevel > level) {
284 | level = newLevel;
285 | }
286 | }
287 | }
288 |
289 |
290 | var ended = false;
291 | var onAnimEnd = function () {
292 | if (ended) {
293 | return;
294 | }
295 | ended = true;
296 |
297 | setTimeout(function () {
298 | /*动画完成后重整数组,将消除的行上面的依次向下整理*/
299 | while (successLine.length > 0) {
300 | var rowm = successLine.shift();
301 | Util.eachNum(rowm, 1, function (row) {
302 | var lastRow = row - 1;
303 |
304 | staticStuffs[row] = [].concat(staticStuffs[lastRow]);
305 |
306 | if (lastRow === 0) {
307 | staticStuffs[lastRow] = [];
308 | Util.eachNum(0, atomwidthCount - 1, function (num) {
309 | staticStuffs[lastRow][num] = 0;
310 | });
311 |
312 | }
313 | });
314 | }
315 | succAniming = false;
316 | gameAtoms = Util.arrCopy(staticStuffs);
317 | }, 50);
318 | };
319 |
320 | /* 在数组里将消除的行全部置为0,通过此操作使得界面上的行有个从左到右消减的动画 */
321 | Util.each(successLine, function (index, value) {
322 | Util.scroll(0, gameAtoms[value].length - 1, {
323 | goo: function (process) {
324 | var l = gameAtoms[value].length;
325 | /*scroll方法有bug吗,process应该在to范围内啊,但是出现了超过to的现象,所以这里判断一下*/
326 | process = process >= l ? l : process;
327 | for (var j = 0; j < process; j++) {
328 | gameAtoms[value][j] = 0;
329 | }
330 | },
331 | end: function (end) {
332 | for (var j = 0; j < gameAtoms[value].length; j++) {
333 | gameAtoms[value][j] = 0;
334 | }
335 |
336 | /* 将消除的行剩下的重整 */
337 | onAnimEnd();
338 | }
339 | }, 200);
340 | });
341 | }
342 |
343 | /* 将 currStuff 材料通过指定的横向偏移量 stuffOffsetX和stuffOffsetY 进行融合,并将 stuffOffsetY 下降1格。*/
344 | /* 如果 currStuff 材料已经到达了 gameAtoms 底部或已有材料的底部将返回 1, 检查游戏结束将返回 -1,其他的放回0表示正常。 */
345 | function _GameArrMerge (stuffOffsetX, mStuffOffsetY, currStuff, mGameAtoms, mStaticStuffs) {
346 |
347 | var grounded = false;
348 |
349 | w:for (var i = currStuff.length - 1; i >= 0 ; i--) {
350 | for (var j = currStuff[i].length - 1; j >= 0; j--) {
351 | if (currStuff[i][j] !== 1) continue;
352 | /* 判断此元素下降一格后是否触底 */
353 |
354 |
355 | var c_stuffOffsetY = mStuffOffsetY + i;
356 | if (c_stuffOffsetY < 0) continue;
357 |
358 | var c_stuffOffsetX = stuffOffsetX + j;
359 | if (c_stuffOffsetX < 0) continue;
360 |
361 | /* 素材达到最低边, 或素材下一个位置有已确认的素材,则认为到底了。 */
362 | if (c_stuffOffsetY === atomheightCount - 1 || mStaticStuffs[c_stuffOffsetY + 1][c_stuffOffsetX] === 1) {
363 | grounded = true;
364 | }
365 |
366 | /* 素材本身出现的位置都已经是頂部了,这绝逼是玩家玩到顶了。 */
367 | if (c_stuffOffsetY === 0 && grounded) {
368 | /* 游戏结束 */
369 | return -1;
370 | }
371 |
372 | if (grounded) {
373 | break w;
374 | }
375 | }
376 | }
377 |
378 | /* 将 currStuff 融合到 mGameAtoms 里面 */
379 | if (!grounded) {
380 | mStuffOffsetY = stuffOffsetY = mStuffOffsetY + 1;
381 | mGameAtoms = gameAtoms = _addStuffToGameAtoms(stuffOffsetX, mStuffOffsetY, currStuff);
382 | }
383 |
384 | /* 如果触底了,则将 mGameAtoms 保存一份为 mStaticStuffs */
385 | if (grounded) {
386 | staticStuffs = Util.arrCopy(mGameAtoms);
387 | }
388 |
389 |
390 | return grounded ? 1 : 0;
391 | }
392 |
393 | /* 将指定stuff 添加到 游戏数组 staticStuffs 里面,按照指定位置添加,然后返回添加完成的结果,这个结果预期是赋值给gameAtoms的。 */
394 | /* 本方法本身不会修改 staticStuffs。 */
395 | function _addStuffToGameAtoms (stuffOffsetX, stuffOffsetY, stuff) {
396 | var mGameAtoms = Util.arrCopy(staticStuffs);
397 |
398 | for (var i = 0; i < stuff.length; i++) {
399 | for (var j = 0; j < stuff[i].length; j++) {
400 | if (
401 | stuffOffsetY + i < 0 ||
402 | stuffOffsetX +j < 0 ||
403 | stuffOffsetY + i >= atomheightCount ||
404 | stuff[i][j] !== 1
405 | ) {
406 | continue;
407 | }
408 | mGameAtoms[stuffOffsetY + i][stuffOffsetX + j] = stuff[i][j];
409 | }
410 | }
411 |
412 | return mGameAtoms;
413 | }
414 |
415 | /* startX 所有点阵起始计算横坐标点。 */
416 | /* startY 所有点阵起始计算竖坐标点。 */
417 | /* 绘制一个点阵,通过 2 个index下标确定绘制具体哪一个点阵。 */
418 | /* 下标的数值规则是:从左上角到右上交 widthIndex 1~10。 */
419 | /* 从左上角到左下交 heightIndex 1~20。 */
420 | /* c 绘制颜色。 */
421 | function renderAtom (startX, startY, widthIndex, heightIndex, ctx, c) {
422 | var x = startX + (widthIndex * (atomSpace + atomWidth)) - atomWidth;
423 | var y = startY + (heightIndex * (atomSpace + atomHeight)) - atomHeight;
424 |
425 | var osc = ctx.strokeStyle;
426 | var osw = ctx.lineWidth;
427 | var ofc = ctx.fillStyle;
428 | ctx.strokeStyle = c;
429 | ctx.fillStyle = c;
430 | ctx.lineWidth = atomBorder;
431 | ctx.beginPath();
432 | ctx.rect(x, y, atomWidth, atomHeight);
433 | ctx.stroke();
434 |
435 | ctx.fillRect(
436 | x + atomBorder + atomInset,
437 | y+atomBorder+atomInset,
438 | atomWidth-(2*atomBorder)-(2*atomInset),
439 | atomHeight-(2*atomBorder)-(2*atomInset)
440 | );
441 |
442 | ctx.strokeStyle = osc;
443 | ctx.lineWidth = osw;
444 | ctx.fillStyle = ofc;
445 | }
446 |
447 | /* 绘制左边游戏面板。 */
448 | function renderLeft (ctx) {
449 | /* 先绘制点阵背景 */
450 | for (var i = 1; i <= atomwidthCount; i++) {
451 | for (var j = 1; j <= atomheightCount; j++) {
452 | renderAtom(0, 0, i,j, ctx, drawColor2);
453 | }
454 | }
455 |
456 | /* 绘制游戏数组 */
457 | if (gameAtoms) {
458 | for (i = 0; i < gameAtoms.length; i++) {
459 | for (j = 0; j < gameAtoms[i].length; j++) {
460 | if (gameAtoms[i][j] !== 1) continue;
461 | renderAtom(0, 0, j + 1, i + 1, ctx, drawColor1);
462 | }}
463 | }
464 |
465 |
466 | /* 绘制重置动画 */
467 | if (resetAtoms) {
468 | for (i = resetAtoms.length - 1; i >= 0; i--) {
469 | if (resetAtoms[i]) {
470 | for (j = resetAtoms[i].length - 1; j >= 0 ; j--) {
471 | if (resetAtoms[i][j] !== 1) continue;
472 | renderAtom(0, 0, j + 1, i + 1, ctx, drawColor1);
473 | }
474 | }
475 | }
476 | }
477 | }
478 |
479 | /* 绘制右边 下一个方块,游戏成绩。 */
480 | function renderRight (ctx) {
481 |
482 | /* 绘制游戏成绩 */
483 | var yOffset = fontSize;
484 | ctx.font = "italic normal normal " + fontSize + "px arial";
485 | ctx.fillText("Score", splitPosition + atomSpace, yOffset);
486 | ctx.font = "normal normal bold " + fontSize + "px arial";
487 | yOffset = yOffset + fontSize;
488 | ctx.fillText(String(score), splitPosition + atomSpace, yOffset);
489 |
490 | ctx.font = "italic normal normal " + fontSize + "px arial";
491 | yOffset = yOffset + fontSize + fontSpace;
492 | ctx.fillText("Next", splitPosition + atomSpace, yOffset);
493 | /* 绘制接下来要使用的材料。 */
494 | for (var i = 1; i <= 4; i++) {
495 | for (var j = 1; j <= 4; j++) {
496 | /* 绘制背景 */
497 | renderAtom(splitPosition, yOffset, i, j, ctx, drawColor2);
498 |
499 | /* 绘制预备材料 */
500 | if (nextStuff) {
501 | if (nextStuff[j - 1][i - 1] !== 1) continue;
502 | renderAtom(splitPosition, yOffset, i, j, ctx, drawColor1);
503 | }
504 | }
505 | }
506 |
507 | /* 绘制等级 */
508 | ctx.font = "italic normal normal " + fontSize + "px arial";
509 | yOffset = yOffset + fontSize + fontSpace + (4 * (atomHeight + atomSpace));
510 | ctx.fillText("Level", splitPosition + atomSpace, yOffset);
511 | ctx.font = "normal normal bold " + fontSize + "px arial";
512 | yOffset = yOffset + fontSize;
513 | ctx.fillText(String(level), splitPosition + atomSpace, yOffset);
514 |
515 | /* 绘制最佳成绩 */
516 | ctx.font = "italic normal normal " + fontSize + "px arial";
517 | yOffset = yOffset + fontSize + fontSpace;
518 | ctx.fillText("Best", splitPosition + atomSpace, yOffset);
519 | ctx.font = "normal normal bold " + fontSize + "px arial";
520 | yOffset = yOffset + fontSize;
521 | ctx.fillText(String(bestscore), splitPosition + atomSpace, yOffset);
522 |
523 | /* 绘制暂停提示 */
524 | if (pause) {
525 | ctx.font = "italic normal normal " + fontSize + "px arial";
526 | yOffset = yOffset + fontSize + fontSpace;
527 | ctx.fillText("Paused", splitPosition + atomSpace, yOffset);
528 | }
529 | }
530 |
531 | /* 此方法会被循环调用,用于绘制游戏内容。 */
532 | function onRender (ctx) {
533 | ctx.strokeStyle = drawColor1;
534 | ctx.fillStyle = bgColor;
535 | ctx.lineCap = 'butt';
536 | ctx.lineWidth = lineWidth;
537 | ctx.clearRect(0, 0, gameWidth, gameHeight);
538 | ctx.fillStyle = drawColor1;
539 |
540 | /* 绘制游戏区域 */
541 | renderLeft(ctx);
542 |
543 | /* 绘制分割线 */
544 | ctx.beginPath();
545 | ctx.moveTo(splitPosition, 0);
546 | ctx.lineTo(splitPosition, gameHeight);
547 | ctx.stroke();
548 | ctx.closePath();
549 |
550 | /* 绘制右边状态值区域 */
551 | renderRight(ctx);
552 | }
553 |
554 | /* 开始执行绘制。 */
555 | function render (ctx) {
556 | (function loop () {
557 | onRender(ctx);
558 | if (window.requestAnimationFrame) {
559 | window.requestAnimationFrame(loop);
560 | } else if (window.webkitRequestAnimationFrame) {
561 | window.webkitRequestAnimationFrame(loop);
562 | } else {
563 | setTimeout(loop, 33);
564 | }
565 | })();
566 | }
567 |
568 | /* ------------------------------------------------------------------------------------- */
569 | /* 上列方法均是游戏内部逻辑方法,外界不可以调用。 */
570 |
571 |
572 | /* 下列方法均是用于操控游戏的方法,外界可以调用。 */
573 | /* ------------------------------------------------------------------------------------- */
574 |
575 | /* 调用此方法开始游戏。 如果在游戏进行中重复调用了此方法,将忽略。 */
576 | function startGame () {
577 |
578 | /* 一旦此数组有值,则认为在游戏中,直接不处理。 */
579 | if (!gameover) {
580 | return;
581 | }
582 | gameover = false;
583 |
584 | /* 初始化游戏数组为一个空数组 */
585 | gameAtoms = [];
586 | staticStuffs = [];
587 | for (var j = 0; j < atomheightCount; j++) {
588 | gameAtoms[j] = [];
589 | staticStuffs[j] = [];
590 | for (var i = 0; i < atomwidthCount; i++) {
591 | gameAtoms[j][i] = 0;
592 | staticStuffs[j][i] = 0;
593 | }
594 | }
595 |
596 | var lastTime = 0;
597 | (function loop() {
598 |
599 | if (
600 | (!pause) &&
601 | (!gameover /* 游戏未标记为结束 */) &&
602 | (!succAniming/*在消减动画时不执行下落*/) &&
603 | Date.now() - lastTime >= (turbo ? TURBO_TIME_SPACE : LEVELS[level])
604 | ) {
605 |
606 | var isNewCurrStuf = false;
607 |
608 | if (!currStuff) {
609 | currStuff = nextStuff; /* 始终优先从下一个材料获取 */
610 | nextStuff = null;
611 | isNewCurrStuf = !!currStuff;
612 | }
613 | if (!currStuff) {
614 | currStuff = randomStuff(); /* 通过下一个材料也没能获取到材料,说明这是游戏刚开始,此处可以直接随机获取一个。 */
615 | nextStuff = null;
616 | isNewCurrStuf = !!currStuff;
617 | }
618 | if (!nextStuff) {
619 | nextStuff = randomStuff(); /* 产生下一个新材料 */
620 | isNewCurrStuf = !!currStuff;
621 | }
622 |
623 | if (isNewCurrStuf) {
624 | turboModeOFF(); /*新材料掉下来时关闭急速模式*/
625 | }
626 |
627 | /* 将 当前掉落 的材料通过指定的横向偏移量进行融合,并将 currStuff 下降1格。 */
628 | var grounded = _GameArrMerge(stuffOffsetX, stuffOffsetY, currStuff, gameAtoms, staticStuffs);
629 | if (grounded === 1) {
630 | /* 掉落到了能够掉落的最底部了,可以进行下一个材料的掉落了。 */
631 | currStuff = null;
632 | stuffOffsetX = STUFF_START_X_OFFSET;
633 | stuffOffsetY = STUFF_START_Y_OFFSET;
634 |
635 | /* 检查堆砌成功了的 */
636 | checkSuccessLine();
637 | } else if (grounded === -1) {
638 |
639 | /* 游戏结束 */
640 | resetGame();
641 | } else {
642 | /* 正常下落。什么都不用处理。 */
643 | }
644 |
645 | lastTime = Date.now();
646 | }
647 | if (!gameover) {
648 | if (window.requestAnimationFrame) {
649 | window.requestAnimationFrame(loop);
650 | } else if (window.webkitRequestAnimationFrame) {
651 | window.webkitRequestAnimationFrame(loop);
652 | } else {
653 | setTimeout(loop, 5);
654 | }
655 | }
656 | })();
657 | }
658 |
659 | /* 暂停游戏,再次调用则恢复。 */
660 | function pauseGame () {
661 | if (!gameover && gameAtoms && staticStuffs) {
662 | pause = !pause;
663 | }
664 | }
665 |
666 | /* 开启急速模式,急速模式下落完成一个材料后自动关闭,也可以手动调用 turboModeOFF 方法关闭。*/
667 | function turboModeON() {
668 | if (gameAtoms && currStuff) {
669 | turbo = true;
670 | }
671 | }
672 |
673 | /* 关闭急速模式。 */
674 | function turboModeOFF() {
675 | turbo = false;
676 | }
677 |
678 | /* 旋转材料。 此方法只有在游戏中有效,可以将正在下落的材料进行顺时针90度旋转。 */
679 | function rotateStuff () {
680 | if (gameAtoms && currStuff && (!pause)) {
681 | var temp = [[], [], [], []];
682 |
683 | // 进行旋转材料
684 | for (var i = 0; i < currStuff.length; i++) {
685 | for (var j = 0; j < currStuff[i].length; j++) {
686 |
687 | var ni = j;
688 | var nj = currStuff.length - 1 - i;
689 | temp[ni][nj] = currStuff[i][j];
690 |
691 | if (stuffOffsetY + ni < 0) {
692 | /* 材料还没下降到屏幕内 */
693 | continue;
694 | }
695 |
696 | if (stuffOffsetY + ni >= atomheightCount) {
697 | /*变化会超出屏幕,不准变*/
698 | return;
699 | }
700 |
701 | if (stuffOffsetX + nj >= atomwidthCount || stuffOffsetX + nj < 0) {
702 | return;
703 | }
704 |
705 |
706 | /*判断变化后的材料是否和已确定的堆砌产生重叠,产生了则不进行此次变化*/
707 | if (staticStuffs[stuffOffsetY + ni][stuffOffsetX + nj] === 1) {
708 | return;
709 | }
710 | }
711 | }
712 |
713 | /* 变化了之后,重新赋值数组,让界面变化。 */
714 | currStuff = temp;
715 |
716 | gameAtoms = _addStuffToGameAtoms(stuffOffsetX, stuffOffsetY, currStuff);
717 | }
718 | }
719 |
720 | /* 将材料向左边移动一格。 */
721 | function left () {
722 | _moveCurrStuff(-1);
723 | }
724 |
725 | /* 将材料向右边移动一格。 */
726 | function right () {
727 | _moveCurrStuff(1);
728 | }
729 |
730 | /* 结束游戏、复位。 */
731 | function resetGame () {
732 | if (gameover) {
733 | return;
734 | }
735 |
736 | gameover = true;
737 |
738 | /* 保存最佳成绩。*/
739 | if (score > bestscore) {
740 | bestscore = score;
741 | window.localStorage && window.localStorage.setItem("bestscore", bestscore);
742 | }
743 |
744 | resetAnim(function () {
745 | _resetGame();
746 | });
747 | }
748 |
749 | /* 是否暂停。 */
750 | function isPaused () {
751 | return pause;
752 | }
753 |
754 | /* 获取当前成绩。 */
755 | function getScore() {
756 | return score;
757 | }
758 |
759 | /* 获取当前等级。 */
760 | function getLevel() {
761 | return score;
762 | }
763 |
764 | /* 获取当前下降的材料。 */
765 | function getCuffStuf() {
766 | return currStuff;
767 | }
768 |
769 | gameDom = initGameDom(domId);
770 | gameCanvas = initGameCanvas(gameDom);
771 | initLogic();
772 | initEvent();
773 | render(gameCanvas);
774 |
775 | this.startGame = startGame;
776 | this.pauseGame = pauseGame;
777 | this.turboModeON = turboModeON;
778 | this.turboModeOFF = turboModeOFF;
779 | this.rotateStuff = rotateStuff;
780 | this.left = left;
781 | this.right = right;
782 | this.resetGame = resetGame;
783 | this.isPaused = isPaused;
784 | this.getScore = getScore;
785 | this.getLevel = getLevel;
786 | this.getCuffStuf = getCuffStuf;
787 | };
--------------------------------------------------------------------------------
/src/wzw_levels.js:
--------------------------------------------------------------------------------
1 | /* 游戏等级配置 */
2 |
3 | /* 定义了各个等级下降的速度, 实际上数字用于settimeout时间间隔 */
4 | var LEVELS = [800, 700, 600, 550, 500, 450, 400, 350, 300, 250, 200, 150, 130, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 5];
5 |
6 | /* 成绩对应等级 */
7 | var SCORE_LEVELS = {
8 | "50": 1,
9 | "100": 2,
10 | "150": 3,
11 | "200": 4,
12 | "250": 5,
13 | "300": 6,
14 | "350": 7,
15 | "400": 8,
16 | "450": 9,
17 | "500": 10,
18 | "550": 11,
19 | "600": 12,
20 | "700": 13,
21 | "850": 14,
22 | "1000": 15,
23 | "1100": 16,
24 | "1300": 17,
25 | "1500": 18,
26 | "2000": 19,
27 | "2500": 20,
28 | "3000": 21,
29 | "4000": 22,
30 | "5000": 23
31 | };
32 |
33 | module.exports = {
34 | LEVELS, SCORE_LEVELS
35 | };
--------------------------------------------------------------------------------
/src/wzw_stufs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 游戏中下落的素材,都是来自这个数组里面。
3 | * 这里面为了保证每个材料机会相同,有可能出现重复的
4 | *
5 | *
6 | * created:Microanswer
7 | * update: 2020年1月13日09:37:22
8 | * */
9 |
10 | var STUFS = [[
11 |
12 | [0, 0, 0, 0], /* 长条 */
13 | [0, 0, 0, 0],
14 | [1, 1, 1, 1],
15 | [0, 0, 0, 0]], [
16 |
17 | [0, 0, 0, 0], /* 长条 */
18 | [0, 0, 0, 0],
19 | [1, 1, 1, 1],
20 | [0, 0, 0, 0]], [
21 |
22 | [0, 1, 0, 0], /* 长条 */
23 | [0, 1, 0, 0],
24 | [0, 1, 0, 0],
25 | [0, 1, 0, 0]], [
26 |
27 | [0, 1, 0, 0], /* 长条 */
28 | [0, 1, 0, 0],
29 | [0, 1, 0, 0],
30 | [0, 1, 0, 0]], [
31 |
32 | // ------------------------------------------------
33 |
34 | [0, 0, 0, 0], /* 四块 */
35 | [0, 1, 1, 0],
36 | [0, 1, 1, 0],
37 | [0, 0, 0, 0]], [
38 |
39 | [0, 0, 0, 0], /* 四块 */
40 | [0, 1, 1, 0],
41 | [0, 1, 1, 0],
42 | [0, 0, 0, 0]], [
43 |
44 | [0, 0, 0, 0], /* 四块 */
45 | [0, 1, 1, 0],
46 | [0, 1, 1, 0],
47 | [0, 0, 0, 0]], [
48 |
49 | [0, 0, 0, 0], /* 四块 */
50 | [0, 1, 1, 0],
51 | [0, 1, 1, 0],
52 | [0, 0, 0, 0]], [
53 |
54 | // ------------------------------------------------
55 |
56 | [0, 0, 0, 0], /* 翻7 */
57 | [0, 1, 0, 0],
58 | [0, 1, 1, 1],
59 | [0, 0, 0, 0]], [
60 |
61 | [0, 0, 0, 0], /* 翻7 */
62 | [0, 1, 1, 0],
63 | [0, 1, 0, 0],
64 | [0, 1, 0, 0]], [
65 |
66 | [0, 0, 0, 0], /* 翻7 */
67 | [0, 1, 1, 1],
68 | [0, 0, 0, 1],
69 | [0, 0, 0, 0]], [
70 |
71 | [0, 0, 0, 0], /* 翻7 */
72 | [0, 0, 1, 0],
73 | [0, 0, 1, 0],
74 | [0, 1, 1, 0]], [
75 |
76 | // ------------------------------------------------
77 |
78 | [0, 0, 0, 0], /* 正7 */
79 | [0, 1, 1, 1],
80 | [0, 1, 0, 0],
81 | [0, 0, 0, 0]], [
82 |
83 | [0, 0, 0, 0], /* 正7 */
84 | [0, 1, 1, 0],
85 | [0, 0, 1, 0],
86 | [0, 0, 1, 0]], [
87 |
88 | [0, 0, 0, 0], /* 正7 */
89 | [0, 0, 0, 1],
90 | [0, 1, 1, 1],
91 | [0, 0, 0, 0]], [
92 |
93 | [0, 1, 0, 0], /* 正7 */
94 | [0, 1, 0, 0],
95 | [0, 1, 1, 0],
96 | [0, 0, 0, 0]], [
97 |
98 |
99 | // ------------------------------------------------
100 |
101 | [0, 0, 0, 0], /* 土 */
102 | [0, 1, 1, 1],
103 | [0, 0, 1, 0],
104 | [0, 0, 0, 0]], [
105 |
106 | [0, 0, 0, 0], /* 土 */
107 | [0, 0, 1, 0],
108 | [0, 1, 1, 0],
109 | [0, 0, 1, 0]], [
110 |
111 | [0, 0, 0, 0], /* 土 */
112 | [0, 0, 1, 0],
113 | [0, 1, 1, 1],
114 | [0, 0, 0, 0]], [
115 |
116 | [0, 0, 0, 0], /* 土 */
117 | [0, 0, 1, 0],
118 | [0, 0, 1, 1],
119 | [0, 0, 1, 0]], [
120 |
121 |
122 | // ------------------------------------------------
123 |
124 | [0, 0, 0, 0], /* z */
125 | [0, 1, 1, 0],
126 | [0, 0, 1, 1],
127 | [0, 0, 0, 0]], [
128 |
129 | [0, 0, 0, 0], /* z */
130 | [0, 1, 1, 0],
131 | [0, 0, 1, 1],
132 | [0, 0, 0, 0]], [
133 |
134 | [0, 0, 0, 0], /* z */
135 | [0, 0, 1, 0],
136 | [0, 1, 1, 0],
137 | [0, 1, 0, 0]], [
138 |
139 | [0, 0, 0, 0], /* z */
140 | [0, 0, 1, 0],
141 | [0, 1, 1, 0],
142 | [0, 1, 0, 0]], [
143 |
144 |
145 | // ------------------------------------------------
146 |
147 | [0, 0, 0, 0], /* 翻z */
148 | [0, 0, 1, 1],
149 | [0, 1, 1, 0],
150 | [0, 0, 0, 0]], [
151 |
152 | [0, 0, 0, 0], /* 翻z */
153 | [0, 0, 1, 1],
154 | [0, 1, 1, 0],
155 | [0, 0, 0, 0]], [
156 |
157 | [0, 0, 0, 0], /* 翻z */
158 | [0, 1, 0, 0],
159 | [0, 1, 1, 0],
160 | [0, 0, 1, 0]], [
161 |
162 | [0, 0, 0, 0], /* 翻z */
163 | [0, 1, 0, 0],
164 | [0, 1, 1, 0],
165 | [0, 0, 1, 0]]
166 | ];
167 |
168 | module.exports = STUFS;
--------------------------------------------------------------------------------
/src/wzw_util.js:
--------------------------------------------------------------------------------
1 | function Util() {
2 |
3 | /**
4 | * 滚动。 此方法并不滚动界面,而是将一个数值变化到另一个数值。
5 | * @param from 从某个值
6 | * @param to 到某个值
7 | * @param back 不停的回调
8 | * @param dur 动画执行时长,默认 500 毫秒
9 | */
10 | this.scroll = function (from, to, back, dur) {
11 | var y = from;
12 | y = y || 0;
13 | var startY = y;
14 |
15 | var distanceY = to - startY;
16 |
17 | if (distanceY === 0) {
18 | // 没有意义的滚动
19 | back && back.end && back.end(to);
20 | return undefined
21 | }
22 |
23 | var ended = false;
24 | var time = dur || 500;
25 | var ftp = 60;
26 |
27 | var ease = function (pos) { // 要使用的缓动公式
28 | return pos;
29 | };
30 |
31 | var startTime = Date.now(); // 开始时间
32 | // 开始执行
33 | (function dd () {
34 | setTimeout(function () {
35 | var now = Date.now(); // 当前帧开始时间
36 | var timestamp = now - startTime; // 逝去的时间(已进行动画的时间)
37 | var detal2 = ease(timestamp / time);
38 | var result2 = Math.ceil(startY + detal2 * distanceY);
39 |
40 | if (!ended) {
41 | back && back.goo && back.goo(result2);
42 | }
43 | if (time <= timestamp) {
44 | ended = true;
45 | back.end(to);
46 | } else {
47 | setTimeout(dd, 1000 / ftp);
48 | }
49 | }, 1000 / ftp);
50 | })();
51 | };
52 |
53 | /*
54 | 打印数组
55 | * */
56 | this.printArr = function (arr) {
57 | var s = "";
58 | this.each(arr, function (i, arrr) {
59 | s += (i + ":" + arrr.join(" ")) + "\n";
60 | });
61 | console.log(s);
62 | };
63 |
64 | /**
65 | * 二维数组拷贝
66 | * */
67 | this.arrCopy = function (src) {
68 | var temp = [];
69 | for (var i = 0; i < src.length; i++) {
70 | temp[i] = [];
71 | for (var j = 0; j < src[j].length; j++) {
72 | temp[i][j] = src[i][j];
73 | }
74 | }
75 | return temp;
76 | };
77 |
78 | /**
79 | * 循环数字
80 | * @param from 自
81 | * @param to 到
82 | * @param fun 每次调用
83 | */
84 | this.eachNum = function (from, to, fun) {
85 | if (from > to) {
86 |
87 | for (var i = from; i >= to; i--) {
88 | fun && fun(i);
89 | }
90 |
91 | return;
92 | }
93 | for (var i = from; i <= to; i++) {
94 | fun && fun(i);
95 | }
96 | };
97 |
98 | /* 循环数组 */
99 | this.each = function (arr, fun) {
100 | for (var i = 0; i < arr.length; i++) {
101 | fun && fun(i, arr[i]);
102 | }
103 | }
104 | }
105 |
106 | module.exports = new Util();
--------------------------------------------------------------------------------