Статьи

На этот раз — третья часть создания тетриса в скомпилированном скрипте JavaFX

Как я упоминал в предыдущем посте (который я случайно опубликовал преждевременно), я говорил о JavaFX Script на Sun Tech Days в Сиднее, Австралия. Это был отличный опыт, так как это была хорошо организованная, информативная конференция. Конечно, Сидней — красивый город, наполненный замечательными людьми.

Tetrisstacking_2

Кроме того, этот пост ссылается на первые две статьи в этой серии Tetris, поэтому, пожалуйста, взгляните на эти статьи, чтобы узнать, где мы находимся:

1) Давайте создадим игру тетрис в скомпилированном скрипте JavaFX

2) Создание программы Tetris (часть вторая) в скомпилированном скрипте JavaFX

Во время конференции я добился определенного прогресса в приложении Tetris и использовал его в одной из своих презентаций. Пожалуйста, обратитесь к скриншоту, показанному выше.

Эта версия приложения Tetris не является на 100% функциональной и не содержит ошибок, но ее вполне достаточно для преподавания концепций JavaFX Script в презентации. Одна из моих следующих публикаций будет более полнофункциональной игрой в тетрис (например, слой блоков исчезнет при заполнении). В этом посте эта игра будет показана как апплет JavaFX Script, работающий внутри браузера. Посмотрите на исходный код ниже, и вы заметите, что я изменил довольно много вещей из последней версии. Например, пользовательский компонент TetrisPlayingField привязан к модели всех квадратов в игровом поле.

TetrisMain.fx:

/ * 
* TetrisMain.fx - основная программа для скомпилированной игры JavaFX Script Tetris
*
* Разработана в 2008 году Джеймсом Уивером (jim.weaver на lat-inc.com)
* в качестве примера скомпилированного скрипта JavaFX.
* /
пакет tetris_ui;

импорт javafx.ui. *;
импорт javafx.ui.canvas. *;
import java.lang.System;
import tetris_model. *;

Frame {
var canvas: Canvas
width: 350
height: 500
title: "TetrisJFX"
background: Color.LIGHTGREY
content:
StackPanel {
content: [
Canvas {
content:
ImageView {
image:
Image {
url: "images / background.jpg"
}
}
},
BorderPanel {
var model =
TetrisModel {}
center:
FlowPanel {
alignment: Alignment.LEADING
vgap: 20
hgap: 20
content: [
Canvas {
content:
TetrisPlayingField {
model: model)
}
},
Label {
text: bind "<html> <font color = # B0E0E6 size = 24>
{model.score} </ font> </ html>"
}
]
}
bottom:
FlowPanel {
alignment: Alignment.LEADING
content: [
Button {
text: «Play»
передний план: Color.DARKBLUE
action:
function () {
model.t.start ();
}
},
Кнопка {
текст: «Повернуть»
передний план:
действие Color.DARKBLUE :
function () {
model.rotate90 ();
}
},
Кнопка {
текст: «Левый»
передний план: Color.DARKBLUE
action:
function () {
model.moveLeft ();
}
},
Кнопка {
текст: «Правый»
передний план: Color.DARKBLUE
action:
function () {
model.moveRight ();
}
}
]
}
}
]
}
visible: true
onClose:
function (): Void {
System.exit (0);
}
}

 

TetrisPlayingField.fx:

/ * 
* TetrisPlayingField.fx -
* Пользовательский графический компонент, который является пользовательским интерфейсом
* игрового поля.
*
* Разработано в 2008 году Джеймсом Л. Уивером (jim.weaver на lat-inc.com)
* в качестве примера скомпилированного скрипта JavaFX.
*
* /
package tetris_ui;

импорт javafx.ui. *;
импорт javafx.ui.canvas. *;
import java.lang.System;
import tetris_model. *;

