meta-next
Version:
281 lines (235 loc) • 5.83 kB
JavaScript
import Engine from "../Engine"
import Vector2 from "../math/Vector2"
import Vector3 from "../math/Vector3"
import Matrix4 from "../math/Matrix4"
import AABB from "../math/AABB"
class Node
{
constructor()
{
this._position = new Vector2(0, 0)
this._worldPosition = null
this._scale = new Vector2(1, 1)
this._pivot = new Vector2(0, 0)
this._anchor = null
this._size = new Vector2(0, 0)
this.color = new Vector3(1, 1, 1)
this._volume = new AABB()
this._transform = new Matrix4()
this._angle = 0.0
this.parent = null
this.children = null
this.needUpdateTransform = true
this.needUpdateVolume = true
this.needUpdateOffset = true
}
updateTransform()
{
if(this.parent)
{
const parentSize = this.parent._size
const parentPivot = this.parent._pivot
this._transform.copy(this.parent.transform)
if(this._anchor) {
this._transform.translate(
this._position.x - (parentSize.x * parentPivot.x) + (parentSize.x * this._anchor.x),
this._position.y - (parentSize.y * parentPivot.y) + (parentSize.y * this._anchor.y),
0.0)
}
else {
this._transform.translate(
this._position.x - (parentSize.x * parentPivot.x),
this._position.y - (parentSize.y * parentPivot.y),
0.0)
}
}
else
{
this._transform.identity()
if(this._anchor) {
const engineWindow = Engine.window
this._transform.translate(
this._position.x + (engineWindow.width * this._anchor.x),
this._position.y + (engineWindow.height * this._anchor.y),
0.0)
}
else {
this._transform.translate(this._position.x, this._position.y, 0.0)
}
}
if(this._angle !== 0.0) {
this._transform.rotate(this._angle, 0, 0, 1.0)
}
if(this._scale.x !== 1.0 || this._scale.y !== 1.0) {
this._transform.scale(this._scale.x, this._scale.y, 1.0)
}
if(this.children) {
for(let n = 0; n < this.children.length; n++) {
this.children[n].needUpdateTransform = true
}
}
this.needUpdateTransform = false
this.needUpdateVolume = true
}
updateVolume()
{
if(this.parent)
{
const worldPosition = this.worldPosition
this._volume.set(
worldPosition.x - (this._pivot.x * this._size.x),
worldPosition.y - (this._pivot.y * this._size.y),
this._size.x * this._scale.x | 0,
this._size.y * this._scale.y | 0)
}
else
{
this._volume.set(
this._position.x - (this._pivot.x * this._size.x),
this._position.y - (this._pivot.y * this._size.y),
this._size.x * this._scale.x | 0,
this._size.y * this._scale.y | 0)
}
this.needUpdateVolume = false
}
get worldPosition()
{
if(this.parent) {
const worldPosition = this.parent.worldPosition
if(!this._worldPosition) {
this._worldPosition = new Vector2(worldPosition.x + this._position.x, worldPosition.y + this._position.y)
}
else {
this._worldPosition.set(worldPosition.x + this._position.x, worldPosition.y + this._position.y)
}
return this._worldPosition
}
return this._position
}
clampX(increment, min, max)
{
const volume = this.volume
if((volume.minX + increment) < min) {
this.x = this._size.x * this._pivot.x
return true
}
else if((volume.maxX + increment) > max) {
this.x = max - this._size.x * this._pivot.x
return true
}
this.x += increment
return false
}
clampY(increment, min, max)
{
const volume = this.volume
if((volume.minY + increment) < min) {
this.y = this._size.y * this._pivot.y
return true
}
else if((volume.maxY + increment) > max) {
this.y = max - this._size.y * this._pivot.y
return true
}
this.y += increment
return false
}
addChild(node)
{
if(!this.children) {
this.children = [ node ]
}
else {
this.children.push(node)
}
node.parent = this
node.needUpdateTransform = true
}
removeChild(node)
{
if(!this.children) { return }
if(node.parent !== this) {
console.warn(`(Node.removeChild) Node has different parent: ${node.parent}`)
return
}
const index = this.children.indexOf(node)
if(index === -1) { return }
this.children[index] = this.children[this.children.length - 1]
this.children.pop()
node.parent = null
node.needUpdateTransform = true
}
detach()
{
if(!this.parent) { return }
this.parent.removeChild(this)
}
get position() {
this.needUpdateTransform = true
return this._position
}
set angle(angle) {
if(this._angle === angle) { return }
this._angle = angle
this.needUpdateTransform = true
}
get angle() {
return this._angle
}
get scale() {
this.needUpdateTransform = true
return this._scale
}
get pivot() {
this.needUpdateTransform = true
this.needUpdateOffset = true
return this._pivot
}
get anchor()
{
if(!this._anchor) {
this._anchor = new Vector2(0, 0)
}
this.needUpdateTransform = true
return this._anchor
}
get size() {
this.needUpdateTransform = true
this.needUpdateOffset = true
return this._size
}
get volume() {
if(this.needUpdateVolume) {
this.updateVolume()
}
return this._volume
}
get transform()
{
if(this.needUpdateTransform) {
this.updateTransform()
}
return this._transform;
}
set x(value) {
this._position.x = value
this.needUpdateTransform = true
}
get x() {
return this._position.x
}
set y(value) {
this._position.y = value
this.needUpdateTransform = true
}
get y() {
return this._position.y
}
get width() {
return this._size.x
}
get height() {
return this._size.y
}
}
export default Node