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 17 package com.replica.replicaisland; 18 19 import android.content.res.AssetManager; 20 21 import java.io.IOException; 22 import java.io.InputStream; 23 24 /** 25 * Manages information about the current level, including setup, deserialization, and tear-down. 26 */ 27 public class LevelSystem extends BaseObject { 28 29 public int mWidthInTiles; 30 public int mHeightInTiles; 31 public int mTileWidth; 32 public int mTileHeight; 33 public GameObject mBackgroundObject; 34 public ObjectManager mRoot; 35 private byte[] mWorkspaceBytes; 36 private TiledWorld mSpawnLocations; 37 private GameFlowEvent mGameFlowEvent; 38 private int mAttempts; 39 private LevelTree.Level mCurrentLevel; 40 41 public LevelSystem() { 42 super(); 43 mWorkspaceBytes = new byte[4]; 44 mGameFlowEvent = new GameFlowEvent(); 45 reset(); 46 } 47 48 @Override 49 public void reset() { 50 if (mBackgroundObject != null && mRoot != null) { 51 mBackgroundObject.removeAll(); 52 mBackgroundObject.commitUpdates(); 53 mRoot.remove(mBackgroundObject); 54 mBackgroundObject = null; 55 mRoot = null; 56 } 57 mSpawnLocations = null; 58 mAttempts = 0; 59 mCurrentLevel = null; 60 } 61 62 public float getLevelWidth() { 63 return mWidthInTiles * mTileWidth; 64 } 65 66 public float getLevelHeight() { 67 return mHeightInTiles * mTileHeight; 68 } 69 70 public void sendRestartEvent() { 71 mGameFlowEvent.post(GameFlowEvent.EVENT_RESTART_LEVEL, 0, 72 sSystemRegistry.contextParameters.context); 73 } 74 75 public void sendNextLevelEvent() { 76 mGameFlowEvent.post(GameFlowEvent.EVENT_GO_TO_NEXT_LEVEL, 0, 77 sSystemRegistry.contextParameters.context); 78 } 79 80 public void sendGameEvent(int type, int index, boolean immediate) { 81 if (immediate) { 82 mGameFlowEvent.postImmediate(type, index, 83 sSystemRegistry.contextParameters.context); 84 } else { 85 mGameFlowEvent.post(type, index, 86 sSystemRegistry.contextParameters.context); 87 } 88 } 89 90 /** 91 * Loads a level from a binary file. The file consists of several layers, including background 92 * tile layers and at most one collision layer. Each layer is used to bootstrap related systems 93 * and provide them with layer data. 94 * @param stream The input stream for the level file resource. 95 * @param tiles A tile library to use when constructing tiled background layers. 96 * @param background An object to assign background layer rendering components to. 97 * @return 98 */ 99 public boolean loadLevel(LevelTree.Level level, InputStream stream, ObjectManager root) { 100 boolean success = false; 101 mCurrentLevel = level; 102 AssetManager.AssetInputStream byteStream = (AssetManager.AssetInputStream) stream; 103 int signature; 104 try { 105 signature = (byte)byteStream.read(); 106 if (signature == 96) { 107 final int layerCount = (byte)byteStream.read(); 108 final int backgroundIndex = (byte)byteStream.read(); 109 110 mRoot = root; 111 mTileWidth = 32; 112 mTileHeight = 32; 113 114 ContextParameters params = sSystemRegistry.contextParameters; 115 int currentPriority = SortConstants.BACKGROUND_START + 1; 116 for (int x = 0; x < layerCount; x++) { 117 final int type = (byte)byteStream.read(); 118 final int tileIndex = (byte)byteStream.read(); 119 byteStream.read(mWorkspaceBytes, 0, 4); 120 final float scrollSpeed = Utils.byteArrayToFloat(mWorkspaceBytes); 121 122 // TODO: use a pool here? Seems pointless. 123 TiledWorld world = new TiledWorld(byteStream); 124 125 if (type == 0) { // it's a background layer 126 assert mWidthInTiles != 0; 127 assert mTileWidth != 0; 128 129 // We require a collision layer to set up the tile sizes before we load. 130 // TODO: this really sucks. there's no reason each layer can't have its 131 // own tile widths and heights. Refactor this crap. 132 if (mWidthInTiles > 0 && mTileWidth > 0) { 133 134 LevelBuilder builder = sSystemRegistry.levelBuilder; 135 136 if (mBackgroundObject == null) { 137 mBackgroundObject = 138 builder.buildBackground( 139 backgroundIndex, 140 mWidthInTiles * mTileWidth, 141 mHeightInTiles * mTileHeight); 142 root.add(mBackgroundObject); 143 } 144 145 146 builder.addTileMapLayer(mBackgroundObject, currentPriority, 147 scrollSpeed, params.gameWidth, params.gameHeight, 148 mTileWidth, mTileHeight, world, tileIndex); 149 150 151 currentPriority++; 152 } 153 154 } else if (type == 1) { // collision 155 // Collision always defines the world boundaries. 156 mWidthInTiles = world.getWidth(); 157 mHeightInTiles = world.getHeight(); 158 159 160 CollisionSystem collision = sSystemRegistry.collisionSystem; 161 if (collision != null) { 162 collision.initialize(world, mTileWidth, mTileHeight); 163 } 164 } else if (type == 2) { // objects 165 mSpawnLocations = world; 166 spawnObjects(); 167 } else if (type == 3) { // hot spots 168 HotSpotSystem hotSpots = sSystemRegistry.hotSpotSystem; 169 if (hotSpots != null) { 170 hotSpots.setWorld(world); 171 } 172 173 } 174 } 175 176 // hack! 177 sSystemRegistry.levelBuilder.promoteForegroundLayer(mBackgroundObject); 178 179 } 180 181 } catch (IOException e) { 182 //TODO: figure out the best way to deal with this. Assert? 183 } 184 185 return success; 186 } 187 188 public void spawnObjects() { 189 GameObjectFactory factory = sSystemRegistry.gameObjectFactory; 190 if (factory != null && mSpawnLocations != null) { 191 DebugLog.d("LevelSystem", "Spawning Objects!"); 192 193 factory.spawnFromWorld(mSpawnLocations, mTileWidth, mTileHeight); 194 } 195 } 196 197 public void incrementAttemptsCount() { 198 mAttempts++; 199 } 200 201 public int getAttemptsCount() { 202 return mAttempts; 203 } 204 205 public LevelTree.Level getCurrentLevel() { 206 return mCurrentLevel; 207 } 208 } 209