Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add convenience search methods to SceneGraph #148

Merged
merged 3 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,74 @@ public void isComponentAddable(Component component) throws InvalidComponentExcep
}
}

/**
* Returns the first child GameObject matching the name.
*
* @param name the GameObject name to search for
* @return the first GameObject found or null if not found
*/
public GameObject findChildByName(String name) {
for (GameObject go : this) {
if (go.name.equals(name)) {
return go;
}
}

return null;
}

/**
* Returns an Array of all child GameObjects matching the name.
*
* @param name the GameObject name to search for
* @return Array of all matching GameObjects
*/
public Array<GameObject> findChildrenByName(String name) {
Array<GameObject> objects = new Array<>();
for (GameObject go : this) {
if (go.name.equals(name)) {
objects.add(go);
}
}

return objects;
}

/**
* Returns an Array of all child GameObjects that have the given Component.Type
*
* @param type the Component Type to search for
* @return Array of all matching GameObjects
*/
public Array<GameObject> findChildrenByComponent(Component.Type type) {
Array<GameObject> objects = new Array<>();
for (GameObject go : this) {
Component component = go.findComponentByType(type);
if (component != null) {
objects.add(go);
}
}

return objects;
}

/**
* Returns an Array of all child GameObjects that have the given Tag
*
* @param tag the string tag to search for
* @return Array of all matching GameObjects
*/
public Array<GameObject> findChildrenByTag(String tag) {
Array<GameObject> objects = new Array<>();
for (GameObject go : this) {
if (go.tags != null && go.tags.contains(tag, false)) {
objects.add(go);
}
}

return objects;
}

