
After reading about the
Tower Defense competition, I immediately had the idea to create a world of eternal darkness.
In order to at least see something, you need to build a light tower to illuminate the creatures crawling past.
Under the cat described the implementation of this idea in JavaFX.
')
Towers and shells
On
the competition
website you can download the initial engine and follow the instructions to describe your towers and shells.
To begin with, we will create a light tower, in which we will redefine the rate of fire, the radius of destruction, and in the fire () method, we will specify the type of projectile being fired.
public class LightTower extends Tower {
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 }
}
}
Then we define a light projectile, in the explode () method of which we need to indicate what happens to the projectile in an explosion.
public class LightBall extends Bullet {
override var damageRadius : Number = 120 ;
override function explode ( ) {
// explosion algorithm
}
}
ShapeSubtract Component
JavaFX provides the ShapeSubtract component, which allows you to draw geometric shapes with clipped regions.
All game space will be covered with a black square. We will use a circle as the area illuminated by the light projectile.
 | ShapeSubtract { a : Rectangle { width : 200 height : 200 fill : Color . BLACK } b : Circle { radius : 75 centerX : 100 centerY : 100 } }
|
To animate the illuminated area, we use the Timeline class, which will change the variable radius from its initial value to the final one. We also
bind the radius attribute of the circle with the variable radius using the
bind operator.
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
}
}
True, in this case we will not get the expected effect. Those. the radius of the circle will change when the variable changes, the radius, but the subtraction of areas will occur only once at the very beginning.

You can achieve the desired result by placing the
bind operator before the subtracted circle. In this case, we associate the subtracted shape with the expression on the right, and if any variable included in the expression changes, the
ShapeSubtract component will also change.
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
}
}

Rendering the illuminated area
Let's set the class LightElem, which will contain the attributes of the illuminated area. When the projectile explodes, we will create a LightElem, set its coordinates and animate the radius of the illuminated area.
public class LightElem {
public var radius : Number ;
public var centerX : Number ;
public var centerY : Number ;
}
All graphics are defined in the Field class create () method.
To draw the illuminated area, now you need to go through the sequence of LightElem elements and create circles that will be subtracted from the darkened area.
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
}
}
]
}
}
}