com.timvisee.voxeltex.architecture.gameobject.GameObject.java Source code

Java tutorial

Introduction

Here is the source code for com.timvisee.voxeltex.architecture.gameobject.GameObject.java

Source

/******************************************************************************
 * Copyright (c) Tim Visee 2016. All rights reserved.                         *
 *                                                                            *
 * @author Tim Visee                                                          *
 * @website http://timvisee.com/                                              *
 *                                                                            *
 * Open Source != No Copyright                                                *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included    *
 * in all copies or substantial portions of the Software.                     *
 *                                                                            *
 * You should have received a copy of The MIT License (MIT) along with this   *
 * program. If not, see <http://opensource.org/licenses/MIT/>.                *
 ******************************************************************************/

package com.timvisee.voxeltex.architecture.gameobject;

import com.timvisee.voxeltex.architecture.component.AbstractComponent;
import com.timvisee.voxeltex.architecture.component.drawable.DrawableComponentInterface;
import com.timvisee.voxeltex.architecture.component.overlay.OverlayComponentInterface;
import com.timvisee.voxeltex.module.transform.Transform;
import com.timvisee.voxeltex.runtime.global.MainCamera;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

public class GameObject extends AbstractGameObject {

    /**
     * Game object name.
     */
    private String name;

    /**
     * The transform instance of this object.
     */
    private Transform transform = new Transform(this);

    /**
     * The parent of this game object.
     */
    private AbstractGameObject parent = null;

    /**
     * The children of this game object.
     */
    private List<AbstractGameObject> children = new ArrayList<>();

    /**
     * The components on this game object.
     */
    private List<AbstractComponent> components = new ArrayList<>();

    /**
     * List of children that are queued to be removed.
     */
    private List<AbstractGameObject> childrenRemoveQueue = new ArrayList<>();

    /**
     * List of components that are queued to be removed.
     */
    private List<AbstractComponent> componentsRemoveQueue = new ArrayList<>();

    /**
     * Float buffer for the rendering matrix.
     */
    private FloatBuffer fb = BufferUtils.createFloatBuffer(16);

    /**
     * View matrix cache.
     * This is used to optimize performance and object allocation at runtime.
     */
    private static final Matrix4f viewMatrixCache = new Matrix4f();

    /**
     * Constructor.
     *
     * @param name Game object name.
     */
    public GameObject(String name) {
        super(name);
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Transform getTransform() {
        return this.transform;
    }

    @Override
    public AbstractGameObject getParent() {
        return this.parent;
    }

    @Override
    public boolean hasParent() {
        return getParent() != null;
    }

    @Override
    public void setParent(AbstractGameObject parent) {
        this.parent = parent;
    }

    @Override
    public List<AbstractGameObject> getChildren() {
        return this.children;
    }

    @Override
    public boolean hasChildren() {
        return getChildCount(false) > 0;
    }

    @Override
    public int getChildCount(boolean recursive) {
        // Count the number of children if not recursive
        if (!recursive)
            return this.children.size();

        // Count the number of recursive children
        int count = 0;

        // Loop through all the children, and count
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            count += this.children.get(i).getChildCount(true);

        // Return the number of recursive children
        return count;
    }

    @Override
    public void addChild(AbstractGameObject gameObject) {
        // Set the parent
        gameObject.setParent(this);

        // Set the scene
        gameObject.setScene(getScene());

        // Add the game object to the children
        this.children.add(gameObject);

        // Create the game object
        if (getScene() != null)
            gameObject.create();

        // Start the game object if the scene has started
        if (isSceneStarted())
            gameObject.start();
    }

    @Override
    public AbstractGameObject getChild(int i) {
        return this.children.get(i);
    }

    @Override
    public boolean removeChild(AbstractGameObject gameObject) {
        return this.childrenRemoveQueue.add(gameObject);
    }

    @Override
    public AbstractGameObject removeChild(int i) {
        // Get the child that will be removed
        AbstractGameObject child = this.children.get(i);

        // Remove and return the child
        removeChild(child);
        return child;
    }

    @Override
    public List<AbstractComponent> getComponents() {
        return this.components;
    }

    @Override
    public boolean hasComponents() {
        return getComponentCount() > 0;
    }

    @Override
    public int getComponentCount() {
        return this.components.size();
    }

    @Override
    public void addComponent(AbstractComponent component) {
        // Add the component
        this.components.add(component);

        // Set the component owner
        component.setOwner(this);

        // Create the component
        if (getScene() != null)
            component.create();

        // Start the component if the scene is started
        if (isSceneStarted())
            component.start();
    }

    @Override
    public AbstractComponent getComponent(int i) {
        return this.components.get(i);
    }

    @Override
    public <T extends AbstractComponent> T getComponent(Class<T> componentType) {
        // Loop through all components to find an applicable one
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++) {
            // Check whether this component is valid
            if (componentType.isAssignableFrom(this.components.get(i).getClass()))
                //noinspection unchecked
                return (T) this.components.get(i);
        }

        // None found, return null
        return null;
    }

