javascript – 类似俄罗斯方块的游戏中的硬件
作者:互联网
我正在构建一个类似俄罗斯方块的游戏,当你有一条完整的线条时我不会删除一条线,而是移除所有连接的部分.清除碎片后,这让我难以理解.
请参阅this example,了解我正在尝试的快速和脏的版本.
function Board (width, height) {
this.width = width;
this.height = height;
this.board = [];
this.pieces = [];
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
if (!this.board[y]) {
this.board[y] = [];
}
this.board[y][x] = null;
}
}
this.canPlace = function(piece, at) {
for (var y = 0; y < piece.getHeight(); y++) {
for (var x = 0; x < piece.getWidth(); x++) {
if ((y+at.y >= this.height) || this.board[y+at.y][x+at.x]) {
return false;
}
}
}
return true;
}
this.hasFullLine = function(line) {
for (var x = 0; x < this.width; x++) {
if (!this.board[line][x]) {
return false;
}
}
return true;
}
this.place = function(piece) {
var position = piece.getPosition();
var shape = piece.getShape();
for (var y = 0; y < piece.getHeight(); y++) {
for (var x = 0; x < piece.getWidth(); x++) {
if (shape[y][x]) {
this.board[y+position.y][x+position.x] = piece;
}
}
}
if (this.pieces.indexOf(piece) === -1) {
this.pieces.push(piece);
}
piece.render();
}
this.hardDropPieces = function() {
var pieces = this.pieces.slice();
pieces = pieces.sort(function(a,b) {
var aBottom = a.getPosition().y+a.getHeight();
var bBottom = b.getPosition().y+b.getHeight();
return bBottom-aBottom;
});
for (var i = 0; i < pieces.length; i++) {
this.hardDrop(pieces[i]);
}
}
this.hardDrop = function(piece) {
var position = piece.getPosition();
this.clearArea(piece);
while(this.canPlace(piece, {x: piece.getPosition().x, y: piece.getPosition().y+1})) {
piece.setPosition(piece.getPosition().x, piece.getPosition().y+1);
}
this.place(piece);
}
this.clearArea = function(piece) {
var position = piece.getPosition();
var shape = piece.getShape();
for (var y = 0; y < piece.getHeight(); y++) {
for (var x = 0; x < piece.getWidth(); x++) {
if (shape[y][x]) {
this.board[y+position.y][x+position.x] = null;
}
}
}
}
this.remove = function(piece) {
this.clearArea(piece);
this.pieces.splice(this.pieces.indexOf(piece),1);
}
this.clearPiecesOnLine = function(line) {
var piecesToClear = [];
for (var x = 0; x < this.width; x++) {
var piece = this.board[line][x];
if (piecesToClear.indexOf(piece) === -1) {
piecesToClear.push(piece);
}
}
for (var i = 0; i < piecesToClear.length; i++) {
this.remove(piecesToClear[i]);
}
return piecesToClear;
}
this.toString = function() {
var str = "";
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
str += this.board[y][x] ? "1" : "0";
}
str += "\n";
}
return str;
}
}
function Piece (shape, fill, stroke, paper, cellWidth) {
this.shape = shape;
this.fill = fill;
this.stroke = stroke;
this.cellWidth = cellWidth;
this.svgGroup = paper.g().append();
this.position = {x:0, y:0};
this.width = this.shape[0].length;
this.height = this.shape.length;
this.removed = false;
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
if (this.shape[y][x]) {
var rect = paper.rect(x*cellWidth, y*cellWidth, cellWidth, cellWidth);
rect.attr({
fill: this.fill,
stroke: this.stroke
});
rect.appendTo(this.svgGroup);
}
}
}
this.setPosition = function(x, y) {
this.position.x = x;
this.position.y = y;
}
this.getPosition = function() {
return this.position;
}
this.render = function() {
var matrix = new Snap.Matrix();
matrix.translate(this.position.x*cellWidth, this.position.y*cellWidth);
this.svgGroup.attr({
transform: matrix
});
}
this.getWidth = function() {
return this.width;
}
this.getHeight = function() {
return this.height;
}
this.getShape = function() {
return this.shape;
}
this.delete = function() {
this.svgGroup.remove();
}
this.isRemoved = function() {
return this.removed;
}
}
var shapes = [
[
[0,1,0],
[1,1,1]
],
[
[1,1,1,1]
],
[
[1,1,1],
[0,1,0],
[1,1,1]
],
[
[1,1],
[1,1]
],
[
[1,1,1],
[0,1,1],
[0,1,1],
[1,1,1]
],
[
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
],
[
[1,0,1],
[1,1,1]
]
];
var width = 10;
var height = 20;
var cellWidth = 20;
var paper = Snap("#svg");
var board = new Board(width, height);
var tick = 500;
paper.attr({
width: cellWidth*width,
height: cellWidth*height
});
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
var rect = paper.rect(x*cellWidth, y*cellWidth, cellWidth, cellWidth);
rect.attr({
fill: "#ccc",
stroke: "#ddd"
});
}
}
var piece = new Piece(shapes[0], "red", "white", paper, cellWidth);
piece.setPosition(0, 18);
board.place(piece);
piece = new Piece(shapes[1], "orange", "white", paper, cellWidth);
piece.setPosition(3, 19);
board.place(piece);
piece = new Piece(shapes[2], "yellow", "white", paper, cellWidth);
piece.setPosition(2, 8);
board.place(piece);
piece = new Piece(shapes[3], "green", "white", paper, cellWidth);
piece.setPosition(0, 17);
board.place(piece);
piece = new Piece(shapes[4], "blue", "white", paper, cellWidth);
piece.setPosition(2, 15);
board.place(piece);
piece = new Piece(shapes[5], "indigo", "white", paper, cellWidth);
piece.setPosition(1, 11);
board.place(piece);
piece = new Piece(shapes[6], "violet", "white", paper, cellWidth);
piece.setPosition(7, 17);
piece.render();
function update() {
if (piece.isRemoved()) {
return;
}
var position = piece.getPosition();
if (board.canPlace(piece, {x:position.x,y:position.y+1})) {
piece.setPosition(position.x,position.y+1);
board.place(piece);
for (var y = 0; y < piece.getHeight(); y++) {
if (board.hasFullLine(piece.getPosition().y+y)) {
var removed = board.clearPiecesOnLine(piece.getPosition().y+y);
setTimeout(function() {
for (var i = 0; i < removed.length; i++) {
removed[i].delete();
}
board.hardDropPieces();
},tick);
}
}
}
}
setTimeout(update, tick);
这几乎是董事会逻辑的要点.放置的碎片通过引用保存在一个数组中,清理后我将那些未被最低点移除的碎片分类,然后将它们中的每一个尽可能地丢弃.
当没有任何部件相互连接时,这种方法可以工作,但是当它们存在时我就无法弄清楚如何进行,如this example所示.
显然,蓝色部分是最低点,但它不能向下移动,因为绿色部分位于其内部.我考虑合并它们并丢弃它们,但这会导致其他问题.就像this case会发生什么?
我很确定我只是很厚,并且有一种相对简单的方法可以解决这个问题……?任何帮助将非常感激!
所有部分都是自动生成的,并且有太多的部分,并且可以随时添加更多部分,以便不做出一般解决方案.
解决方法:
我找到了两个缺少逻辑的部分.第一部分是你进行滴剂的地方.你需要为每个块一步一步地做,然后继续这样做,直到你不再丢弃.像这样
this.hardDropPieces = function() {
var pieces = this.pieces.slice();
pieces = pieces.sort(function(a,b) {
var aBottom = a.getPosition().y+a.getHeight();
var bBottom = b.getPosition().y+b.getHeight();
return bBottom-aBottom;
});
var canStillDrop = true;
while (canStillDrop) { // Keep going until we can't drop no more
canStillDrop = false;
for (var i = 0; i < pieces.length; i++) {
canStillDrop = this.hardDrop(pieces[i]) ? true : canStillDrop;
}
}
}
this.hardDrop = function(piece) {
var didDrop = false;
var position = piece.getPosition();
this.clearArea(piece);
if(this.canPlace(piece, {x: position.x, y: position.y+1})) {
piece.setPosition(position.x, position.y+1);
didDrop = true; // Oh, I see we have dropped
}
this.place(piece);
return didDrop; // Did we drop a spot? Then we should keep going
}
第二部分是你可以使用一点递归来检查是否有任何阻止你掉落的瓷砖实际连接到地板上.这个你已经认识到的:
this.canPlace = function(piece, at) {
// Will it fall below the floor? Then it's a no-go
if (piece.getHeight()+at.y > this.height) {
return false;
}
// Loop through shape
for (var y = 0; y < piece.getHeight(); y++) {
for (var x = 0; x < piece.getWidth(); x++) {
// Ignore non-shape positions
if (!piece.shape[y][x]) continue;
// Get piece at current shape position
var pieceAtPos = this.board[y+at.y][x+at.x];
// Is the piece (or any that it's resting on) connected to the floor?
if (pieceAtPos && pieceAtPos!==piece && this.isPieceGrounded(pieceAtPos, [piece]) ){
return false;
}
}
}
return true;
}
但是也请问isPieceGrounded.
this.isPieceGrounded = function(piece, testedPieces) {
// Check all positions BELOW the piece
var at = { x: piece.getPosition().x, y: piece.getPosition().y+1 };
// Is it connected to the floor?
if (piece.getHeight()+at.y+1 >= this.height) {
return true;
}
// *Sigh* Loop through THIS whole piece
for (var y = 0; y < piece.getHeight(); y++) {
for (var x = 0; x < piece.getWidth(); x++) {
if (!piece.shape[y][x]) continue;
var pieceAtPos = this.board[y+at.y][x+at.x];
if (pieceAtPos && pieceAtPos!==piece && testedPieces.indexOf(pieceAtPos) < 0) {
// Keep a list of all tested pieces so we don't end up in an infinite loop by testing them back and forth
testedPieces.push(pieceAtPos);
// Let's test that one and all its connected ones as well
if (this.isPieceGrounded(pieceAtPos, testedPieces)) {
return true;
};
}
}
}
return false;
}
http://jsfiddle.net/971yvc8r/2/
我确信有很多不同的解决方案,但我认为这样的事情可能是最有效的.
标签:javascript,html5,game-physics,tetris 来源: https://codeday.me/bug/20190702/1358554.html