
com.almasb.fxgl.entity.components.ViewComponent.kt Maven / Gradle / Ivy
/*
* FXGL - JavaFX Game Library. The MIT License (MIT).
* Copyright (c) AlmasB ([email protected]).
* See LICENSE for details.
*/
package com.almasb.fxgl.entity.components
import com.almasb.fxgl.core.View
import com.almasb.fxgl.entity.component.Component
import com.almasb.fxgl.entity.component.CoreComponent
import javafx.beans.property.ReadOnlyIntegerProperty
import javafx.beans.property.ReadOnlyIntegerWrapper
import javafx.beans.property.SimpleDoubleProperty
import javafx.event.Event
import javafx.event.EventHandler
import javafx.event.EventType
import javafx.scene.Group
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.transform.Rotate
import javafx.scene.transform.Scale
/**
* Represents visual aspect of an entity.
*
* @author Almas Baimagambetov ([email protected])
*/
@CoreComponent
class ViewComponent : Component() {
private val viewRoot = Group()
// no scale or rotate is applied
private val viewRootNoTransform = Group()
internal val devRoot = Group()
private val updateableViews = arrayListOf()
/**
* This node is managed by FXGL and is part of active scene graph, do NOT modify children.
*/
val parent: Parent = Group(viewRoot, viewRootNoTransform, devRoot)
val z: ReadOnlyIntegerProperty = ReadOnlyIntegerWrapper(0)
@get:JvmName("opacityProperty")
val opacityProp = SimpleDoubleProperty(1.0)
var opacity: Double
get() = opacityProp.value
set(value) { opacityProp.value = value }
/**
* If made invisible, all events (e.g. mouse) go through the entity
* and do not register on the entity.
* In contrast, changing opacity to 0 still allows the entity to receive
* events (e.g. mouse clicks).
*/
var isVisible: Boolean
get() = parent.isVisible
set(value) { parent.isVisible = value }
/**
* @return all view children (the order is transform applied first, then without transforms)
*/
val children: List
get() = viewRoot.children + viewRootNoTransform.children
init {
viewRoot.opacityProperty().bind(opacityProp)
viewRootNoTransform.opacityProperty().bind(viewRoot.opacityProperty())
}
override fun onAdded() {
viewRoot.translateXProperty().bind(entity.xProperty().subtract(entity.transformComponent.positionOriginXProperty()))
viewRoot.translateYProperty().bind(entity.yProperty().subtract(entity.transformComponent.positionOriginYProperty()))
viewRootNoTransform.translateXProperty().bind(viewRoot.translateXProperty())
viewRootNoTransform.translateYProperty().bind(viewRoot.translateYProperty())
devRoot.translateXProperty().bind(viewRoot.translateXProperty())
devRoot.translateYProperty().bind(viewRoot.translateYProperty())
val scale = Scale()
scale.xProperty().bind(entity.transformComponent.scaleXProperty())
scale.yProperty().bind(entity.transformComponent.scaleYProperty())
scale.pivotXProperty().bind(entity.transformComponent.scaleOriginXProperty())
scale.pivotYProperty().bind(entity.transformComponent.scaleOriginYProperty())
val rotate = Rotate()
rotate.axis = Rotate.Z_AXIS
rotate.angleProperty().bind(entity.transformComponent.angleProperty())
rotate.pivotXProperty().bind(entity.transformComponent.rotationOriginXProperty())
rotate.pivotYProperty().bind(entity.transformComponent.rotationOriginYProperty())
viewRoot.transforms.addAll(rotate, scale)
devRoot.transforms.addAll(rotate, scale)
(z as ReadOnlyIntegerWrapper).bind(entity.transformComponent.zProperty())
}
override fun onUpdate(tpf: Double) {
updateableViews.forEach { it.onUpdate(tpf) }
}
override fun onRemoved() {
(parent as Group).children.clear()
clearChildren()
}
/**
* Register event handler for event type that occurs on this view.
*/
fun addEventHandler(eventType: EventType, eventHandler: EventHandler) {
parent.addEventHandler(eventType, eventHandler)
}
/**
* Remove event handler for event type that occurs on this view.
*/
fun removeEventHandler(eventType: EventType, eventHandler: EventHandler) {
parent.removeEventHandler(eventType, eventHandler)
}
/**
* Add a child node to this view.
*/
@JvmOverloads fun addChild(node: Node, isTransformApplied: Boolean = true) {
if (isTransformApplied) {
viewRoot.children += node
} else {
viewRootNoTransform.children += node
}
if (node is View)
updateableViews += node
}
/**
* Remove a child from this view.
*/
fun removeChild(node: Node) {
viewRoot.children -= node
viewRootNoTransform.children -= node
if (node is View)
updateableViews -= node
}
/**
* Remove all (with and without transforms) children.
*/
fun clearChildren() {
viewRoot.children.forEach {
if (it is View) {
updateableViews -= it
it.dispose()
}
}
viewRootNoTransform.children.forEach {
if (it is View) {
updateableViews -= it
it.dispose()
}
}
viewRoot.children.clear()
viewRootNoTransform.children.clear()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy