com.isoterik.racken.GameObject Maven / Gradle / Ivy
Show all versions of racken Show documentation
package com.isoterik.racken;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.SnapshotArray;
import com.badlogic.gdx.utils.reflect.ClassReflection;
/**
* A GameObject represents an entity in the game. A GameObject can't do anything on its own; you have to give it
* properties before it can do anything.
* A GameObject is a container; we have to add pieces to it to make into a character, a tree, a spaceship or whatever
* else you would like it to be. Each piece is called a {@link Component}.
*
*
* Every GameObject has a {@link Transform} component attached automatically and cannot be removed. This is because the
* Transform defines where the GameObject is located and how it is rotated and scaled; without a Transform, the
* GameObject would not have a location in the game world.
*
*
* To create game objects, use the static factory methods: {@link #newInstance(String)} and {@link #newInstance()}
*
* @see Component
*
* @author imranabdulmalik
*/
public final class GameObject {
private final SnapshotArray components;
private final SnapshotArray children;
public final Transform transform;
private String tag;
private Scene hostScene;
private GameObject parent;
private GameObject()
{ this("Untagged"); }
private GameObject(String tag) {
components = new SnapshotArray<>(Component.class);
children = new SnapshotArray<>(GameObject.class);
transform = new Transform();
transform.__setGameObject(this);
components.add(transform);
this.tag = tag;
}
/**
* Adds child game objects to this game object
* @param children the children
* @throws IllegalStateException if any of the children is already a child of another game object
*/
public void addChildren(GameObject... children) {
for (GameObject child : children)
addChild(child);
}
/**
* Adds a child to this game object
* @param child the child to add
* @throws IllegalStateException if the child is already a child of another game object
*/
public void addChild(GameObject child) {
if (child.hasParent())
throw new IllegalStateException("A GameObject cannot have more than one parent: " +
"Tag=" + child.getTag());
if (!children.contains(child, true)) {
children.add(child);
child.setParent(this);
}
}
/**
* Removes a child from this game object
* @param child the child to remove
* @return true if the child was found and removed. false otherwise
*/
public boolean removeChild(GameObject child) {
boolean removed = children.removeValue(child, true);
if (removed)
child.setParent(null);
return removed;
}
/**
* Removes all children of this game object
*/
public void clearChildren() {
for (GameObject child : children)
child.setParent(null);
children.clear();
}
/**
* Returns the children of this game object
* @return the children of this game object
*/
public SnapshotArray getChildren() {
return children;
}
/**
* Sets the scene where this game object resides.
* This method is called internally by the system. Do not call it directly!
* @param hostScene the host scene
*/
public void __setHostScene(Scene hostScene) {
this.hostScene = hostScene;
for (Component comp : components) {
comp.__setHostScene(hostScene);
if (comp.getRenderCamera() == null)
comp.setRenderCamera(hostScene.getMainCamera());
}
forEachChild(gameObject -> gameObject.__setHostScene(hostScene));
}
public void setParent(GameObject parent) {
this.parent = parent;
}
public GameObject getParent() {
return parent;
}
public boolean hasParent() {
return parent != null;
}
/**
*
* @return the scene where this game object resides
*/
public Scene getHostScene()
{ return hostScene; }
/**
* Sets the tag for this game object. It is not required to be unique.
* @param tag the tag
*/
public void setTag(String tag)
{ this.tag = tag; }
/**
*
* @return the tag for this game object
*/
public String getTag()
{ return tag; }
/**
* Called when this game object is removed from a scene.
* DO NOT CALL THIS METHOD!
*/
public void __removeFromScene() {
for (Component comp : components)
comp.stop();
forEachChild(GameObject::__removeFromScene);
}
/**
* Adds a component to this game object.
* @param component the component
*/
public void addComponent(Component component) {
if (components.contains(component, true))
return;
component.__setGameObject(this);
component.attach();
for (Component comp : components)
comp.componentAdded(component);
// If this game object is already added to a scene then we need to alert the component
if (hostScene != null) {
component.__setHostScene(hostScene);
if (component.getRenderCamera() == null)
component.setRenderCamera(hostScene.getMainCamera());
component.start();
}
components.add(component);
}
/**
* Removes a component attached to this game object.
* @param component the component to remove.
* @return true if the component was removed. false otherwise
*/
public boolean removeComponent(Component component) {
if (components.contains(component, true) &&
components.removeValue(component, true)) {
for (Component comp : components)
comp.componentRemoved(component);
// detach
component.detach();
component.__setGameObject(null);
return true;
}
return false;
}
/**
* Removes the first component found for a particular type that is attached to this host game object.
* @param componentClass the class of the component
* @param the type of component
* @return true if a component of such type is removed. false otherwise
*/
public boolean removeComponent(Class componentClass)
{ return removeComponent(getComponent(componentClass)); }
/**
* Removes all the components found for a particular type that is attached to this host game object.
* @param componentClass the class of the component
* @param the type of component
*/
public void removeComponents(Class componentClass) {
for (Component c : components) {
if (ClassReflection.isAssignableFrom(componentClass, c.getClass()))
removeComponent(c);
}
}
/**
* Gets a component of a particular type that is attached to this game object.
* @param componentClass the class of the component
* @param the type of component
* @return the component. null if not found
*/
public T getComponent(Class componentClass) {
for (Component c : components) {
if (ClassReflection.isAssignableFrom(componentClass, c.getClass()))
return (T)c;
}
return null;
}
/**
* Gets components of a particular type that is attached to this game object.
* @param componentClass the class of the component
* @param the type of component
* @return the components found or empty list if none found
*/
public Array getComponents(Class componentClass) {
Array comps = new Array<>();
for (Component c : components) {
if (ClassReflection.isAssignableFrom(componentClass, c.getClass()))
comps.add((T)c);
}
return comps;
}
/**
* Returns all the components attached to this game object.
* @return all the components attached to this game object.
*/
public SnapshotArray getComponents()
{ return components; }
/**
* Checks if a component of a particular type is attached to the host game object.
* @param componentClass the class of the component
* @param the type of component
* @return true if a component of such type exists. false otherwise
*/
public boolean hasComponent(Class componentClass)
{ return getComponent(componentClass) != null; }
/**
* Checks if a component is attached to this game object.
* @param component the component to check.
* @return true if a component of such type exists. false otherwise
*/
public boolean hasComponent(Component component)
{ return components.contains(component, true); }
/**
* Calls the given iteration listener on all components attached to this game object.
* @param iterationListener the iteration listener
* @param withChildren if true, the components of the children of this game object will also be iterated
*/
public void forEachComponent(ComponentIterationListener iterationListener, boolean withChildren) {
Component[] array = components.begin();
for (Component component : array)
if (component != null)
iterationListener.onIterate(component);
components.end();
if (withChildren)
forEachChild(gameObject -> gameObject.forEachComponent(iterationListener));
}
/**
* Calls the given iteration listener on all components attached to this game object and all its children
* @param iterationListener the iteration listener
*/
public void forEachComponent(ComponentIterationListener iterationListener) {
forEachComponent(iterationListener, true);
}
/**
* Calls the given iteration listener on every child of this game object
* @param iterationListener the iteration listener
*/
public void forEachChild(GameObjectIterationListener iterationListener) {
GameObject[] array = children.begin();
for (GameObject gameObject : array)
if (gameObject != null)
iterationListener.onIterate(gameObject);
children.end();
}
/**
* Checks if the provided tag equals the current tag of this gameObject.
* @param otherTag the tag to compare to.
* @return true if the tags are similar. false otherwise
*/
public boolean sameTag(String otherTag) {
return this.tag.equals(otherTag);
}
/**
* An iteration listener that can be used to iterate the components of a {@link GameObject}.
*/
public interface ComponentIterationListener {
void onIterate(Component component);
}
/**
* Creates a new {@link GameObject} given a tag.
* @param tag the tag for the game object
* @return the created game object
*/
public static GameObject newInstance(String tag)
{ return new GameObject(tag); }
/**
* Creates a new {@link GameObject} using 'Untagged' as the default tag.
* @return the created game object
*/
public static GameObject newInstance()
{ return new GameObject(); }
/**
* An iteration listener for processing game objects
*/
public interface GameObjectIterationListener {
void onIterate(GameObject gameObject);
}
}