Document directory
I can finally play the third animation game, ^ _ ^.
Trial
Demo: http://ambar.github.com/Tetris/
Origin
How to Implement
Because Wikipedia's materials are very similar to bricks, I called tetromino in my code as a brick, and the entire tile Board as a wall-corresponding to the player's control targets and maps in the game.
Deformation
First, observe the "J" shape transpose (T) and rotation (r) graphics, zero represents the hollow part, non-zero solid part:
J =>1,0,01,1,1T =>1,10,10,1R =>1,11,01,0
Transpose: each row is converted into each column of the target. By comparing transpose and Rotating Graphs, we can see that the difference between them is thatThe element order of each row is the opposite., The corresponding array method is very clear, namely pop and unshift, implementation:
// Use a two-dimensional array to represent the 'shape' var shape_array = [[, 0], [, 1],] // transpose, row and column switching var transpose = function (ary) {var ret = [], row, rows = ary. length, cols = ary [0]. length; cols. times (function (y) {ret. push (ROW = []) rows. times (function (x) {row. push (ary [x] [Y])}) return ret;} // rotate to the right (clockwise). The reverse order is Var rotate = function (ary) when each row generates column elements) {var ret = [], row, rows = ary. length, cols = ary [0]. length; cols. times (function (y) {ret. push (ROW = []) rows. times (function (x) {row. unshift (ary [x] [Y])}) return ret ;}
Now, let's look at the image that is rotated to the left. We can see it in comparison with the transpose image.Reverse the order of rowsYou can use the Reverse Method of the ready-made array:
/* Counter-clockwise rotation illustration 0, 10, 11, 1 * // counter-clockwise rotation algorithm var rotate_anticlockwise = function (ary) {return transpose (ary). Reverse ();}
I started the game with a counter-clockwise rotation, and I thought it was more natural. After a try on other online game implementations, the results are clockwise = _ =.
Brick Definition
I have defined three main attributes:
- Position: coordinates in the lower left corner
- Parts: coordinates of each visible part
- Shape: Shape
/** Map a shape (two-dimensional array) to a position list (one-dimensional array) based on the reference position in the lower left corner of a shape (two-dimensional array ). Zero is empty, all discard * @ POS {vector} * @ shape {array} */var mapshape = function (Pos, shape) {var ret = [], rows = shape. length, cols = shape [0]. length; rows. times (function (x) {cols. times (function (y) {shape [rows-x-1] [Y] & ret. push (POS. add (V ([y,-x])}) ;}); return ret ;}
If the reference coordinate of a brick is vector [3, 4], shape is the J shown above, and its parts is:
// parts = mapShape( V([3,4]), shape_ary ) =>[ Vector[3,4], Vector[4,4], Vector[5,4], Vector[3,3] ]
With proper attribute definitions, it is easy to move and join the walls.
Map
Map relationship storage and collision section, the structure is the same as the above shape, using a two-dimensional array.
Note that the coordinate system and array on the screen do not correspond directly:
screen : {x,y}┏━━━x┃ yarray : [x][y]┏━━━y┃ x
The point transpose on the screen can correspond to the elements of the array.
The first half of my game was stored as follows:
map[p.x][p.y] = type;
Point P corresponds to the map array element, which is very helpful, but has two disadvantages:
- It is inconvenient to observe or print the structure. You need to transpose the map array. (If the layout is 20*10, the map structure is 10*20)
- It is inconvenient to detect the elimination of rows. You must also transpose the columns as rows.
Therefore, in the second half, we corrected the problem:
map[p.y][p.x] = type;
Cancel
I used a very simple method, without any special effect-to delete a row directly, and then use a zero-element template line to insert it to the map header:
function eraseRow(idx) {this.map.splice(idx,1);this.map.unshift(this.tmplRow);}
Collision
Es5Some methods of are most suitable for processing this, just accept the preceding parts parameter:
function collideWith(vectors) {var map = this.map, height = this.height;return vectors.some(function(v) {var row = map[v.y];return v.y >= height || (row && row[v.x]);})}
Details
- HSL is much more convenient than RGB.
- When you draw a polygon, the diagonal line will have a black tooth. You can draw a line segment on it.
- Canvas painting consumes too much text, especially Firefox. If necessary, create a canvas layer as the background, draw the text above it, and use CSS to locate it under the main canvas.
- Without hardware acceleration, just draw a common image, and the image will be stuck after the half screen. The solution is to cache the drawn image with getimagedata.
AMD
The game code later switched to AMDMethod organization, the loader selects the seajs written by Chinese people.
AMDIt is a module definition method proposed by commonjs. It eliminates the old form of using global variables as namespaces.
Compared with older namespaces, amdIt is easier to organize code, and the structure is more clean and consistent.
This game took me a few hours to switch. Conclusion:
- If a module is a set of functions, use exports
- If a module is a single class, use module. Exports
- The first parameter 'module name' of the define function is completely meaningless. I started to name all the files in order to be able to merge them easily. Later I found it too troublesome-because when you want to reference it, you may have to open the file to find out what name it named. This is a tragedy. All of them are changed.
File placement levelThat is, your namespace. This should be the core concept of AMD.
Problems that may occur when using seajs:
- Loop reference. Seajs will report a warning, which can be ruled out after careful check. However, it can work even if it is not ruled out. It's a bit tangled. Now the compromise is to export a global variable tetrisgame.
- The second dependency parameter of define may also have the strange problem of module reference. It is also a circular reference, but there is no error message or something, and the loaded module has not been loaded for a long time, prompting timeout.
Use
// The length of the grid. The default value is 40 // tetrisgame. unit = 20; // display the gridline. The default value is true // tetrisgame. showgrid = false; // The topic type ["classic", "window", "bubble"]. The default value is classic/tetrisgame. theme = 'window'; // canvas, number of columns, number of rows, and tetrisgame scaling. init ('# RIS-game', 10, 20, 1); // tetrisgame. init ('# RIS-game', 10, 20 ,. 5 );
View or download
Https://github.com/ambar/Tetris