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