/* * Copyright (C) 2008 The Android Open Source Project * * 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.replica.replicaisland; import android.content.res.AssetManager; import java.io.IOException; import java.io.InputStream; /** * Manages information about the current level, including setup, deserialization, and tear-down. */ public class LevelSystem extends BaseObject { public int mWidthInTiles; public int mHeightInTiles; public int mTileWidth; public int mTileHeight; public GameObject mBackgroundObject; public ObjectManager mRoot; private byte[] mWorkspaceBytes; private TiledWorld mSpawnLocations; private GameFlowEvent mGameFlowEvent; private int mAttempts; private LevelTree.Level mCurrentLevel; public LevelSystem() { super(); mWorkspaceBytes = new byte[4]; mGameFlowEvent = new GameFlowEvent(); reset(); } @Override public void reset() { if (mBackgroundObject != null && mRoot != null) { mBackgroundObject.removeAll(); mBackgroundObject.commitUpdates(); mRoot.remove(mBackgroundObject); mBackgroundObject = null; mRoot = null; } mSpawnLocations = null; mAttempts = 0; mCurrentLevel = null; } public float getLevelWidth() { return mWidthInTiles * mTileWidth; } public float getLevelHeight() { return mHeightInTiles * mTileHeight; } public void sendRestartEvent() { mGameFlowEvent.post(GameFlowEvent.EVENT_RESTART_LEVEL, 0, sSystemRegistry.contextParameters.context); } public void sendNextLevelEvent() { mGameFlowEvent.post(GameFlowEvent.EVENT_GO_TO_NEXT_LEVEL, 0, sSystemRegistry.contextParameters.context); } public void sendGameEvent(int type, int index, boolean immediate) { if (immediate) { mGameFlowEvent.postImmediate(type, index, sSystemRegistry.contextParameters.context); } else { mGameFlowEvent.post(type, index, sSystemRegistry.contextParameters.context); } } /** * Loads a level from a binary file. The file consists of several layers, including background * tile layers and at most one collision layer. Each layer is used to bootstrap related systems * and provide them with layer data. * @param stream The input stream for the level file resource. * @param tiles A tile library to use when constructing tiled background layers. * @param background An object to assign background layer rendering components to. * @return */ public boolean loadLevel(LevelTree.Level level, InputStream stream, ObjectManager root) { boolean success = false; mCurrentLevel = level; AssetManager.AssetInputStream byteStream = (AssetManager.AssetInputStream) stream; int signature; try { signature = (byte)byteStream.read(); if (signature == 96) { final int layerCount = (byte)byteStream.read(); final int backgroundIndex = (byte)byteStream.read(); mRoot = root; mTileWidth = 32; mTileHeight = 32; ContextParameters params = sSystemRegistry.contextParameters; int currentPriority = SortConstants.BACKGROUND_START + 1; for (int x = 0; x < layerCount; x++) { final int type = (byte)byteStream.read(); final int tileIndex = (byte)byteStream.read(); byteStream.read(mWorkspaceBytes, 0, 4); final float scrollSpeed = Utils.byteArrayToFloat(mWorkspaceBytes); // TODO: use a pool here? Seems pointless. TiledWorld world = new TiledWorld(byteStream); if (type == 0) { // it's a background layer assert mWidthInTiles != 0; assert mTileWidth != 0; // We require a collision layer to set up the tile sizes before we load. // TODO: this really sucks. there's no reason each layer can't have its // own tile widths and heights. Refactor this crap. if (mWidthInTiles > 0 && mTileWidth > 0) { LevelBuilder builder = sSystemRegistry.levelBuilder; if (mBackgroundObject == null) { mBackgroundObject = builder.buildBackground( backgroundIndex, mWidthInTiles * mTileWidth, mHeightInTiles * mTileHeight); root.add(mBackgroundObject); } builder.addTileMapLayer(mBackgroundObject, currentPriority, scrollSpeed, params.gameWidth, params.gameHeight, mTileWidth, mTileHeight, world, tileIndex); currentPriority++; } } else if (type == 1) { // collision // Collision always defines the world boundaries. mWidthInTiles = world.getWidth(); mHeightInTiles = world.getHeight(); CollisionSystem collision = sSystemRegistry.collisionSystem; if (collision != null) { collision.initialize(world, mTileWidth, mTileHeight); } } else if (type == 2) { // objects mSpawnLocations = world; spawnObjects(); } else if (type == 3) { // hot spots HotSpotSystem hotSpots = sSystemRegistry.hotSpotSystem; if (hotSpots != null) { hotSpots.setWorld(world); } } } // hack! sSystemRegistry.levelBuilder.promoteForegroundLayer(mBackgroundObject); } } catch (IOException e) { //TODO: figure out the best way to deal with this. Assert? } return success; } public void spawnObjects() { GameObjectFactory factory = sSystemRegistry.gameObjectFactory; if (factory != null && mSpawnLocations != null) { DebugLog.d("LevelSystem", "Spawning Objects!"); factory.spawnFromWorld(mSpawnLocations, mTileWidth, mTileHeight); } } public void incrementAttemptsCount() { mAttempts++; } public int getAttemptsCount() { return mAttempts; } public LevelTree.Level getCurrentLevel() { return mCurrentLevel; } }