1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.replica.replicaisland; 18 19import java.util.Comparator; 20 21/** 22 * A node in the game graph that manages the activation status of its children. The 23 * GameObjectManager moves the objects it manages in and out of the active list (that is, 24 * in and out of the game tree, causing them to be updated or ignored, respectively) each frame 25 * based on the distance of that object to the camera. Objects may specify an "activation radius" 26 * to define an area around themselves so that the position of the camera can be used to determine 27 * which objects should receive processing time and which should be ignored. Objects that do not 28 * move should have an activation radius that defines a sphere similar to the size of the screen; 29 * they only need processing when they are visible. Objects that move around will probably need 30 * larger regions so that they can leave the visible area of the game world and not be immediately 31 * deactivated. 32 */ 33public class GameObjectManager extends ObjectManager { 34 private static final int MAX_GAME_OBJECTS = 384; 35 private float mMaxActivationRadius; 36 private final static HorizontalPositionComparator sGameObjectComparator 37 = new HorizontalPositionComparator(); 38 private FixedSizeArray<BaseObject> mInactiveObjects; 39 private FixedSizeArray<GameObject> mMarkedForDeathObjects; 40 private GameObject mPlayer; 41 private boolean mVisitingGraph; 42 private Vector2 mCameraFocus; 43 44 45 public GameObjectManager(float maxActivationRadius) { 46 super(MAX_GAME_OBJECTS); 47 mMaxActivationRadius = maxActivationRadius; 48 49 mInactiveObjects = new FixedSizeArray<BaseObject>(MAX_GAME_OBJECTS); 50 mInactiveObjects.setComparator(sGameObjectComparator); 51 52 mMarkedForDeathObjects = new FixedSizeArray<GameObject>(MAX_GAME_OBJECTS); 53 mVisitingGraph = false; 54 55 mCameraFocus = new Vector2(); 56 57 } 58 59 @Override 60 public void commitUpdates() { 61 super.commitUpdates(); 62 63 GameObjectFactory factory = sSystemRegistry.gameObjectFactory; 64 final int objectsToKillCount = mMarkedForDeathObjects.getCount(); 65 if (factory != null && objectsToKillCount > 0) { 66 final Object[] deathArray = mMarkedForDeathObjects.getArray(); 67 for (int x = 0; x < objectsToKillCount; x++) { 68 factory.destroy((GameObject)deathArray[x]); 69 } 70 mMarkedForDeathObjects.clear(); 71 } 72 } 73 74 @Override 75 public void update(float timeDelta, BaseObject parent) { 76 commitUpdates(); 77 78 CameraSystem camera = sSystemRegistry.cameraSystem; 79 80 mCameraFocus.set(camera.getFocusPositionX(), camera.getFocusPositionY()); 81 mVisitingGraph = true; 82 FixedSizeArray<BaseObject> objects = getObjects(); 83 final int count = objects.getCount(); 84 85 if (count > 0) { 86 final Object[] objectArray = objects.getArray(); 87 for (int i = count - 1; i >= 0; i--) { 88 GameObject gameObject = (GameObject)objectArray[i]; 89 final float distance2 = mCameraFocus.distance2(gameObject.getPosition()); 90 if (distance2 < (gameObject.activationRadius * gameObject.activationRadius) 91 || gameObject.activationRadius == -1) { 92 gameObject.update(timeDelta, this); 93 } else { 94 // Remove the object from the list. 95 // It's safe to just swap the current object with the last 96 // object because this list is being iterated backwards, so 97 // the last object in the list has already been processed. 98 objects.swapWithLast(i); 99 objects.removeLast(); 100 if (gameObject.destroyOnDeactivation) { 101 mMarkedForDeathObjects.add(gameObject); 102 } else { 103 mInactiveObjects.add((BaseObject)gameObject); 104 } 105 } 106 } 107 } 108 109 mInactiveObjects.sort(false); 110 final int inactiveCount = mInactiveObjects.getCount(); 111 if (inactiveCount > 0) { 112 final Object[] inactiveArray = mInactiveObjects.getArray(); 113 for (int i = inactiveCount - 1; i >= 0; i--) { 114 GameObject gameObject = (GameObject)inactiveArray[i]; 115 116 final Vector2 position = gameObject.getPosition(); 117 final float distance2 = mCameraFocus.distance2(position); 118 final float xDistance = position.x - mCameraFocus.x; 119 if (distance2 < (gameObject.activationRadius * gameObject.activationRadius) 120 || gameObject.activationRadius == -1) { 121 gameObject.update(timeDelta, this); 122 mInactiveObjects.swapWithLast(i); 123 mInactiveObjects.removeLast(); 124 objects.add(gameObject); 125 } else if (xDistance < -mMaxActivationRadius) { 126 // We've passed the focus, we can stop processing now 127 break; 128 } 129 } 130 } 131 mVisitingGraph = false; 132 } 133 134 135 @Override 136 public void add(BaseObject object) { 137 if (object instanceof GameObject) { 138 super.add(object); 139 } 140 } 141 142 @Override 143 public void remove(BaseObject object) { 144 super.remove(object); 145 if (object == mPlayer) { 146 mPlayer = null; 147 } 148 } 149 150 public void destroy(GameObject object) { 151 mMarkedForDeathObjects.add(object); 152 remove(object); 153 } 154 155 public void destroyAll() { 156 assert mVisitingGraph == false; 157 commitUpdates(); 158 159 FixedSizeArray<BaseObject> objects = getObjects(); 160 final int count = objects.getCount(); 161 for (int i = count - 1; i >= 0; i--) { 162 mMarkedForDeathObjects.add((GameObject)objects.get(i)); 163 objects.remove(i); 164 } 165 166 final int inactiveObjectCount = mInactiveObjects.getCount(); 167 for (int j = inactiveObjectCount - 1; j >= 0; j--) { 168 mMarkedForDeathObjects.add((GameObject)mInactiveObjects.get(j)); 169 mInactiveObjects.remove(j); 170 } 171 172 mPlayer = null; 173 } 174 175 public void setPlayer(GameObject player) { 176 mPlayer = player; 177 } 178 179 public GameObject getPlayer() { 180 return mPlayer; 181 } 182 183 /** Comparator for game objects objects. */ 184 private final static class HorizontalPositionComparator implements Comparator<BaseObject> { 185 public int compare(BaseObject object1, BaseObject object2) { 186 int result = 0; 187 if (object1 == null && object2 != null) { 188 result = 1; 189 } else if (object1 != null && object2 == null) { 190 result = -1; 191 } else if (object1 != null && object2 != null) { 192 float delta = ((GameObject) object1).getPosition().x 193 - ((GameObject) object2).getPosition().x; 194 if (delta < 0) { 195 result = -1; 196 } else if (delta > 0) { 197 result = 1; 198 } 199 } 200 return result; 201 } 202 } 203} 204