css, hold, next, fix rotate
This commit is contained in:
parent
8992f4d02b
commit
0f3ab4052e
@ -1,11 +1,51 @@
|
|||||||
* {
|
* {
|
||||||
background: #000;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
body {
|
||||||
background: #000;
|
background-image: url("../images/bg.jpg");
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.columns {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side {
|
||||||
|
flex-grow: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rows {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 5% 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hold {
|
||||||
|
max-width: 120px;
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats {
|
||||||
|
margin: 10% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix {
|
||||||
|
max-width: 200px;
|
||||||
|
margin: 5% 2%;
|
||||||
|
border: 0.5px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next {
|
||||||
|
max-width: 120px;
|
||||||
|
margin: 5% 2%;
|
||||||
|
}
|
BIN
images/bg.jpg
Normal file
BIN
images/bg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 KiB |
15
index.html
15
index.html
@ -8,6 +8,19 @@
|
|||||||
<script type="text/javascript" src="js/webtris.js"></script>
|
<script type="text/javascript" src="js/webtris.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="matrix" width="200" height="400">Votre navigateur ne supporte pas HTML5, veuillez le mettre à jour pour jouer.</canvas>
|
<div class="columns">
|
||||||
|
<div class="side"></div>
|
||||||
|
<div class="rows">
|
||||||
|
<canvas id="hold" class="hold" width="120" height="120"></canvas>
|
||||||
|
<div class="stats">
|
||||||
|
SCORE: 123123123123<br/>
|
||||||
|
HIGH SCORE:<br/>
|
||||||
|
TIME:<br/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<canvas id="matrix" class="matrix" width="200" height="400">Votre navigateur ne supporte pas HTML5, veuillez le mettre à jour pour jouer.</canvas>
|
||||||
|
<canvas id="next" class="next" width="120" height="400"></canvas>
|
||||||
|
<div class="side"></div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
108
js/webtris.js
108
js/webtris.js
@ -2,7 +2,7 @@ Array.prototype.add = function(other) {
|
|||||||
return this.map((x, i) => x + other[i])
|
return this.map((x, i) => x + other[i])
|
||||||
}
|
}
|
||||||
Array.prototype.rotate = function(spin) {
|
Array.prototype.rotate = function(spin) {
|
||||||
return [spin*pos[1], pos[0]]
|
return [-spin*this[1], spin*this[0]]
|
||||||
}
|
}
|
||||||
Array.prototype.sample = function() {
|
Array.prototype.sample = function() {
|
||||||
return this.splice(Math.floor(Math.random()*this.length), 1)[0]
|
return this.splice(Math.floor(Math.random()*this.length), 1)[0]
|
||||||
@ -10,10 +10,12 @@ Array.prototype.sample = function() {
|
|||||||
|
|
||||||
|
|
||||||
const MINO_SIZE = 20
|
const MINO_SIZE = 20
|
||||||
const MATRIX_LINES = 20
|
|
||||||
const MATRIX_COLLUMNS = 10
|
|
||||||
const NEXT_PIECES = 5
|
const NEXT_PIECES = 5
|
||||||
const INIT_POSITION = [4, 0]
|
const MATRIX_LINES = 20
|
||||||
|
const MATRIX_COLUMNS = 10
|
||||||
|
const HELD_PIECE_POSITION = [2, 2]
|
||||||
|
const FALLING_PIECE_POSITION = [4, 0]
|
||||||
|
const NEXT_PIECES_POSITIONS = Array.from({length: NEXT_PIECES}, (v, k) => [2, k*4+2])
|
||||||
const LOCK_DELAY = 500
|
const LOCK_DELAY = 500
|
||||||
const FALL_DELAY = 1000
|
const FALL_DELAY = 1000
|
||||||
const AUTOREPEAT_DELAY = 300
|
const AUTOREPEAT_DELAY = 300
|
||||||
@ -24,8 +26,8 @@ const MOVEMENT = {
|
|||||||
DOWN: [0, 1]
|
DOWN: [0, 1]
|
||||||
}
|
}
|
||||||
const SPIN = {
|
const SPIN = {
|
||||||
CW: -1,
|
CW: 1,
|
||||||
CCW: 1
|
CCW: -1
|
||||||
}
|
}
|
||||||
const T_SPIN = {
|
const T_SPIN = {
|
||||||
NULL: "",
|
NULL: "",
|
||||||
@ -50,7 +52,7 @@ const SCORES = [
|
|||||||
shapes = []
|
shapes = []
|
||||||
class Tetromino {
|
class Tetromino {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.pos = INIT_POSITION
|
this.pos = FALLING_PIECE_POSITION
|
||||||
this.orientation = 0
|
this.orientation = 0
|
||||||
this.rotated_last = false
|
this.rotated_last = false
|
||||||
this.rotation_point_5_used = false
|
this.rotation_point_5_used = false
|
||||||
@ -66,7 +68,7 @@ class Tetromino {
|
|||||||
[[0, 0], [ 1, 0], [ 1, -1], [0, 2], [ 1, 2]],
|
[[0, 0], [ 1, 0], [ 1, -1], [0, 2], [ 1, 2]],
|
||||||
[[0, 0], [ 1, 0], [ 1, 1], [0, -2], [ 1, -2]],
|
[[0, 0], [ 1, 0], [ 1, 1], [0, -2], [ 1, -2]],
|
||||||
[[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]],
|
[[0, 0], [-1, 0], [-1, -1], [0, 2], [-1, 2]],
|
||||||
[[0, 0], [-1, 0], [-1, 1], [0, -2], [-1, -2]],
|
[[0, 0], [-1, 0], [-1, 1], [0, 2], [-1, -2]],
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
if (!shapes.lenght)
|
if (!shapes.lenght)
|
||||||
@ -134,49 +136,57 @@ class Tetromino {
|
|||||||
|
|
||||||
function draw_mino(context, x, y, color) {
|
function draw_mino(context, x, y, color) {
|
||||||
context.fillStyle = color
|
context.fillStyle = color
|
||||||
context.fillRect(x*MINO_SIZE, y*MINO_SIZE, MINO_SIZE, MINO_SIZE);
|
context.fillRect(x*MINO_SIZE, y*MINO_SIZE, MINO_SIZE, MINO_SIZE)
|
||||||
context.strokeStyle = "rgba(255, 255, 255, 128)";
|
context.lineWidth = 0.5
|
||||||
context.strokeRect(x*MINO_SIZE, y*MINO_SIZE, MINO_SIZE, MINO_SIZE);
|
context.strokeStyle = "white"
|
||||||
|
context.strokeRect(x*MINO_SIZE, y*MINO_SIZE, MINO_SIZE, MINO_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Matrix {
|
class Matrix {
|
||||||
constructor() {
|
constructor(context) {
|
||||||
this.cells = Array.from(Array(MATRIX_COLLUMNS), y => Array(MATRIX_LINES))
|
this.context = context
|
||||||
|
this.cells = Array.from({length: MATRIX_COLUMNS}, (v, k) => Array(MATRIX_LINES))
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_is_occupied(x, y) {
|
cell_is_occupied(x, y) {
|
||||||
return 0 <= x && x < MATRIX_COLLUMNS && y < MATRIX_LINES ? this.cells[x][y] : true
|
return 0 <= x && x < MATRIX_COLUMNS && y < MATRIX_LINES ? this.cells[x][y] : true
|
||||||
}
|
}
|
||||||
|
|
||||||
space_to_move(piece_pos, minoes_pos) {
|
space_to_move(piece_pos, minoes_pos) {
|
||||||
for (const abs_mino_pos of minoes_pos.map(pos => pos.add(piece_pos))) {
|
for (const pos of minoes_pos) {
|
||||||
if (this.cell_is_occupied(...abs_mino_pos))
|
if (this.cell_is_occupied(...pos.add(piece_pos)))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(context) {
|
draw() {
|
||||||
// grid
|
// grid
|
||||||
context.strokeStyle = "rgba(128, 128, 128, 128)";
|
const width = MATRIX_COLUMNS*MINO_SIZE
|
||||||
context.beginPath();
|
const height = MATRIX_LINES*MINO_SIZE
|
||||||
for (var x = 0; x <= MATRIX_COLLUMNS*MINO_SIZE; x += MINO_SIZE) {
|
this.context.clearRect(0, 0, width, height)
|
||||||
context.moveTo(x, 0);
|
this.context.strokeStyle = "rgba(128, 128, 128, 128)"
|
||||||
context.lineTo(x, matrixCanvas.height);
|
this.context.lineWidth = 0.5
|
||||||
|
this.context.beginPath()
|
||||||
|
for (var x = 0; x <= width; x += MINO_SIZE) {
|
||||||
|
this.context.moveTo(x, 0);
|
||||||
|
this.context.lineTo(x, height);
|
||||||
}
|
}
|
||||||
for (var y = 0; y <= MATRIX_LINES*MINO_SIZE; y += MINO_SIZE) {
|
for (var y = 0; y <= height; y += MINO_SIZE) {
|
||||||
context.moveTo(0, y);
|
this.context.moveTo(0, y);
|
||||||
context.lineTo(matrixCanvas.width, y);
|
this.context.lineTo(width, y);
|
||||||
}
|
}
|
||||||
context.stroke();
|
this.context.stroke()
|
||||||
|
// falling piece
|
||||||
|
falling_piece.draw(this.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function move(movement) {
|
function move(movement) {
|
||||||
const test_pos = tetro.pos.add(movement)
|
const test_pos = falling_piece.pos.add(movement)
|
||||||
if (matrix.space_to_move(test_pos, tetro.minoes_pos)) {
|
if (matrix.space_to_move(test_pos, falling_piece.minoes_pos)) {
|
||||||
tetro.pos = test_pos
|
falling_piece.pos = test_pos
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -185,14 +195,14 @@ function move(movement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rotate(spin) {
|
function rotate(spin) {
|
||||||
const text_minoes_pos = tetro.minoes_pos.map(pos => [spin*pos[1], pos[0]])
|
const test_minoes_pos = falling_piece.minoes_pos.map(pos => pos.rotate(spin))
|
||||||
rotation_point = 0
|
rotation_point = 0
|
||||||
for (const movement of tetro.srs[spin==SPIN.CW?"CW":"CCW"][tetro.orientation]) {
|
for (const movement of falling_piece.srs[spin==SPIN.CW?"CW":"CCW"][falling_piece.orientation]) {
|
||||||
const test_pos = [tetro.pos[0]+movement[0], tetro.pos[1]+movement[1]]
|
const test_pos = falling_piece.pos.add(movement)
|
||||||
if (matrix.space_to_move(test_pos, text_minoes_pos)) {
|
if (matrix.space_to_move(test_pos, test_minoes_pos)) {
|
||||||
tetro.pos = test_pos
|
falling_piece.pos = test_pos
|
||||||
tetro.minoes_pos = text_minoes_pos
|
falling_piece.minoes_pos = test_minoes_pos
|
||||||
tetro.orientation = (tetro.orientation - spin + 4) % 4
|
falling_piece.orientation = (falling_piece.orientation + spin + 4) % 4
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rotation_point++
|
rotation_point++
|
||||||
@ -261,9 +271,9 @@ function autorepeat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function keyDownHandler(e) {
|
function keyDownHandler(e) {
|
||||||
|
if (e.key in actions) {
|
||||||
if (!pressedKeys.has(e.key)) {
|
if (!pressedKeys.has(e.key)) {
|
||||||
pressedKeys.add(e.key)
|
pressedKeys.add(e.key)
|
||||||
if (e.key in actions) {
|
|
||||||
action = actions[e.key]
|
action = actions[e.key]
|
||||||
action()
|
action()
|
||||||
if (repeatableActions.includes(action)) {
|
if (repeatableActions.includes(action)) {
|
||||||
@ -284,8 +294,8 @@ function keyDownHandler(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function keyUpHandler(e) {
|
function keyUpHandler(e) {
|
||||||
pressedKeys.delete(e.key)
|
|
||||||
if (e.key in actions) {
|
if (e.key in actions) {
|
||||||
|
pressedKeys.delete(e.key)
|
||||||
action = actions[e.key]
|
action = actions[e.key]
|
||||||
if (actionsToRepeat.includes(action)) {
|
if (actionsToRepeat.includes(action)) {
|
||||||
actionsToRepeat.splice(actionsToRepeat.indexOf(action), 1)
|
actionsToRepeat.splice(actionsToRepeat.indexOf(action), 1)
|
||||||
@ -302,18 +312,24 @@ function keyUpHandler(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
matrixContext.clearRect(0, 0, MATRIX_COLLUMNS*MINO_SIZE, MATRIX_LINES*MINO_SIZE);
|
held_piece.draw(holdContext)
|
||||||
matrix.draw(matrixContext)
|
matrix.draw()
|
||||||
tetro.draw(matrixContext)
|
next_pieces.map(piece => piece.draw(nextContext))
|
||||||
requestAnimationFrame(draw)
|
requestAnimationFrame(draw)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
matrixCanvas = document.getElementById("matrix");
|
holdContext = document.getElementById("hold").getContext("2d")
|
||||||
matrixContext = matrixCanvas.getContext("2d");
|
matrixContext = document.getElementById("matrix").getContext("2d")
|
||||||
|
nextContext = document.getElementById("next").getContext("2d")
|
||||||
|
|
||||||
matrix = new Matrix()
|
matrix = new Matrix(matrixContext)
|
||||||
tetro = new Tetromino()
|
held_piece = new Tetromino()
|
||||||
|
held_piece.pos = HELD_PIECE_POSITION
|
||||||
|
falling_piece = new Tetromino()
|
||||||
|
falling_piece.pos = FALLING_PIECE_POSITION
|
||||||
|
next_pieces = Array.from({length: NEXT_PIECES}, (v, k) => new Tetromino())
|
||||||
|
next_pieces.map((piece, i, array) => piece.pos = NEXT_PIECES_POSITIONS[i])
|
||||||
|
|
||||||
document.addEventListener("keydown", keyDownHandler, false);
|
document.addEventListener("keydown", keyDownHandler, false);
|
||||||
document.addEventListener("keyup", keyUpHandler, false);
|
document.addEventListener("keyup", keyUpHandler, false);
|
||||||
|
Reference in New Issue
Block a user