Skip to content
This repository has been archived by the owner on Jul 27, 2021. It is now read-only.

Get/Set Scene transform values #621

Open
belohlavek opened this issue Oct 30, 2019 · 3 comments
Open

Get/Set Scene transform values #621

belohlavek opened this issue Oct 30, 2019 · 3 comments
Assignees
Labels

Comments

@belohlavek
Copy link
Contributor

Currently all position/rotation/scale data for an entity's Transform is relative to that entity's parent. This will lead to several problems and hardships.
For example, making a subentity follow another entity or even the player (Camera.instance.position) would result in an operation between global and local transforms.
As of today users need to solve this by themselves using their own implementations. It would be great to ship this as part of the Transform API.

The need for this API was made clear after the SDK game jam and is currently required to avoid repeating code inside the Builder's smart items.

Proposed API:

All the methods would live inside the Transform component

public getScenePosition(): Readonly<Vector3>
public setScenePosition(vec: Vector3): void
public getSceneRotation(): Readonly<Quaternion>
public setSceneRotation(quat: Quaternion): void
public getSceneScale(): Readonly<Vector3>
public setSceneScale(vec: Vector3): void
public getSceneUp(): Readonly<Vector3>
public getSceneDown(): Readonly<Vector3>
public getSceneForward(): Readonly<Vector3>
public getSceneBackward(): Readonly<Vector3>
public getSceneLeft(): Readonly<Vector3>
public getSceneRight(): Readonly<Vector3>

Proposed implementation:

Keep in mind they are meant to be used as an extension of the Entity class and the code submitted in a PR would be slightly different (adding new methods to the Transform component)

Entity.prototype.getGlobalPosition = function (this: Entity) {
    let entityPosition = this.hasComponent(Transform) ? this.getComponent(Transform).position.clone() : Vector3.Zero()
    let parentEntity = this.getParent() as Entity

    if (parentEntity != null) {
        let parentRotation = parentEntity.hasComponent(Transform) ? parentEntity.getComponent(Transform).rotation : Quaternion.Identity
        return parentEntity.getGlobalPosition().add(entityPosition.rotate(parentRotation))
    }

    return entityPosition
}

Entity.prototype.setGlobalPosition = function (this: Entity, position: Vector3) {
    let transform = this.getComponent(Transform)

    if (transform != null) {
        let parentEntity = this.getParent() as Entity
        if (parentEntity != null) {
            let parentOffset = position.subtract(parentEntity.getGlobalPosition())
            transform.position = DivVectors(parentOffset.rotate(Quaternion.Inverse(parentEntity.getGlobalRotation())), parentEntity.getGlobalScale())
        }
        else {
            transform.position = position
        }
    }
}

Entity.prototype.getGlobalRotation = function (this: Entity) {
    let entityRotation = this.hasComponent(Transform) ? this.getComponent(Transform).rotation.clone() : Quaternion.Identity
    let parentEntity = this.getParent() as Entity

    if (parentEntity != null) {
        return parentEntity.getGlobalRotation().multiply(entityRotation)
    }

    return entityRotation
}

Entity.prototype.setGlobalRotation = function (this: Entity, rotation: Quaternion) {
    let transform = this.getComponent(Transform)

    if (transform != null) {
        let parentEntity = this.getParent() as Entity
        if (parentEntity != null) {
            transform.rotation = rotation.multiply(Quaternion.Inverse(parentEntity.getGlobalRotation()))
        }
        else {
            transform.rotation = rotation
        }
    }
}

Entity.prototype.getGlobalScale = function (this: Entity) {
    let entityScale = this.hasComponent(Transform) ? this.getComponent(Transform).scale.clone() : Vector3.One()
    let parentEntity = this.getParent() as Entity

    if (parentEntity != null) {
        return parentEntity.getGlobalScale().multiply(entityScale)
    }

    return entityScale
}

Entity.prototype.setGlobalScale = function (this: Entity, scale: Vector3) {
    let transform = this.getComponent(Transform)

    if (transform != null) {
        let parentEntity = this.getParent() as Entity
        if (parentEntity != null) {
            transform.scale = DivVectors(scale, parentEntity.getGlobalScale())
        }
        else {
            transform.scale = scale
        }
    }
}

Entity.prototype.globalForward = function (this: Entity) {
    return Vector3.Forward().rotate(this.getGlobalRotation())
}

Entity.prototype.globalRight = function (this: Entity) {
    return Vector3.Right().rotate(this.getGlobalRotation())
}

Entity.prototype.globalUp = function (this: Entity) {
    return Vector3.Up().rotate(this.getGlobalRotation())
}

Further improvements:

We can further improve performance if we make the renderer supply some of the data instead of looping through the entity tree in the scene's worker.

@menduz
Copy link
Member

menduz commented Oct 31, 2019

Those helpers will be definitely helpful, isn't the Transform component a better place to add it than the Entity class?

Adding those to the entity will break the ECS pattern. It is not that we cannot do it, but it will open the door to other anti patterns and in the future it will be more difficult to get rid of those anti patterns

@belohlavek
Copy link
Contributor Author

belohlavek commented Oct 31, 2019

Those helpers will be definitely helpful, isn't the Transform component a better place to add it than the Entity class?

Yes! Please read the issue :P

The proposed implementation was copy pasted from elsewhere, I didn't update the signatures but the proposed API is meant to be fully implemented in the Transform component

Sorry if it is not clear enough 😓

@menduz
Copy link
Member

menduz commented Oct 31, 2019

Ok, it makes sense

@moliva moliva added the builder label Nov 7, 2019
@moliva moliva self-assigned this Nov 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants