1+ /*
2+ * Copyright (c) 2025 by Gerrit Grunwald
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package eu .hansolo .spacefx ;
18+
19+ import javafx .animation .AnimationTimer ;
20+ import javafx .beans .DefaultProperty ;
21+ import javafx .geometry .Insets ;
22+ import javafx .scene .canvas .Canvas ;
23+ import javafx .scene .canvas .GraphicsContext ;
24+ import javafx .scene .layout .Background ;
25+ import javafx .scene .layout .BackgroundFill ;
26+ import javafx .scene .layout .CornerRadii ;
27+ import javafx .scene .layout .Pane ;
28+ import javafx .scene .layout .Region ;
29+ import javafx .scene .paint .Color ;
30+
31+ import java .util .Arrays ;
32+ import java .util .Random ;
33+
34+
35+ @ DefaultProperty ("children" )
36+ public class StarField extends Region {
37+ private static final double WIDTH = 1920 ;
38+ private static final double HEIGHT = 1080 ;
39+ private static final Random RND = new Random ();
40+ public static final int NO_OF_STARS = 200 ;
41+ public static final long FPS_60 = 0 _016_666_666l ;
42+ private Canvas canvas ;
43+ private GraphicsContext ctx ;
44+ private Pane pane ;
45+ private Star [] stars = new Star [NO_OF_STARS ];
46+ private long deltaTime = FPS_60 ;
47+ private long lastTimerCall ;
48+ private AnimationTimer timer ;
49+
50+
51+ // ******************** Constructors **************************************
52+ public StarField () {
53+ for (int i = 0 ; i < NO_OF_STARS ; i ++) {
54+ Star star = new Star ();
55+ star .x = RND .nextDouble () * WIDTH ;
56+ stars [i ] = star ;
57+ }
58+
59+ timer = new AnimationTimer () {
60+ @ Override public void handle (final long now ) {
61+ if (now > lastTimerCall ) {
62+ lastTimerCall = now + deltaTime ;
63+ redraw ();
64+ }
65+ }
66+ };
67+
68+ initGraphics ();
69+ registerListeners ();
70+ }
71+
72+
73+ // ******************** Initialization ************************************
74+ private void initGraphics () {
75+ canvas = new Canvas (WIDTH , HEIGHT );
76+ ctx = canvas .getGraphicsContext2D ();
77+ pane = new Pane (canvas );
78+ pane .setPrefSize (WIDTH , HEIGHT );
79+ pane .setBackground (new Background (new BackgroundFill (Color .BLACK , CornerRadii .EMPTY , Insets .EMPTY )));
80+
81+ getChildren ().setAll (pane );
82+
83+ setPrefSize (WIDTH , HEIGHT );
84+ }
85+
86+ private void registerListeners () {
87+ //widthProperty().addListener(o -> resize());
88+ //heightProperty().addListener(o -> resize());
89+ }
90+
91+
92+ // ******************** Methods *******************************************
93+ public void start () { this .timer .start (); }
94+ public void stop () { this .timer .stop (); }
95+
96+ private void redraw () {
97+ ctx .clearRect (0 , 0 , WIDTH , HEIGHT );
98+ ctx .setFill (Color .rgb (255 , 255 , 255 , 0.9 ));
99+ Arrays .stream (stars ).forEach (star -> {
100+ star .update ();
101+ ctx .fillOval (star .x , star .y , star .size , star .size );
102+ });
103+ }
104+
105+
106+ // ******************** Inner Classes ************************************
107+ private class Star {
108+ private final Random rnd = new Random ();
109+ private final double yVariation = 0 ;
110+ private final double minSpeedX = 4 ;
111+ private double x ;
112+ private double y ;
113+ private double size ;
114+ private double vX ;
115+ private double vY ;
116+ private double vXVariation ;
117+
118+
119+ public Star () {
120+ // Random size
121+ size = rnd .nextInt (2 ) + 1 ;
122+
123+ // Position
124+ x = -size ;
125+ y = (int )(rnd .nextDouble () * HEIGHT );
126+
127+ // Random Speed
128+ vXVariation = (rnd .nextDouble () * 0.5 ) + 0.2 ;
129+
130+ // Velocity
131+ vX = (int ) (Math .round (((rnd .nextDouble () * 1.5 ) + minSpeedX ) * vXVariation ));
132+ vY = (int ) (Math .round ((rnd .nextDouble () * yVariation ) - yVariation * 0.5 ));
133+ }
134+
135+
136+ private void respawn () {
137+ x = -size ;
138+ y = (int ) (RND .nextDouble () * HEIGHT );
139+ }
140+
141+ private void update () {
142+ x += vX ;
143+ y += vY ;
144+
145+ // Respawn star
146+ if (x > WIDTH + size ) {
147+ respawn ();
148+ }
149+ }
150+ }
151+ }
0 commit comments