класс TetrisPlayingField extends CompositeNode {
закрытый статический атрибут squareOutlineColor = Color.BLACK;
закрытый статический атрибут squareOutlineWidth = 1;
модель открытого атрибута: TetrisModel;
публичная функция composeNode (): Node {
Group {
content: bind [
Rect {
x: 0
y: 0
width: model.NUM_COLS * model.SQUARE_SIZE
height: model.NUM_ROWS * model.SQUARE_SIZE
strokeWidth: 1
штрих: Color.BLACK
заливка: Color.BLUE
непрозрачность: .5
},
для (ячейка в model.fieldCells,
где ячейка <> TetrisShapeType.NONE) {
Rect {
var yPos: Integer = indexof ячейки / model.NUM_COLS
x: (indexof ячейки% model.NUM_COLS) .intValue () * model.SQUARE_SIZE
y: yPos * model.SQUARE_SIZE
ширина: model.SQUARE_SIZE
height: model.SQUARE_SIZE
fill: cell.squareColor
stroke: squareOutlineColour
strokeWidth: squareOutlineWidth
}
}
]
}
}
}

 

TetrisModel.fx:

/ * 
* TetrisModel.fx - модель, лежащая в основе пользовательского интерфейса Tetris
*
* Разработана в 2008 году Джеймсом Уивером (jim.weaver на lat-inc.com)
* для использования в качестве примера скомпилированного скрипта JavaFX.
*
* /
package tetris_model;

импорт javafx.ui.animation. *;
import java.lang.System;
import com.sun.javafx.runtime.PointerFactory;
импорт java.lang.Double;

открытый класс TetrisModel {
/ ** размер каждого тетромино в пикселях * /
открытый статический атрибут SQUARE_SIZE = 20;

/ ** Количество рядов в игровом поле * /
открытый статический атрибут NUM_ROWS = 20;

/ ** Количество столбцов в игровом поле * /
открытый статический атрибут NUM_COLS = 10;

закрытый атрибут stopDropping: Boolean;

/ **
* Последовательность объектов, представляющих
* тип фигур (включая фигуры) в каждой ячейке игрового поля
* /
открытый атрибут fieldCells: TetrisShapeType [] =
для (i в [1 .. (NUM_ROWS * NUM_COLS)]]) {
TetrisShapeType.NONE;
};


/ **
* Активный тип фигуры тетромино.
* /
открытый атрибут activeShapeType: TetrisShapeType;

оценка публичного атрибута: целое число = 10000;

/ **
* Это значение увеличивается с помощью механизма анимации KeyFrame
* и представляет строку, в которой в данный момент находится основной блок.
* /
открытый атрибут a: целое число при замене (oldVal) {
if (a == 0) {
stopDropping = false;
}
if (not stopDropping) {
// Обновить счет. ТОДО: Реализовать реальный счет позже
: + = 100;

// Удалить tetromino из игрового поля
updateFieldCells (tetrominoHorzPos, oldVal, tetrominoAngle, true);

if (canMoveDown (tetrominoHorzPos, a, tetrominoAngle)) {
// удалось переместиться вниз, поэтому поместите тетромино соответственно
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, false);
}
else {
System.out.println ("Невозможно сдвинуться с места !!!!!!!!");
updateFieldCells (tetrominoHorzPos, oldVal, tetrominoAngle, false);
stopDropping = true;
}
}

if (a> = stopValue) {
activeShapeType = TetrisShapeType.randomShapeType ();
tetrominoAngle = 0;
}
};
закрытый атрибут pf = PointerFactory {};
закрытый атрибут bpa = bind pf.make (a);
закрытый атрибут pa = bpa.unwrap ();
закрытый атрибут interpolate = NumberValue.LINEAR;
закрытый атрибут stopValue = NUM_ROWS + 2;
открытый атрибут t =
временная шкала {
keyFrames: [
KeyFrame {
keyTime: 0s;
KeyValues:
NumberValue {
target: pa;
значение: 0;
интерполировать: связывать интерполировать
}
},
KeyFrame {
keyTime: 10s;
keyValues:
NumberValue {
target: pa;
значение: bind stopValue
interpolate: bind interpolate
}
}
]
repeatCount: Double.POSITIVE_INFINITY
};
открытый атрибут tetrominoAngle: Number;
открытый атрибут tetrominoHorzPos: Number = (NUM_COLS / 2) как целое число;

публичная функция rotate90 (): Void {
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, true);
tetrominoAngle = computeNewAngle (tetrominoAngle, 90);
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, false);
}

открытая функция computeNewAngle (originalRotationAngle: Integer, степеньToRotate): Integer {
((originalRotationAngle + градусовToRotate)% (activeShapeType.rotateStates * 90)) как целое число;
}

public function moveLeft (): Void {
if (tetrominoHorzPos> 0) {
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, true);
tetrominoHorzPos--;
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, false);
}
}

публичная функция moveRight (): Void {
// TODO: нужно разрешить частям сталкиваться с
правой стороной. На данный момент

жесткий код 3. if (tetrominoHorzPos <NUM_COLS - 3) {
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, true);
tetrominoHorzPos ++;
updateFieldCells (tetrominoHorzPos, a, tetrominoAngle, false);
}
}

/ **
* Сохраняет последовательность fieldCells (которая представляет собой
* ячейки на игровом поле) обновленной, чтобы отражать реальность.
* укажите в строке и столбце, что * основной блок был
* расположен, а также прежний угол тетромино.
* Новая строка, столбец, угол, а также тип фигуры
* хранятся в модели, поэтому не нужно передавать их.
* /
public function updateFieldCells (oldX: Integer, oldY: Integer, oldAngle: Integer, remove: Boolean): Void {
// Извлечь форму из своего старого местоположения на игровом поле
для (oldCell в TetrisShapeType.squarePositionsForRotatedShape (activeShapeType,
oldAngle) )) {
fieldCells [(oldY + oldCell.y) * NUM_COLS + oldX + oldCell.x] =
if (удалить) TetrisShapeType.NONE else activeShapeType;
}
}

открытая функция canMoveDown (oldX: Integer, oldY: Integer, oldAngle: Integer): Boolean {
var retVal = true;
for (oldCell в TetrisShapeType.squarePositionsForRotatedShape (activeShapeType,
oldAngle)) {
// Сначала проверьте, находится ли тетромино внизу
// игрового поля
if ((oldY + oldCell.y) * NUM_COLS + oldX + oldCell.x> sizeof fieldCells) {
retVal = false;
}
// Теперь проверим, не мешает ли другое тетромино двигаться вниз,
если if (fieldCells [(oldY + oldCell.y) * NUM_COLS + oldX + oldCell.x] <>
TetrisShapeType.NONE) {
System.out.println ( "{(oldY + oldCell.y) * NUM_COLS + oldX + oldCell.x},
{fieldCells [(oldY + oldCell.y) * NUM_COLS +
oldX + oldCell.x] .name}");
retVal = false;
}
}
return retVal;
}
}

 

TetrisShapeType.fx

/ * 
* TetrisShapeType.fx - тип фигуры тетриса,
* *, J, L, O, S, T и Z
*
* Разработано в 2008 году Джеймсом Л. Уивером (jim.weaver на lat-inc.com)
* служить примером скомпилированного скрипта JavaFX.
*
* /
package tetris_model;

импорт javafx.ui. *;
import java.awt.Point;
import java.lang.Math;
import java.lang.System;

/ **
* Этот класс содержит информацию о модели для каждого типа
* тетромино (кусок тетриса).
* /
public class TetrisShapeType {
идентификатор открытого атрибута: Integer;
публичный атрибут name: String;

/ **
* Последовательность, содержащая положения каждого квадрата в
типе * tetromino. Первый элемент в последовательности - это
* тот, вокруг которого будет вращаться тетромино.
* Обратите внимание, что тип "O" tetromino не вращается.
* /
открытый атрибут squarePositions: Point [];

// открытый атрибут allowRotate: Boolean = true;

/ **
* Допустимые значения: 1 (для формы «O», 2 (для фигур «S», «Z» и «I»)
* и 4 (для фигур «L», «J» и «T») )
* /
открытый атрибут rotateStates: Integer = 4;

открытый атрибут squareColor: Color;

/ ** "NONE"shape (представляет отсутствие формы) * /
открытый статический атрибут NONE =
TetrisShapeType {
id: 0
name: "."
squarePositions: [
новая точка (0, 0),
новая точка (0, 0),
новая точка (0, 0),
новая точка (0, 0)
]
squareColor: Color.SILVER
};

/ ** Форма "I" (четыре квадрата по прямой) * /
открытый статический атрибут I =
TetrisShapeType {
id: 1
name: "I"
squarePositions: [
новая точка (0, 0),
новая точка (-1, 0),
новая точка (1, 0),
новая точка (2, 0)
]
squareColor: Color.SILVER
rotateStates: 2
};

/ ** Форма "T" (выглядит как полная "T") * /
открытый статический атрибут T =
TetrisShapeType {
id: 2
name: "T"
squarePositions: [
new Point (0, 0),
new Point (-1) , 0),
новая точка (1, 0),
новая точка (0, 1)
]
squareColor: Color.HOTPINK
};

