@@ -2,7 +2,6 @@ package sc.gui.view
22
33import javafx.animation.KeyFrame
44import javafx.animation.Timeline
5- import javafx.geometry.HPos
65import javafx.geometry.Orientation
76import javafx.geometry.Point2D
87import javafx.geometry.Pos
@@ -17,25 +16,21 @@ import javafx.scene.layout.*
1716import javafx.util.Duration
1817import sc.api.plugins.Team
1918import sc.gui.AppStyle
19+ import sc.gui.util.listenImmediately
2020import sc.plugin2025.*
2121import sc.plugin2025.Field
2222import sc.plugin2025.util.HuIConstants
2323import tornadofx.*
24-
25- private const val BOARDSIZE = 9
24+ import kotlin.math.*
2625
2726class HuIBoard : GameBoard <GameState >() {
28- val grid = GridPane ().apply {
29- hgap = AppStyle .formSpacing
30- vgap = AppStyle .formSpacing
31-
32- }
27+ val grid = AnchorPane ()
3328 val cards = Array (2 ) { VBox () }
3429
3530 private val graphicSize = squareSize.doubleBinding {
3631 minOf(
37- root.width.div(BOARDSIZE + 4 /* cards on the sides */ ),
38- viewHeight / BOARDSIZE
32+ root.width.div(12 + 4 /* cards on the sides */ ),
33+ viewHeight / 12
3934 )
4035 }
4136
@@ -59,6 +54,7 @@ class HuIBoard: GameBoard<GameState>() {
5954 private val players = Team .values().map {
6055 createImage(" player_" + it.color, 0.8 ).apply {
6156 effect = playerEffects[it.index]
57+ isMouseTransparent = true
6258 }
6359 }
6460 private val toClear = ArrayList <Node >()
@@ -76,11 +72,13 @@ class HuIBoard: GameBoard<GameState>() {
7672 false
7773 )
7874 if (index != 0 )
79- putOnPosition(
80- Label (index.toString()).apply { isMouseTransparent = true },
81- index,
82- false
83- )
75+ runLater { // So the labels are in front of the fields
76+ putOnPosition(
77+ Label (index.toString()).apply { isMouseTransparent = true },
78+ index,
79+ false
80+ )
81+ }
8482 }
8583 } else {
8684 toClear.forEach {
@@ -157,7 +155,7 @@ class HuIBoard: GameBoard<GameState>() {
157155 this .children.addAll(
158156 label.move(
159157 Duration .seconds(animFactor),
160- Point2D (0.0 , graphicSize.value * - . 6 ),
158+ Point2D (0.0 , graphicSize.value * - 1.0 ),
161159 play = false ,
162160 ),
163161 label.fade(
@@ -195,16 +193,50 @@ class HuIBoard: GameBoard<GameState>() {
195193
196194 cards[activeTeam.index].apply {
197195 clear()
198- children.addAll(state.getHare(activeTeam).getCards().map { createImage(it.graphicName(), 1.6 ) })
196+ children.addAll(state.getHare(activeTeam).getCards().map { createImage(it.graphicName(), 1.5 ) })
199197 }
200198 }
201199
200+ private var spiralFactor = 0.0
201+ /* * Translated from https://stackoverflow.com/questions/78472829/equidistant-points-along-an-archimedean-spiral-with-fixed-gap-between-points-and*/
202+ private fun spiral (radius : Double , numCycles : Double , nPoints : Int ): DoubleArray {
203+ val dr = radius / numCycles
204+ val thetaMax = 2 * PI * numCycles
205+ val a = radius / thetaMax
206+ spiralFactor = radius / (2 * PI * numCycles.toInt())
207+ val sMax = (a / 2 ) * (thetaMax * sqrt(1 + thetaMax.pow(2 )) + ln(thetaMax + sqrt(1 + thetaMax.pow(2 ))))
208+ val s = DoubleArray (nPoints) { dr / 2 + it * (sMax - dr / 2 ) / nPoints }
209+
210+ val theta = DoubleArray (nPoints)
211+ for (i in s.indices) {
212+ var t = 0.0
213+ var told = t + 1
214+ while (abs(t - told) > 1 .0e- 10 ) {
215+ told = t
216+ t = sqrt((- 1 + sqrt(1 + 4 * (2 * s[i] / a - ln(t + sqrt(1 + t.pow(2 )))).pow(2 ))) / 2 )
217+ }
218+ theta[i] = t
219+ }
220+ return theta
221+ }
222+
223+ val spiralRadius = 5.0
224+ val archimedeanSpiral = spiral(spiralRadius, 3.65 , HuIConstants .NUM_FIELDS ).reversed()
225+
202226 private fun <T : Node > putOnPosition (node : T , position : Int , clear : Boolean = true): T {
203227 if (clear) {
204228 grid.children.remove(node)
205229 toClear.add(node)
206230 }
207- grid.add(node, position % BOARDSIZE , position / BOARDSIZE )
231+ grid.add(node)
232+ val pos = archimedeanSpiral[position]
233+ graphicSize.listenImmediately { value ->
234+ val adjustedValue = value.toDouble()
235+ node.anchorpaneConstraints {
236+ leftAnchor = adjustedValue * (spiralFactor * pos * cos(pos) + spiralRadius)
237+ bottomAnchor = adjustedValue * (spiralFactor * pos * sin(pos) + spiralRadius)
238+ }
239+ }
208240 return node
209241 }
210242
@@ -218,6 +250,7 @@ class HuIBoard: GameBoard<GameState>() {
218250 fields[pos].onClickMove(EatSalad )
219251 putOnPosition(
220252 Button (" Salat fressen" ).apply {
253+ translateYProperty().bind(graphicSize.divide(- 2 ))
221254 addClass(" small" )
222255 onLeftClick { sendHumanMove(EatSalad ) }
223256 },
@@ -229,9 +262,8 @@ class HuIBoard: GameBoard<GameState>() {
229262 state.possibleExchangeCarrotMoves().forEach { car ->
230263 putOnPosition(
231264 Button (carrotCostString(car.amount)).apply {
232- translateYProperty().bind(graphicSize.doubleBinding {
233- - car.amount * (it?.toDouble()?.div(20 ) ? : 3.0 )
234- })
265+ translateX = AppStyle .spacing
266+ translateYProperty().bind(graphicSize.multiply(- car.amount / 20.0 - .2 ))
235267 onLeftClick { sendHumanMove(car) }
236268 },
237269 state.currentPlayer.position
@@ -256,14 +288,19 @@ class HuIBoard: GameBoard<GameState>() {
256288 if (currentPos + maxAdvance < targetPos || state.checkAdvance(distance) != null )
257289 return @forEachIndexed
258290 val flow = FlowPane (Orientation .HORIZONTAL ).apply {
259- this .prefWidthProperty().bind(graphicSize)
260- this .maxWidthProperty().bind(graphicSize)
261- this .hgap = AppStyle .miniSpacing
262- this .vgap = AppStyle .miniSpacing
291+ maxWidthProperty().bind(graphicSize)
292+ hgap = AppStyle .miniSpacing
293+ vgap = AppStyle .miniSpacing
263294 }
264295 var totalCards = 0
265296 state.possibleCardMoves(distance)?.also {
266- putOnPosition(Group (Group (flow).apply { this .isManaged = false }), targetPos)
297+ putOnPosition(
298+ Group (Group (flow).apply { isManaged = false }).apply {
299+ translateX = AppStyle .spacing
300+ translateY = - AppStyle .formSpacing
301+ },
302+ targetPos
303+ )
267304 totalCards = it.sumOf { it.getCards().size }
268305 }?.forEach { advance ->
269306 val cards = advance.getCards()
@@ -307,9 +344,7 @@ class HuIBoard: GameBoard<GameState>() {
307344
308345 private fun carrotCost (value : Int , position : Int ) =
309346 putOnPosition(Label (carrotCostString(value)).apply {
310- gridpaneConstraints {
311- this .hAlignment = HPos .CENTER
312- }
347+ translateY = - .8 * graphicSize.value
313348 isMouseTransparent = true
314349 }, position)
315350
0 commit comments