Skip to content

Commit

Permalink
[bgw-gui] Added HexOrientation to HexagonGrid and HexagonView (#407)
Browse files Browse the repository at this point in the history
* Added option for flat hexagon grid and hexagon views

* Updated documentation to fix missing and wrong Hexagon information

* Added missing changelog entries for older pre-release versions

* Fixed hexagon grid to use q and r in docs
  • Loading branch information
smilefx committed Jan 31, 2024
1 parent 06a99c3 commit 266db43
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 22 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,28 @@
# Changelog
All notable changes to this project will be documented in this file.

## 0.9.5-Pre - 30.01.2024

### Added
- Added `HexOrientation` to `HexagonGrid` and `HexagonView` to support different orientations of hexagons.

## 0.9.4-Pre - 15.01.2024

### Fixed
- Fixed `TextInputUIComponent` not showing prompt text when text is empty.

## 0.9.2-Pre - 15.12.2023

### Added
- Added missing `Cursor` CSS styles.

### Changed
- Refactored `Visual` styling properties observer.
- Propagate compound visual styles to children.

### Fixed
- Fixed CSS style properties not being set correctly.

## [0.9] - 27.11.2023

### Added
Expand Down
19 changes: 15 additions & 4 deletions bgw-docs/src/main/jekyll/components/container/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,25 @@ Here is an example on how to change the default coordinate system to axial.
```kotlin
val hexagonGrid: HexagonGrid<HexagonView> = HexagonGrid(coordinateSystem = CoordinateSystem.AXIAL)

for (row in -2..2) {
for (col in -2..2) {
val hexagon = HexagonView(visual = ColorVisual.BLUE)
hexagonGrid[col, row] = hexagon
for (q in -2..2) {
for (r in -2..2) {
if (q + r >= -2 && q + r <= 2) {
val hexagon = HexagonView(visual = ColorVisual.BLUE)
hexagonGrid[q, r] = hexagon
}
}
}
```

### Hexagon Grid Orientations
The HexagonGrid class supports two orientations: pointy top and flat top.

### Pointy Top Orientation
**This is the default orientation for a HexGrid.** In the pointy top orientation (`HexOrientation.POINTY_TOP`), the hexagons are positioned with their tips pointing up and down.

### Flat Top Orientation
In the flat top orientation (`HexOrientation.FLAT_TOP`), the hexagons are positioned with their tips pointing left and right.

## Container overview

[View it on GitHub](https://github.com/tudo-aqua/bgw/tree/main/bgw-examples/bgw-docs-examples/src/main/kotlin/examples/components/container/ContainerExample.kt){:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@ For a dice roll there exists a dedicated [DiceAnimation][DiceAnimationDoc].
The [HexagonView][HexagonDoc] component can also be utilized for hexagonal tokens,
providing a versatile solution for displaying various hexagonal-shaped elements.

A Hexagon by default has its tips pointing up and down (`HexOrientation.POINTY_TOP`). It can however also have its tips pointing left and right (`HexOrientation.FLAT_TOP`).

Hexagons only have one visual.
39 changes: 28 additions & 11 deletions bgw-gui/src/main/kotlin/tools/aqua/bgw/builder/HexagonBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import kotlin.math.sqrt
import tools.aqua.bgw.builder.FXConverters.toFXColor
import tools.aqua.bgw.builder.FXConverters.toFXImage
import tools.aqua.bgw.components.gamecomponentviews.HexagonView
import tools.aqua.bgw.core.HexOrientation
import tools.aqua.bgw.style.color
import tools.aqua.bgw.style.pixel
import tools.aqua.bgw.visual.*
Expand All @@ -53,7 +54,7 @@ object HexagonBuilder {
/** Builds [HexagonView]. */
internal fun buildHexagonView(hexagonView: HexagonView): Region {
val root = Pane().apply { isPickOnBounds = false }
val points = generatePoints(hexagonView.size.toDouble())
val points = generatePoints(hexagonView.size.toDouble(), orientation = hexagonView.orientation)
hexagonView.visualProperty.setGUIListenerAndInvoke(hexagonView.visual) { _, nV ->
root.children.clear()
val component =
Expand Down Expand Up @@ -107,14 +108,27 @@ object HexagonBuilder {
nV.pixel.toDouble()
} else 0.0
}
visual.borderRadiusProperty.addListenerAndInvoke(visual.borderRadius) { _, nV ->
clip =
if (nV != null && nV.pixel > 0) {
val size = hexagonView.size.toDouble() - nV.pixel.toDouble()
val offsetX = hexagonView.widthProperty.value / 2 - sqrt(3.0) / 2 * size
val offsetY = hexagonView.heightProperty.value / 2 - size
Polygon(*generatePoints(size, offsetX, offsetY)).apply { roundCorners() }
} else null

if (hexagonView.orientation == HexOrientation.POINTY_TOP) {
visual.borderRadiusProperty.addListenerAndInvoke(visual.borderRadius) { _, nV ->
clip =
if (nV != null && nV.pixel > 0) {
val size = hexagonView.size.toDouble() - nV.pixel.toDouble()
val offsetX = hexagonView.widthProperty.value / 2 - sqrt(3.0) / 2 * size
val offsetY = hexagonView.heightProperty.value / 2 - size
Polygon(*generatePoints(size, offsetX, offsetY)).apply { roundCorners() }
} else null
}
} else {
visual.borderRadiusProperty.addListenerAndInvoke(visual.borderRadius) { _, nV ->
clip =
if (nV != null && nV.pixel > 0) {
val size = hexagonView.size.toDouble() - nV.pixel.toDouble()
val offsetX = hexagonView.widthProperty.value / 2 - size
val offsetY = hexagonView.heightProperty.value / 2 - sqrt(3.0) / 2 * size
Polygon(*generatePoints(size, offsetX, offsetY)).apply { roundCorners() }
} else null
}
}
})
.apply { isPickOnBounds = false }
Expand All @@ -141,10 +155,13 @@ object HexagonBuilder {
private fun generatePoints(
size: Double,
offsetX: Number = 0.0,
offsetY: Number = 0.0
offsetY: Number = 0.0,
orientation: HexOrientation = HexOrientation.POINTY_TOP
): DoubleArray {
val points = mutableListOf<Double>()
var angle = 90.0

var angle = if (orientation == HexOrientation.POINTY_TOP) 30.0 else 0.0

repeat(HEXAGON_SIDES) {
val x = size * cos(Math.toRadians(angle)) + size
val y = size * sin(Math.toRadians(angle)) + size
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package tools.aqua.bgw.components.container

import kotlin.math.sqrt
import tools.aqua.bgw.components.gamecomponentviews.HexagonView
import tools.aqua.bgw.core.HexOrientation
import tools.aqua.bgw.visual.Visual

private typealias OffsetCoordinate = Pair<Int, Int>
Expand All @@ -35,14 +36,17 @@ private typealias AxialCoordinate = Pair<Int, Int>
* @param visual The visual representation of the hexagon grid. Default is an empty visual.
* @param coordinateSystem The coordinate system to use for the grid. Default is
* `CoordinateSystem.OFFSET`.
* @param orientation The orientation of the hexagons in the grid. Default is
* `HexOrientation.POINTY_TOP`.
*/
class HexagonGrid<T : HexagonView>(
posX: Number = 0,
posY: Number = 0,
width: Number = 0,
height: Number = 0,
visual: Visual = Visual.EMPTY,
coordinateSystem: CoordinateSystem = CoordinateSystem.OFFSET
coordinateSystem: CoordinateSystem = CoordinateSystem.OFFSET,
var orientation: HexOrientation = HexOrientation.POINTY_TOP
) :
GameComponentContainer<T>(
posX = posX, posY = posY, width = width, height = height, visual = visual) {
Expand Down Expand Up @@ -74,6 +78,7 @@ class HexagonGrid<T : HexagonView>(
*/
operator fun set(columnIndex: Int, rowIndex: Int, component: T) {
map[columnIndex to rowIndex]?.run { observableComponents.remove(this) }
component.orientation = orientation
map[columnIndex to rowIndex] = component
observableComponents.add(component)
}
Expand All @@ -87,13 +92,26 @@ class HexagonGrid<T : HexagonView>(
map.forEach { (x, y), hexagon ->
val (q, r) =
when (coordinateSystem) {
CoordinateSystem.OFFSET -> x to y
CoordinateSystem.AXIAL -> x + (y - (y and 1)) / 2 to y
CoordinateSystem.OFFSET -> {
if (orientation == HexOrientation.POINTY_TOP) x to y else y to x
}
CoordinateSystem.AXIAL -> {
if (orientation == HexOrientation.POINTY_TOP) x + (y - (y and 1)) / 2 to y
else y + (x - (x and 1)) / 2 to x
}
}
with(hexagon) {
val actualWidth = width / 2 * sqrt(3.0)
posXProperty.setSilent(actualWidth * q + if (r % 2 == 0) 0.0 else actualWidth / 2)
posYProperty.setSilent(height * r - r * height / 4)
if (orientation == HexOrientation.POINTY_TOP) {
hexagon.orientation = HexOrientation.POINTY_TOP
val actualWidth = width / 2 * sqrt(3.0)
posXProperty.setSilent(actualWidth * q + if (r % 2 == 0) 0.0 else actualWidth / 2)
posYProperty.setSilent(height * r - r * height / 4)
} else {
hexagon.orientation = HexOrientation.FLAT_TOP
val actualHeight = height / 2 * sqrt(3.0)
posYProperty.setSilent(actualHeight * q + if (r % 2 == 0) 0.0 else actualHeight / 2)
posXProperty.setSilent(width * r - r * width / 4)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package tools.aqua.bgw.components.gamecomponentviews

import tools.aqua.bgw.core.DEFAULT_HEXAGON_SIZE
import tools.aqua.bgw.core.HexOrientation
import tools.aqua.bgw.visual.Visual

/**
Expand All @@ -30,12 +31,14 @@ import tools.aqua.bgw.visual.Visual
* @param size Represents the radius of the outer circle of the [HexagonView] all six points lie on.
* Default: [DEFAULT_HEXAGON_SIZE].
* @param visual Visual for this [HexagonView].
* @param orientation Orientation of the [HexagonView]. Default: [HexOrientation.POINTY_TOP].
*/
open class HexagonView(
posX: Number = 0,
posY: Number = 0,
val size: Number = DEFAULT_HEXAGON_SIZE,
visual: Visual
visual: Visual,
var orientation: HexOrientation = HexOrientation.POINTY_TOP
) :
GameComponentView(
posX = posX,
Expand Down
24 changes: 24 additions & 0 deletions bgw-gui/src/main/kotlin/tools/aqua/bgw/core/HexOrientation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2024 The BoardGameWork Authors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package tools.aqua.bgw.core

/** Enumeration class representing the orientation options for hexagonal grids and views. */
enum class HexOrientation {
POINTY_TOP,
FLAT_TOP
}

0 comments on commit 266db43

Please sign in to comment.