/// <summary> /// Imports a level file. You can read the Level file format description on this file header /// </summary> /// <param name="path">The path.</param> /// <returns></returns> /// <exception cref="System.Exception">Exception Loading level file: + path</exception> public LevelModel ImportLevel(string path) { string line = string.Empty; BlockTypeEnum blockType = BlockTypeEnum.EMPTY; LevelModel model = new LevelModel(); try { // Read the level file using (Stream fs = WaveServices.Storage.OpenContentFile(path)) using (BufferedStream bs = new BufferedStream(fs, 8388608)) // 8Mb buffer it's a good buffer for files. using (StreamReader sr = new StreamReader(bs)) { float blockScaleX = 1.0f; float blockScaleY = 1.0f; float blockScaleZ = 1.0f; // FIRST LINE of the file: Block X scale if (!sr.EndOfStream) { line = sr.ReadLine(); float.TryParse(line, NumberStyles.Number, CultureInfo.InvariantCulture, out blockScaleX); ModelFactoryService.Instance.Scale.X = blockScaleX; } // SECOND LINE of the file: Block Y Scale if (!sr.EndOfStream) { line = sr.ReadLine(); float.TryParse(line, NumberStyles.Number, CultureInfo.InvariantCulture, out blockScaleY); ModelFactoryService.Instance.Scale.Y = blockScaleY; } // THIRD LINE of the file: Block Z Scale if (!sr.EndOfStream) { line = sr.ReadLine(); float.TryParse(line, NumberStyles.Number, CultureInfo.InvariantCulture, out blockScaleZ); ModelFactoryService.Instance.Scale.Z = blockScaleZ; } // The rest of the file is the level while (!sr.EndOfStream) { line = sr.ReadLine(); if (!string.IsNullOrWhiteSpace(line)) // line must be filled with data { string[] splitted = line.Split(SEPARATOR); // split the line if (splitted.Count() > 0) { Column column = new Column(); // creates the column foreach (string value in splitted) { blockType = BlockTypeEnum.EMPTY; // default value if reading error or out of block type error Enum.TryParse<BlockTypeEnum>(value, out blockType); column.Add(blockType); } model.ColumnCollection.Enqueue(column); } } } } } catch (Exception ex) { throw new Exception("Exception Loading level file: " + path, ex); } return model; }
/// <summary> /// Allows this instance to execute custom logic during its /// <c>Update</c>. /// </summary> /// <param name="gameTime">The game time.</param> /// <remarks> /// This method will not be executed if it are not /// <c>Active</c>. /// </remarks> protected override void Update(TimeSpan gameTime) { if (!this.initialized) { this.modelFactoryService = ModelFactoryService.Instance; this.playScene = this.Owner.Scene as MyScene; this.player = this.EntityManager.Find(this.PlayerSource); this.playerTransform = this.player.FindComponent<Transform3D>(); this.playerCollider = this.player.FindComponent<BoxCollider3D>(); this.playerBehavior = this.player.FindComponent<PlayerBehavior>(); this.tempBoundingBox = new BoundingBox(); this.initialized = true; } // Game Tri-state machine switch (GameState) { // Initial level state case GameState.INIT: // Loads the level // it can be done in everywhere we want, in scene too, but then we need to call a Reset method or similar this.LevelModel = ImportService.Instance.ImportLevel(WaveContent.Assets.Levels.level1A_level); // Restart Camera, Player states and positions this.player.FindComponent<PlayerBehavior>().Restart(); // put player over the first ground block // FIRST BLOCK OF LEVEL SHOULD BE A GROUND, logically this.playerTransform.Position = new Vector3(0f, this.modelFactoryService.Scale.Y, 0.0f); // fills the intiial Buffer, we need to load some elements prior playing float currentZ = 0; for (int i = 0; i < BlockBufferSize; i++) { // Create Column this.CreateNextColumnEntity(currentZ); currentZ += this.modelFactoryService.Scale.Z; } GameState = GameState.PLAY; break; // Playing State of game: case GameState.PLAY: // new player position, using acceleration, falling, etc... where applicable //// this.UpdatePlayerPosition(elapsedGameTime); // Check if dead by level platform falling down if (this.playerTransform.Position.Y <= UnderDeadLevel) { this.GameState = Enums.GameState.DIE; break; } // Selects the current and next column, selects the columns to free too. // the current column and next column are used to check collisions, only with those two columns, others are ignored for (int i = 0; i < this.ColumnCollection.Count - 1; i++) { Entity column = this.ColumnCollection[i]; var columnTransform = column.FindComponent<Transform3D>(); // Remove passedby columns by distance if (columnTransform.Position.Z < this.playerTransform.Position.Z - PasseByBlocksToDiscardColumn * this.modelFactoryService.Scale.Z) { ////// removes column this.modelFactoryService.FreeColumn(column); this.ColumnCollection.RemoveAt(i); ////// Create new column at the end this.CreateNextColumnEntity(columnTransform.Position.Z + BlockBufferSize * this.modelFactoryService.Scale.Z); } // check if player is over this column and sets current and next column else if (this.playerTransform.Position.Z < columnTransform.Position.Z + this.modelFactoryService.Scale.Z && this.playerTransform.Position.Z >= columnTransform.Position.Z) { this.CurrentColumn = column; this.NextColumn = this.ColumnCollection[i + 1]; // update the ground level for current and next columns this.CheckGroundPosition(); break; } } // if there are a current column checks the collision in current and next column if (this.CurrentColumn != null && !this.CurrentColumn.IsDisposed && this.NextColumn!=null && !this.NextColumn.IsDisposed) { // creates the union of each column entities List<Entity> collidableCollection = this.CurrentColumn.ChildEntities.ToList(); collidableCollection.AddRange(this.NextColumn.ChildEntities.ToList()); // check if collides foreach (Entity block in collidableCollection) { var blockTransform = block.FindComponent<Transform3D>(); var blockCollider = block.FindComponent<BoxCollider3D>(); // updates the block boundingbox to check collision this.tempBoundingBox.Max = blockTransform.Position + blockCollider.Size / 2; this.tempBoundingBox.Min = blockTransform.Position - blockCollider.Size / 2; // we use intersects of boundboxes cause collider class has not a Intersects with boundingboxes if (this.tempBoundingBox.Intersects(this.playerBehavior.PlayerBoundingBox)) { BlockTypeEnum blockType = BlockTypeEnum.EMPTY; Enum.TryParse<BlockTypeEnum>(block.Tag, out blockType); // if player colliders with the block, we must to check the block effect: switch (blockType) { case BlockTypeEnum.EMPTY: break; // ground and box obstacles can walk over they, but if crash horizontally player dies case BlockTypeEnum.GROUND: case BlockTypeEnum.BOX: if (this.playerBehavior.Collides(blockTransform)) { this.GameState = Enums.GameState.DIE; } break; case BlockTypeEnum.PYRAMID: // pyramid collision dies player this.GameState = Enums.GameState.DIE; break; case BlockTypeEnum.SPEEDERBLOCK: // if collide with speeder then player accelerates this.playerBehavior.Accelerate((float)gameTime.TotalSeconds); break; default: break; } } } } break; // player die state case GameState.DIE: // free every column entity and remove containers from entitymanager foreach (Entity column in this.ColumnCollection) { this.modelFactoryService.FreeColumn(column); } // clears the collection and colums this.ColumnCollection.Clear(); this.CurrentColumn = null; this.NextColumn = null; // just init GameState = GameState.INIT; break; } }