如何解决如何找到俄罗斯方块Tetromino落在网格上的位置并将其显示为预览?
我正在学习 HTML canvas 并选择制作俄罗斯方块游戏作为我通过观看一些教程完成游戏的第一个项目。但是想要通过添加实时预览来使其更好,其中 Tetromino 会出现在页面上,任何人都可以帮助我如何做到这一点? 通过预览,我的意思是如何向玩家显示棋子落在 gameArea 上的位置。
HTML 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<Meta charset="UTF-8">
<Meta http-equiv="X-UA-Compatible" content="IE=edge">
<Meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Tetris Game</title>
<link rel="stylesheet" href="./Game Assets/Style/style.css">
<link rel="shortcut icon" href="./Game Assets/img/tetris.png" type="image/x-icon">
</head>
<body body>
<div id="wrapper">
<div id="GameArea">
<canvas id="gameCanvas" width="300" height="600">
</canvas>
<div id="SLN">
<div id="score">
<h3>score:</h3>
<div id="sc">0</div>
</div>
<div id="Level">
</div>
<div id="NEXT">
<h3>Next:</h3>
<canvas id="preCanvas" width="120" height="120"></canvas>
</div>
</div>
</div>
</div>
<script src="./Game Assets/Script/index.js"></script>
</body>
</html>
这里是 Java 脚本文件
const canvas = document.getElementById("gameCanvas"); //Get The Canvas Element
const ctx = canvas.getContext("2d");
const preview = document.getElementById("preCanvas");
const pre = preview.getContext("2d");
//Tetrominoes Code
const I = [
[
[0,1,0],[0,],[
[0,[1,1],]
];
const J = [
[
[1,0]
],1]
],0]
]
];
const L = [
[
[0,[
[1,0]
]
];
const O = [
[
[0,]
];
const S = [
[
[0,0]
]
];
const T = [
[
[0,0]
]
];
const Z = [
[
[1,0]
]
];
// we first need too define ROW and columns constants
const ROW = 20;
const COL = 10;
// Const for square size
const SQ = 30;
function drawSquare(x,y,color,stroke,T) {
if (stroke === "piece") {
ctx.fillStyle = color;
ctx.fillRect(x * SQ,y * SQ,SQ,SQ);
ctx.strokeStyle = "black";;
ctx.linewidth = 1;
ctx.beginPath();
ctx.strokeRect(x * SQ + 1,y * SQ + 1,SQ - 2,SQ - 2);
ctx.strokeRect(x * SQ + 2,y * SQ + 2,SQ - 4,SQ - 4);
// ctx.strokeRect(x * SQ + 2.5,y * SQ + 2.5,SQ - 5,SQ - 5);
ctx.linewidth = 1;
ctx.beginPath();
ctx.strokeRect(x * SQ + 6.5,y * SQ + 6.5,SQ - 13,SQ - 13);
ctx.linewidth = 1;
ctx.beginPath();
ctx.moveto(x * SQ + 2,y * SQ + 2)
ctx.lineto(x * SQ + 6.5,y * SQ + 6.5);
ctx.stroke();
ctx.beginPath();
ctx.moveto(x * SQ + SQ - 2,y * SQ + 2)
ctx.lineto(x * SQ + SQ - 6.5,y * SQ + 6.5);
ctx.stroke();
// Downn
ctx.beginPath();
ctx.moveto(x * SQ + 2,y * SQ - 2 + SQ)
ctx.lineto(x * SQ + 6.5,y * SQ - 6.5 + SQ);
ctx.stroke();
ctx.beginPath();
ctx.moveto(x * SQ + SQ - 2,y * SQ - 2 + SQ)
ctx.lineto(x * SQ - 6.5 + SQ,y * SQ - 6.5 + SQ);
ctx.stroke();
} else {
ctx.fillStyle = color;
ctx.fillRect(x * SQ,SQ);
}
};
// a VACANT (empty) square has this color.
// const VACANT = "rgba(19,18,0.719)";
const VACANT = "transparent";
// Now we define the board array.
let board = [];
// let's create the rows.
for (let r = 0; r < ROW; r++) {
board[r] = [];
// let's create the columns
for (let c = 0; c < COL; c++) {
board[r][c] = VACANT;
// when we first draw the board all the square are empty,so every square has the value "VACANT".
}
}
function drawBoard() {
for (r = 0; r < ROW; r++) {
for (c = 0; c < COL; c++) {
if (board[r][c] != VACANT) {
drawSquare(c,r,board[r][c],"piece")
} else {
drawSquare(c,"board");
}
}
}
}
drawBoard()
//Piece and there color
let score = 0;
const PIECES = [
[Z,"blue"],[S,"rgb(238,132,46)"],[T,"rgb(248,232,232)"],[O,"yellow"],[L,"rgb(245,94,144)"],[I,"purple"],[J,"rgb(121,236,240)"]
]
// Generator random Piece
function NewPiece(canvas) {
let r = randomN = Math.floor(Math.random() * PIECES.length)
return new Piece(PIECES[r][0],PIECES[r][1])
}
function nextPiece() {
r = Math.floor(Math.random() * PIECES.length)
previewPiece = new PreviewPiece(PIECES[r][0],PIECES[r][1]);
xd = r
previewPiece.clear();
previewPiece.draw();
return xd
}
x = nextPiece()
let p = new Piece(PIECES[x][0],PIECES[x][1]);
function Piece(Tetromino,color) {
this.tetromino = Tetromino;
this.color = color;
this.tetrominoN = 0;
this.activeTetromino = this.tetromino[this.tetrominoN];
this.x = 3;
this.y = -2;
// Piece.prototype.draw
this.draw = function() {
for (r = 0; r < this.activeTetromino.length; r++) {
for (c = 0; c < this.activeTetromino.length; c++) {
if (this.activeTetromino[r][c]) {
drawSquare(this.x + c,this.y + r,this.color,"piece");
}
}
}
}
// Piece.prototype.Clear
this.update = function() {
for (r = 0; r < this.activeTetromino.length; r++) {
for (c = 0; c < this.activeTetromino.length; c++) {
if (this.activeTetromino[r][c]) {
update();
}
}
}
}
// Piece.prototype.moveDown
this.moveDown = function() {
if (!this.collide(0,this.activeTetromino)) {
this.update();
this.y++;
this.draw();
// ctx.shadowOffsetY -= SQ
} else {
//generate new Piece
this.lockPiece();
p = new Piece(PIECES[x][0],PIECES[x][1]);
}
if (this.y === -1) {
// ctx.shadowOffsetY -= 1 * SQ
x = nextPiece();
}
}
// Piece.prototype.moveRight
this.moveRight = function() {
if (!this.collide(1,this.activeTetromino)) {
this.update();
this.x++;
this.draw();
}
}
// Piece.prototype.moveLeft
this.moveLeft = function() {
if (!this.collide(-1,this.activeTetromino)) {
this.update();
this.x--;
this.draw();
}
}
// Piece.prototype.rotate
this.rotate = function() {
let nextPat = this.tetromino[(this.tetrominoN + 1) % this.tetromino.length];
let kick = 0;
if (this.collide(0,nextPat)) {
if (this.x > COL / 2) {
kick = -1;
} else {
kick = 1;
}
}
if (!this.collide(kick,nextPat)) {
this.update();
this.x += kick;
this.tetrominoN = (this.tetrominoN + 1) % this.tetromino.length;
this.activeTetromino = this.tetromino[this.tetrominoN];
this.draw();
}
}
// Piece.prototype.collide
this.collide = function(x,piece) {
for (r = 0; r < piece.length; r++) {
for (c = 0; c < piece.length; c++) {
//Empty square skip
if (!piece[r][c]) {
continue;
}
let newX = this.x + c + x;
let newY = this.y + r + y;
if (newX < 0 || newX > COL || newY >= ROW) {
return true;
}
if (newY < 0) {
continue;
}
if (board[newY][newX] != VACANT) { return true; }
}
}
}
this.lockPiece = function() {
for (r = 0; r < this.activeTetromino.length; r++) {
for (c = 0; c < this.activeTetromino.length; c++) {
//skip empty block
if (!this.activeTetromino[r][c]) {
continue;
}
//piece to lock if reaches the top
if (this.y + r < 0) {
//Game over
// alert("Game Over");
//Stop Game
gameOver = true;
if (gameOver) {
// document.getElementById("gameCanvas").style.display = "none"
}
break;
}
//we lock piece when it reaches bottom
board[this.y + r][this.x + c] = this.color
}
}
// remove full rows
for (r = 0; r < ROW; r++) {
let isRowFull = true;
for (c = 0; c < COL; c++) {
isRowFull = isRowFull && (board[r][c] != VACANT);
}
if (isRowFull) {
for (y = r; y > 1; y--) {
for (c = 0; c < COL; c++) {
// ctx.clearRect(y * SQ,c * SQ,SQ);
board[y][c] = board[y - 1][c];
}
}
//the top row board[0][...] has no row above it
for (c = 0; c < COL; c++) {
board[0][c] = VACANT;
// ctx.clearRect(r * SQ,SQ);
}
//Increase score
score += 100;
console.log(score)
}
// if (this.x > 0) {
// // x = nextPiece();
// }
}
update();
}
}
function update() {
ctx.clearRect(0,canvas.width,canvas.height)
drawBoard();
}
let dropStart = Date.Now();
let gameOver = false;
let speed = 1000;
let Prevscore = 0;
function drop() {
let Now = Date.Now();
let delta = Now - dropStart;
if (delta > speed) {
// p.x = 3;
// p.y = -1
p.moveDown()
dropStart = Date.Now();
}
if (!gameOver) {
requestAnimationFrame(drop)
}
document.getElementById("sc").innerHTML = score;
if (score - Prevscore > 1000) {
speed -= 10;
Prevscore = score;
}
}
drop()
document.addEventListener("keydown",CONTROL);
function CONTROL(event) {
if (event.keyCode == 37) {
if (!gameOver) {
event.preventDefault();
p.moveLeft();
// dropStart = Date.Now();
}
} else if (event.keyCode == 38) {
if (!gameOver) {
event.preventDefault();
p.rotate();
// dropStart = Date.Now();
}
} else if (event.keyCode == 39) {
if (!gameOver) {
event.preventDefault();
p.moveRight()
// dropStart = Date.Now();
}
} else if (event.keyCode == 40) {
if (!gameOver) {
event.preventDefault();
score++;
p.moveDown();
}
}
}
document.getElementById("gameCanvas").addEventListener("click",function(e) {
e.preventDefault();
p.rotate();
dropStart = Date.Now();
})
let TouchX,TouchY,MoveX = 0,MoveY = 0,XDiff,YDiff;
document.getElementById("GameArea").addEventListener("touchstart",function(e) {
TouchX = e.touches[0].clientX
TouchY = e.touches[0].clientY
// console.log("Tx: ",TouchX,"Ty: ",TouchY)
document.getElementById("GameArea").addEventListener('touchmove',function(e) {
e.preventDefault() // prevent scrolling when inside DIV
XDiff = TouchX - MoveX;
YDiff = TouchY - MoveY;
if (Math.abs(e.touches[0].clientX - MoveX) > 15) {
if (Math.abs(XDiff) > Math.abs(YDiff)) {
if (XDiff < 0) {
//Right Swipe;
p.moveRight();
} else {
// Left Swipe
p.moveLeft();
}
}
} else if (Math.abs(e.touches[0].clientY - MoveY) > 0) {
if (Math.abs(XDiff) < Math.abs(YDiff)) {
if (XDiff < 0) {
//Down Swipe;
score++;
p.moveDown();
}
}
}
MoveX = e.touches[0].clientX;
MoveY = e.touches[0].clientY;
// console.log("x: ",e.touches[0].clientX,"y: ",e.touches[0].clientY);
},{ passive: false })
},false);
function drawSquarePreview(x,color) {
pre.fillStyle = color;
pre.fillRect(x * SQ,SQ);
pre.strokeStyle = "black";;
pre.linewidth = 1;
pre.beginPath();
pre.strokeRect(x * SQ + 1,SQ - 2);
pre.strokeRect(x * SQ + 2,SQ - 4);
// pre.strokeRect(x * SQ + 2.5,SQ - 5);
pre.linewidth = 1;
pre.beginPath();
pre.strokeRect(x * SQ + 6.5,SQ - 13);
pre.linewidth = 1;
pre.beginPath();
pre.moveto(x * SQ + 2,y * SQ + 2)
pre.lineto(x * SQ + 6.5,y * SQ + 6.5);
pre.stroke();
pre.beginPath();
pre.moveto(x * SQ + SQ - 2,y * SQ + 2)
pre.lineto(x * SQ + SQ - 6.5,y * SQ + 6.5);
pre.stroke();
// Down
pre.beginPath();
pre.moveto(x * SQ + 2,y * SQ - 2 + SQ)
pre.lineto(x * SQ + 6.5,y * SQ - 6.5 + SQ);
pre.stroke();
pre.beginPath();
pre.moveto(x * SQ + SQ - 2,y * SQ - 2 + SQ)
pre.lineto(x * SQ - 6.5 + SQ,y * SQ - 6.5 + SQ);
}
function PreviewPiece(Tetromino,color) {
this.tetromino = Tetromino;
this.color = color;
this.tetrominoN = 0;
this.activeTetromino = this.tetromino[this.tetrominoN];
this.x = 0;
this.y = 0;
this.draw = function() {
for (r = 0; r < this.activeTetromino.length; r++) {
for (c = 0; c < this.activeTetromino.length; c++) {
if (this.activeTetromino[r][c]) {
drawSquarePreview(this.x + c,this.color);
}
}
}
}
this.clear = function() {
pre.clearRect(0,preview.width,preview.height);
}
}
解决方法
回答我自己的问题很有趣,但是,我在梦中找到了我的答案,所以让我把它放在这里,以便如果有人想知道答案得到帮助,因为,
这就是社区所做的。
所以我们不要再浪费时间了。
check how the game looks after the edit
因此,首先我创建了一个名为 shadow 的新原型函数,然后使用 for 循环检查 tetromino 碰撞的位置返回 for 循环实例(Tetromino 碰撞的位置)减 1。因为我们想在 1 步之前绘制阴影像这样碰撞
this.shadow = function() {
for (i = 1; i < ROW; i++) {
if (this.collide(0,i,this.activeTetromino)) {
return i - 1 //i is the point of collision therefore we draw piece one step before collision
} else { continue; }
}
}
然后,我更新了我的绘图功能 像这样
this.draw = function() {
let sha = this.shadow();
for (r = 0; r < this.activeTetromino.length; r++) {
for (c = 0; c < this.activeTetromino.length; c++) {
if (this.activeTetromino[r][c]) {
drawSquare(this.x + c,this.y + r,this.color,"piece");
// this will also work without the if condition
if (this.y + r !== this.y + r + sha) {
drawSquare(this.x + c,this.y + sha + r,"piece","shadow")
}
}
}
}
}
在这个函数中,我将从 shadow 函数返回的值存储在一个名为 sha
的变量中,然后绘制 tetromino 块,将 y 更改为 this.y + sha + r
并传递一个额外的参数来绘制阴影 & 你猜对了没错,drawSquare 函数中有一个更新,可以绘制一个不同的正方形,这样玩家就可以找出哪一块是阴影,哪一块是实际的一块。在这里你可以做任何事情来让它与众不同,比如只给它灰色或只绘制笔触边界或更改 globalApha 值,所以我选择像这样更改全局 alpha 值
function drawSquare(x,y,color,stroke,T) {
ctx.globalAlpha = 1;
if (stroke === "piece") {
if (T === "shadow") { ctx.globalAlpha = 0.4; }
ctx.fillStyle = color;
ctx.fillRect(x * SQ,y * SQ,SQ,SQ);
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
if (T === "shadow") { ctx.lineWidth = 3; };
ctx.beginPath();
ctx.strokeRect(x * SQ + 1,y * SQ + 1,SQ - 2,SQ - 2);
ctx.strokeRect(x * SQ + 2,y * SQ + 2,SQ - 4,SQ - 4);
// ctx.strokeRect(x * SQ + 2.5,y * SQ + 2.5,SQ - 5,SQ - 5);
ctx.lineWidth = 1;
if (T === "shadow") { ctx.lineWidth = 2; };
ctx.beginPath();
ctx.strokeRect(x * SQ + 6.5,y * SQ + 6.5,SQ - 13,SQ - 13);
ctx.lineWidth = 2;
// if (T === "shadow") { ctx.lineWidth = 5; };
ctx.beginPath();
ctx.moveTo(x * SQ + 2,y * SQ + 2)
ctx.lineTo(x * SQ + 6.5,y * SQ + 6.5);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x * SQ + SQ - 2,y * SQ + 2)
ctx.lineTo(x * SQ + SQ - 6.5,y * SQ + 6.5);
ctx.stroke();
// Downn
ctx.beginPath();
ctx.moveTo(x * SQ + 2,y * SQ - 2 + SQ)
ctx.lineTo(x * SQ + 6.5,y * SQ - 6.5 + SQ);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x * SQ + SQ - 2,y * SQ - 2 + SQ)
ctx.lineTo(x * SQ - 6.5 + SQ,y * SQ - 6.5 + SQ);
ctx.stroke();
}
}
如果您正在寻找这个,希望这对您有所帮助。如果您有更好的方法来进行优化,请随时回答。我不是一个很好的解释者,这是我的问题以及这个表格的答案,所以请原谅任何语法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。