    @Override
    public boolean removeComponent(AbstractComponent component) {
        return this.componentsRemoveQueue.add(component);
    }

    @Override
    public AbstractComponent removeComponent(int i) {
        // Get the component that will be removed
        AbstractComponent component = this.components.get(i);

        // Remove the component, and return
        removeComponent(component);
        return component;
    }

    @Override
    public void create() {
        // Create the children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            this.children.get(i).create();

        // Create all components
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++)
            this.components.get(i).create();
    }

    @Override
    public void start() {
        // Start the children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            this.children.get(i).start();

        // Start all components
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++)
            this.components.get(i).start();

        // Enable the game object if it's enabled state is yet undefined
        if (isEnabledUndefined())
            setEnabled(true);
    }

    @Override
    public synchronized void update() {
        // Update the transform
        this.transform.update();

        // Update all components
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++)
            if (this.components.get(i).isEnabled())
                this.components.get(i).update();

        // Update all children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            if (this.children.get(i).isEnabled())
                this.children.get(i).update();

        // Remove all components that were queued to be removed
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.componentsRemoveQueue.size(); i < size; i++) {
            // Reset the owner of the component
            this.componentsRemoveQueue.get(i).setOwner(null);

            // Remove the component
            this.components.remove(this.componentsRemoveQueue.get(i));
        }

        // Clear the list of queued destroyed components
        this.componentsRemoveQueue.clear();

        // Remove all children that were queued to be removed
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.childrenRemoveQueue.size(); i < size; i++)
            // Remove the child
            this.children.remove(this.childrenRemoveQueue.get(i));

        // Clear the list of queued destroyed children
        this.childrenRemoveQueue.clear();
    }

    @Override
    public void destroy() {
        // Disable the game object
        setEnabled(false);

        // Destroy all components
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++)
            this.components.get(i).destroy();

        // Destroy all children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            this.children.get(i).destroy();

        // Remove this game object from it's parent or from the scene if it doesn't have a parent
        if (hasParent())
            getParent().removeChild(this);
        else
            getScene().removeGameObject(this);

        // Force the game object to finalize
        try {
            //noinspection FinalizeCalledExplicitly
            finalize();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    @Override
    public synchronized void onDraw() {
        // Define whether we started drawing
        boolean drawing = false;

        // Draw all drawable components and all children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++) {
            // Make sure the component is drawable
            if (this.components.get(i) instanceof DrawableComponentInterface) {
                // Make sure the drawing mode is enabled
                if (!drawing) {
                    // Start the drawing process and set the flag
                    drawStart();
                    drawing = true;
                }

                // Draw the component if enabled
                if (this.components.get(i).isEnabled())
                    ((DrawableComponentInterface) this.components.get(i)).onDraw();
            }
        }

        // End the drawing process if it was enabled
        if (drawing)
            drawEnd();

        // Draw all children if enabled
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            if (this.children.get(i).isEnabled())
                this.children.get(i).onDraw();
    }

    @Override
    public synchronized void onDrawOverlay() {
        // Draw all overlay components and all children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.components.size(); i < size; i++)
            // Make sure the component is drawable
            if (this.components.get(i) instanceof OverlayComponentInterface)
                // Draw the component overlay
                if (this.components.get(i).isEnabled())
                    ((OverlayComponentInterface) this.components.get(i)).onDrawOverlay();

        // Draw all children
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0, size = this.children.size(); i < size; i++)
            if (this.children.get(i).isEnabled())
                this.children.get(i).onDrawOverlay();
    }

    /**
     * Prepare and start the drawing process.
     */
    private synchronized void drawStart() {
        // Do not use the cached view matrix in multiple places at the same time
        synchronized (viewMatrixCache) {
            // Combine the world camera and game object matrix to construct the view matrix
            getTransform().addWorldMatrix(MainCamera.createCameraViewMatrix(viewMatrixCache));

            // Load the matrix to the GPU
            GL11.glLoadMatrixf(viewMatrixCache.get(fb));
        }
    }

    /**
     * End the current drawing process.
     */
    private synchronized void drawEnd() {
        // Pop the OpenGL matrix
        GL11.glPopMatrix();
    }

    @Override
    public void onEnable() {
    }

    @Override
    public void onDisable() {
    }
}