/ ** Форма "L" (выглядит как "L") * /
открытый статический атрибут L =
TetrisShapeType {
id: 3
name: "L"
squarePositions: [
новая точка (0, 0),
новая точка (-1, 0),
новая точка (1, 0),
новая точка (-1,1)
]
squareColor: Color.LIGHTBLUE
};

/ ** Форма "J" (выглядит примерно как "J", но
* больше похожа на "L" назад) * /
открытый статический атрибут J =
TetrisShapeType {
id: 4
name: "J"
squarePositions: [
new Point (0, 0),
новая точка (-1, 0),
новая точка (1, 0),
новая точка (1, 1)
]
squareColor: Color.YELLOW
};

/ ** Форма "S" (выглядит примерно как "S") * /
открытый статический атрибут S =
TetrisShapeType {
id: 5
name: "S"
squarePositions:[
Новая точка (0, 0),
новая точка (1, 0),
новая точка (-1, 1),
новая точка (0, 1)
]
squareColor: Color.LIGHTGREEN
rotateStates: 2
};

открытый статический атрибут Z =
TetrisShapeType {
id: 6
name: "Z"
squarePositions: [
новая точка (0, 0),
новая точка (-1, 0),
новая точка (0, 1),
новая точка (1, 1)
]
squareColor: Color.ORANGE
rotateStates: 2
};

/ ** Форма "O" (выглядит как "O", но
* больше похожа на квадрат) * /
public static attribute O =
TetrisShapeType {
id: 7
name: "O"
squarePositions: [
новая точка (0, 0),
новая точка (0, 1),
новая точка (1, 0),
новая точка (1, 1)
]
squareColor: Color.RED
rotateStates: 1
};

/ **
* Последовательность типов фигур для использования при генерации
* случайных типов фигур.
* /
закрытый статический атрибут allShapeTypes: TetrisShapeType [];

/ **
* Функция, которая возвращает случайный TetrisShapeType
* /
публичная статическая функция randomShapeType (): TetrisShapeType {
if (sizeof allShapeTypes <= 0) {
вставить I в allShapeTypes;
вставить T в allShapeTypes;
вставить L в allShapeTypes;
вставить J в allShapeTypes;
вставить S в allShapeTypes;
вставить Z в allShapeTypes;
вставить O в allShapeTypes;
}
allShapeTypes [(Math.random () * sizeof allShapeTypes) как Integer]
}

/ **
* Функция, которая возвращает squarePositions данного TetrisShapeType
* под заданным углом поворота. Это могло бы использовать функции триггера
*, но случаи достаточно просты, чтобы использовать выражения if / else.
* /
публичная статическая функция
squarePositionsForRotatedShape (shapeType: TetrisShapeType, rotAngle: Integer): Point [] {
for (position в shapeType.squarePositions) {
var newX = position.x;
var newY = position.y;
if (rotAngle == 90) {
newX = if (position.y == 0) 0 else position.y * -1;
newY = if (position.x == 0) 0 else position.x;
}
else if (rotAngle == 180) {
newX = position.x * -1;
newY = position.y * -1;
}
else if (rotAngle == 270) {
newX = if (position.y == 0) 0 else position.y;
newY = if (position.x == 0) 0 else position.x * -1;
}
новая точка (newX, newY);
}
}
}

 

Вы, возможно, заметили, что факторинг класс TetrisShape.fx кстати. Будет сделано много улучшений, но мы доберемся до места вместе! Как всегда, пожалуйста, дайте мне знать, если у вас есть вопросы.

С уважением,
Джим Уивер
JavaFX Script: динамические сценарии Java для многофункциональных интернет-приложений и приложений на стороне клиента.

Немедленная загрузка электронных книг (PDF) доступна на сайте книги Apress.