void ICmpUpdatable.OnUpdate() { // If the object we're controlling has been destroyed, forget about it if (this.controlObj != null && this.controlObj.Disposed) this.controlObj = null; // See what player inputs there are to handle if (this.input == null) this.input = new InputMapping(); bool hasInputMethod = this.input.Method != InputMethod.Unknown; if (this.controlObj != null) { this.input.Update(this.controlObj.GameObj.Transform); } else { this.input.Update(null); } // Spawn the player object for the first time when input is detected if (this.controlObj != null && this.input.Method != InputMethod.Unknown && !hasInputMethod) { // Find an alive player or determine that no one has started playing yet bool gameAlreadyOver = false; Player alivePlayer = Player.AlivePlayers.FirstOrDefault(); if (alivePlayer != null) { // Move near already alive player Vector3 alivePlayerPos = alivePlayer.controlObj.GameObj.Transform.Pos; this.controlObj.GameObj.Transform.Pos = alivePlayerPos; } else if (Player.AllPlayers.Any(p => p != this && p.IsPlaying)) { // If we don't have an alive player, but do have playing players, the game must be already over. gameAlreadyOver = true; } else { // Move near initial spawn point this.controlObj.GameObj.Transform.Pos = SpawnPoint.SpawnPos; } // Spawn for the first time / enter the game if (!gameAlreadyOver) { this.controlObj.GameObj.Active = true; } } // Manage the object this player is supposed to control if (this.controlObj != null) { if (this.hasReachedGoal) { RigidBody body = this.controlObj.GameObj.GetComponent<RigidBody>(); SpriteRenderer sprite = this.controlObj.GameObj.GetComponent<SpriteRenderer>(); // If we've reached the goal, update the final animation and do nothing else float goalAnim = MathF.Clamp(((float)Time.GameTimer.TotalMilliseconds - this.goalReachTime) / 2000.0f, 0.0f, 1.0f); // Don't move body.LinearVelocity *= MathF.Pow(0.9f, Time.TimeMult); this.controlObj.TargetAngleRatio = 0.1f; this.controlObj.TargetThrust = Vector2.Zero; // Fade out if (sprite.CustomMaterial == null) sprite.CustomMaterial = new BatchInfo(sprite.SharedMaterial.Res); sprite.CustomMaterial.Technique = DrawTechnique.SharpAlpha; sprite.ColorTint = sprite.ColorTint.WithAlpha(1.0f - goalAnim); // Spawn a goal reached effect if (goalAnim > 0.2f && this.goalEffect != null && this.goalEffectInstance == null) { this.goalEffectInstance = this.goalEffect.Res.Instantiate(this.controlObj.GameObj.Transform.Pos); Scene.Current.AddObject(this.goalEffectInstance); } // Let the ship disappear if (goalAnim >= 1.0f) { this.controlObj.GameObj.Active = false; } } else if (this.controlObj.Active) { // Apply control inputs to the controlled object this.controlObj.TargetAngle = this.input.ControlLookAngle; this.controlObj.TargetAngleRatio = this.input.ControlLookSpeed; this.controlObj.TargetThrust = this.input.ControlMovement; if (this.input.ControlFireWeapon) this.controlObj.FireWeapon(); } else if (hasInputMethod && Player.IsAnyPlayerAlive && !this.hasReachedGoal) { // Respawn when possible this.respawnTime += Time.MsPFMult * Time.TimeMult; if (this.respawnTime > RespawnDelay) { // Move near alive player Player alivePlayer = Player.AlivePlayers.FirstOrDefault(); Vector3 alivePlayerPos = alivePlayer.controlObj.GameObj.Transform.Pos; this.controlObj.GameObj.Transform.Pos = alivePlayerPos; // Respawn this.respawnTime = 0.0f; this.controlObj.Revive(); } } } // Quit the game when requested if (this.input.ControlQuit) DualityApp.Terminate(); // If it's game over, allow to restart the game GameOverScreen gameOverScreen = Scene.Current.FindComponent<GameOverScreen>(); if (gameOverScreen != null && gameOverScreen.HasGameEnded) { if (this.input.ControlStart) Scene.Reload(); } }
void ICmpRenderer.Draw(IDrawDevice device) { // Create a buffer to cache and re-use vertices. Not required, but will boost performance. if (this.buffer == null) { this.buffer = new CanvasBuffer(); } // Create a Canvas to auto-generate vertices from high-level drawing commands. Canvas canvas = new Canvas(device, this.buffer); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, ColorRgba.White)); canvas.State.TextFont = this.font; // Retrieve players if (this.playerOne == null) { this.playerOne = Scene.Current.FindComponents <Player>().Where(p => p.Id == PlayerId.PlayerOne).FirstOrDefault(); } if (this.playerTwo == null) { this.playerTwo = Scene.Current.FindComponents <Player>().Where(p => p.Id == PlayerId.PlayerTwo).FirstOrDefault(); } // Is someone playing using mouse / keyboard? Display a mouse cursor then if (Player.AlivePlayers.Any(p => p.InputMethod == InputMethod.MouseAndKeyboard)) { canvas.FillCircle(DualityApp.Mouse.X, DualityApp.Mouse.Y, 2.0f); } // Is any player alive? Keep that value in mind, won't change here anyway. bool isAnyPlayerAlive = Player.IsAnyPlayerAlive; // Draw health and info of player one if (this.IsPlayerActive(this.playerOne)) { Ship playerShip = this.playerOne.ControlObject; if (playerShip.Active) { // Draw a health bar when alive float health = playerShip.Hitpoints; canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(12 - 1, device.TargetSize.Y - 10 - 198 - 1, 16 + 2, 196 + 2); canvas.State.ColorTint = this.playerOne.Color; canvas.DrawRect(10, device.TargetSize.Y - 10 - 200, 20, 200); canvas.FillRect(12, device.TargetSize.Y - 10 - health * 198.0f, 16, health * 196.0f); } else if (isAnyPlayerAlive && !this.playerOne.HasReachedGoal) { // Draw a respawn timer when dead float respawnPercentage = this.playerOne.RespawnTime / Player.RespawnDelay; string respawnText = string.Format("Respawn in {0:F1}", (Player.RespawnDelay - this.playerOne.RespawnTime) / 1000.0f); Vector2 textSize = canvas.MeasureText(string.Format("Respawn in {0:F1}", 0.0f)); canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(10 - 1, device.TargetSize.Y - 10 - textSize.Y - 2, textSize.X + 5, textSize.Y + 8); canvas.State.ColorTint = this.playerOne.Color; canvas.DrawText(respawnText, 10, device.TargetSize.Y - 10, 0.0f, Alignment.BottomLeft); canvas.FillRect(10, device.TargetSize.Y - 10 - textSize.Y, textSize.X * respawnPercentage, 3); canvas.FillRect(10, device.TargetSize.Y - 10, textSize.X * respawnPercentage, 3); } } // Draw health and info of player two if (this.IsPlayerActive(this.playerTwo)) { Ship playerShip = this.playerTwo.ControlObject; if (playerShip.Active) { // Draw a health bar when alive float health = playerShip.Hitpoints; canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(device.TargetSize.X - 12 - 16 - 1, device.TargetSize.Y - 10 - 198 - 1, 16 + 2, 196 + 2); canvas.State.ColorTint = this.playerTwo.Color; canvas.DrawRect(device.TargetSize.X - 10 - 20, device.TargetSize.Y - 10 - 200, 20, 200); canvas.FillRect(device.TargetSize.X - 12 - 16, device.TargetSize.Y - 10 - health * 198.0f, 16, health * 196.0f); } else if (isAnyPlayerAlive && !this.playerTwo.HasReachedGoal) { // Draw a respawn timer when dead float respawnPercentage = this.playerTwo.RespawnTime / Player.RespawnDelay; string respawnText = string.Format("{0:F1} to Respawn", (Player.RespawnDelay - this.playerTwo.RespawnTime) / 1000.0f); Vector2 textSize = canvas.MeasureText(string.Format("{0:F1} to Respawn", 0.0f)); canvas.State.ColorTint = ColorRgba.Black.WithAlpha(0.5f); canvas.FillRect(device.TargetSize.X - 10 - textSize.X - 3, device.TargetSize.Y - 10 - textSize.Y - 2, textSize.X + 2, textSize.Y + 10); canvas.State.ColorTint = this.playerTwo.Color; canvas.DrawText(respawnText, device.TargetSize.X - 10, device.TargetSize.Y - 10, 0.0f, Alignment.BottomRight); canvas.FillRect(device.TargetSize.X - 10 - textSize.X * respawnPercentage, device.TargetSize.Y - 10 - textSize.Y, textSize.X * respawnPercentage, 3); canvas.FillRect(device.TargetSize.X - 10 - textSize.X * respawnPercentage, device.TargetSize.Y - 10, textSize.X * respawnPercentage, 3); } } }