@Override
public void addChild(GameObject child) {
super.addChild(child);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,49 @@ private int getNextId() {
return maxId + 1;
}

/**
* Returns the first GameObject in the scene matching the name.
*
* @param name the GameObject name to search for
* @return the first GameObject found or null if not found
*/
public GameObject findByName(String name) {
return root.findChildByName(name);
}

/**
* Returns an Array of all GameObjects in the scene matching the name.
* Traversing the scene can be expensive, cache these results if you need them often.
*
* @param name the GameObject name to search for
* @return Array of all matching GameObjects
*/
public Array<GameObject> findAllByName(String name) {
return root.findChildrenByName(name);
}

/**
* Returns an Array of all GameObjects in the scene that have the given Component.Type
* Traversing the scene can be expensive, cache these results if you need them often.
*
* @param type the Component Type to search for
* @return Array of all matching GameObjects
*/
public Array<GameObject> findAllByComponent(Component.Type type) {
return root.findChildrenByComponent(type);
}

/**
* Returns an Array of all scene GameObjects that have the given Tag
* Traversing the scene can be expensive, cache these results if you need them often.
*
* @param tag the string tag to search for
* @return Array of all matching GameObjects
*/
public Array<GameObject> findAllByTag(String tag) {
return root.findChildrenByTag(tag);
}

public GameObject getRoot() {
return root;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class LightUtils {
*/
public static DirectionalLight getDirectionalLight(Environment env) {
DirectionalLightsAttribute dirLightAttribs = env.get(DirectionalLightsAttribute.class, DirectionalLightsAttribute.Type);
if (dirLightAttribs == null) return null;

Array<DirectionalLight> dirLights = dirLightAttribs.lights;
if (dirLights != null && dirLights.size > 0) {
return dirLights.first();
Expand Down
187 changes: 187 additions & 0 deletions commons/src/test/com/mbrlabs/mundus/commons/SceneGraphTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2016. See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.mbrlabs.mundus.commons;

import com.badlogic.gdx.utils.Array;
import com.mbrlabs.mundus.commons.env.MundusEnvironment;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.scene3d.InvalidComponentException;
import com.mbrlabs.mundus.commons.scene3d.Node;
import com.mbrlabs.mundus.commons.scene3d.SceneGraph;
import com.mbrlabs.mundus.commons.scene3d.SimpleNode;

import com.mbrlabs.mundus.commons.scene3d.components.Component;
import com.mbrlabs.mundus.commons.scene3d.components.ModelComponent;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

/**
* @author Marcus Brummer
* @version 21-06-2016
*/
public class SceneGraphTest {

@Test
public void basicParenting() {
Node<SimpleNode> root = new SimpleNode<>(0);
Assert.assertNull(root.getChildren());

SimpleNode<SimpleNode> c0 = new SimpleNode<>(1);
root.addChild(c0);
Assert.assertEquals(1, root.getChildren().size);
Assert.assertSame(root.getChildren().first(), c0);
Assert.assertSame(root, c0.getParent());

SimpleNode<SimpleNode> c1 = new SimpleNode<>(2);
root.addChild(c1);
Assert.assertEquals(2, root.getChildren().size);
Assert.assertSame(root, c0.getParent());

c0.remove();
Assert.assertEquals(1, root.getChildren().size);
Assert.assertNull(c0.getParent());
}

@Test
public void gameObjectFindByName() {
SceneGraph sceneGraph = new SceneGraph(null);

// The GO to search for
String searchName = "SearchName";
GameObject searchObject = new GameObject(sceneGraph, searchName, -1);

// Parent GO
GameObject parent = new GameObject(sceneGraph, "Parent", -1);
parent.addChild(searchObject);

sceneGraph.addGameObject(parent);

GameObject result = sceneGraph.findByName(searchName);
Assert.assertNotNull(result);
Assert.assertEquals(searchName, result.name);
}

@Test
public void gameObjectsFindByName() {
SceneGraph sceneGraph = new SceneGraph(null);

// The GO's to search for
String searchName = "SearchName";
GameObject searchObject = new GameObject(sceneGraph, searchName, -1);
GameObject searchObjectTwo = new GameObject(sceneGraph, searchName, -1);

// Parent GO
GameObject parent = new GameObject(sceneGraph, "Parent", -1);
parent.addChild(searchObject);
parent.addChild(searchObjectTwo);

sceneGraph.addGameObject(parent);

Array<GameObject> result = sceneGraph.findAllByName(searchName);
Assert.assertEquals(2, result.size);
Assert.assertEquals(searchObject, result.get(0));
Assert.assertEquals(searchObjectTwo, result.get(1));
}

@Test
public void gameObjectsHierarchyFindByName() {
SceneGraph sceneGraph = new SceneGraph(null);

// The GO's to search for
String searchName = "SearchName";

int expectedResult = 0;

// Parent GO
GameObject parent = new GameObject(sceneGraph, "Parent", -1);
GameObject currentParent = parent;

// Create a hierarchy of Parent->Child GO's to search through
for (int i = 0; i < 4; i++) {
GameObject searchObject = new GameObject(sceneGraph, searchName, -1);
GameObject nonSearchObject = new GameObject(sceneGraph, "OtherObject", -1);
currentParent.addChild(searchObject);
currentParent.addChild(nonSearchObject);

// each iteration, current child becomes next parent
// variate which one is parent to complicate scenegraph more
currentParent = i % 2 == 0 ? searchObject : nonSearchObject;
expectedResult++;
}

int parentCount = 0;
// Add the top level parent multiple times just add complexity to scenegraph
for (int i = 0; i < 4; i++) {
sceneGraph.addGameObject(parent);
parentCount++;
}

Array<GameObject> result = sceneGraph.findAllByName(searchName);
Assert.assertEquals(expectedResult * parentCount, result.size);
}

@Test
public void gameObjectsFindByComponent() throws InvalidComponentException {
Scene mock = Mockito.mock(Scene.class);
mock.environment = new MundusEnvironment();

SceneGraph sceneGraph = new SceneGraph(null);
sceneGraph.scene = mock;

// The GO's to search for
String searchName = "SearchName";
GameObject searchObject = new GameObject(sceneGraph, searchName, -1);
GameObject searchObjectTwo = new GameObject(sceneGraph, searchName, -1);

searchObject.addComponent(new ModelComponent(searchObject));
searchObjectTwo.addComponent(new ModelComponent(searchObjectTwo));

// Parent GO
GameObject parent = new GameObject(sceneGraph, "Parent", -1);
parent.addChild(searchObject);
parent.addChild(searchObjectTwo);

sceneGraph.addGameObject(parent);

Array<GameObject> result = sceneGraph.findAllByComponent(Component.Type.MODEL);
Assert.assertEquals(2, result.size);
Assert.assertEquals(searchObject, result.get(0));
Assert.assertEquals(searchObjectTwo, result.get(1));
}

@Test
public void gameObjectFindByTag() {
SceneGraph sceneGraph = new SceneGraph(null);

// The GO to search for
String searchTag = "SearchTag";
GameObject searchObject = new GameObject(sceneGraph, "search", -1);
searchObject.addTag(searchTag);

// Parent GO
GameObject parent = new GameObject(sceneGraph, "Parent", -1);
parent.addChild(searchObject);

sceneGraph.addGameObject(parent);

Array<GameObject> result = sceneGraph.findAllByTag(searchTag);
Assert.assertEquals(1, result.size);
Assert.assertEquals(searchTag, result.first().getTags().first());
}

}

This file was deleted.

1 change: 1 addition & 0 deletions gdx-runtime/CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Add render event handling
- Change scene camera to be base camera class
- Add active boolean to Skybox class to toggle rendering
- Added new convenience methods to SceneGraph and GameObject for searching for GameObjects

[0.4.0] ~ 10/12/2022
- [BREAKING CHANGE] The loadScene method for the runtime has changed. A ModelBatch is no longer required to be passed in.
Expand Down