Прочитав про конкурс Tower Defence, у меня сразу возникла идея создать мир вечной темноты.
Чтобы хоть что-то увидеть, нужно построить световую башню для освещения проползающих мимо существ.
Под катом описана реализация этой идеи на JavaFX.
На сайте конкурса можно скачать начальный движок и следуя инструкциям описать свои башни и снаряды.
Для начала создадим световую башню, в которой переопределим скорострельность, радиус поражения, а в методе fire() зададим тип выстреливаемого снаряда.
JavaFX предоставляет компонент ShapeSubtract, который позволяет отрисовывать геометрические фигуры с вырезанными областями.
Все игровое пространство будет закрыто черным квадратом. В качестве области освещаемой световым снарядом будем использовать окружность.
Для анимации освещаемой области воспользуемся классом Timeline, который будет измненять переменную radius от ее начального значения до конечного. А также свяжем атрибут radius окружности с переменной radius с помощью оператора bind.
Правда в этом случае мы не получим ожидаемого эффекта. Т.е. радиус окружности будет изменяться при изменении переменной радиус, но вычитание областей произойдет только один раз в самом начале.
Добится желаемого результата можно поставив оператор bind перед вычитаемой окружностью. В этом случае мы связываем вычитаемую фигуру с выражением справа, и при изменении любой переменной, входящей в выражение, будет также изменяться компонент ShapeSubtract.
Зададим класс LightElem, который будет содержать атрибуты освещаемой области. При взрыве снаряда будем создавать LightElem, задавать его координаты и анимировать радиус освещаемой области.
Для отрисовки освещаемой области теперь нужно пройтись по последовательности элементов LightElem и создать окружности, которые будут вычитаться из затемненной области.
Чтобы хоть что-то увидеть, нужно построить световую башню для освещения проползающих мимо существ.
Под катом описана реализация этой идеи на JavaFX.
Башни и снаряды
На сайте конкурса можно скачать начальный движок и следуя инструкциям описать свои башни и снаряды.
Для начала создадим световую башню, в которой переопределим скорострельность, радиус поражения, а в методе fire() зададим тип выстреливаемого снаряда.
public class LightTower extends Tower {Затем определим световой снаряд, в методе explode() которого нужно указать, что случается со снарядом при взрыве.
override var fireRate = 10s;
override var fireRadius = 100;
override function fire(start: Point2D, end: Point2D): Void {
LightBall { field: field damage: damage start: start end: end }
}
}
public class LightBall extends Bullet {
override var damageRadius: Number = 120;
override function explode() {
// explosion algorithm
}
}
Компонент ShapeSubtract
JavaFX предоставляет компонент ShapeSubtract, который позволяет отрисовывать геометрические фигуры с вырезанными областями.
Все игровое пространство будет закрыто черным квадратом. В качестве области освещаемой световым снарядом будем использовать окружность.
ShapeSubtract { |
var radius = 5.0;
Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: at (5s) {radius => 75.0 tween Interpolator.LINEAR }
}.play();
ShapeSubtract {
a: Rectangle { width: 200 height: 200 fill: Color.BLACK }
b: Circle {
radius: bind radius
centerX: 100
centerY: 100
}
}
Правда в этом случае мы не получим ожидаемого эффекта. Т.е. радиус окружности будет изменяться при изменении переменной радиус, но вычитание областей произойдет только один раз в самом начале.
Добится желаемого результата можно поставив оператор bind перед вычитаемой окружностью. В этом случае мы связываем вычитаемую фигуру с выражением справа, и при изменении любой переменной, входящей в выражение, будет также изменяться компонент ShapeSubtract.
var radius = 5.0;
Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: at (5s) {radius => 75.0 tween Interpolator.LINEAR }
}.play();
ShapeSubtract {
a: Rectangle { width: 200 height: 200 fill: Color.BLACK }
b: bind Circle {
radius: radius
centerX: 100
centerY: 100
}
}
Отрисовка освещаемой области
Зададим класс LightElem, который будет содержать атрибуты освещаемой области. При взрыве снаряда будем создавать LightElem, задавать его координаты и анимировать радиус освещаемой области.
public class LightElem {Вся графики определяется в методе create() класса Field.
public var radius: Number;
public var centerX: Number;
public var centerY: Number;
}
Для отрисовки освещаемой области теперь нужно пройтись по последовательности элементов LightElem и создать окружности, которые будут вычитаться из затемненной области.
public class Field extends CustomNode {
public var lights: LightElem[];
override function create() {
Group {
content: [
// Other components
ShapeSubtract {
a: Rectangle { width: 550 height: 550 fill: Color.BLACK }
b: bind for (elem in lights) Circle {
centerX: elem.centerX
centerY: elem.centerY
radius: elem.radius
}
}
]
}
}
}