Debugger Console

Did you know that Otter has a debugger console built into it?  It's true.  If you press the ~ on your keyboard at any point during a DEBUG build of your game then you'll be able to access the console.  The debugger console can be useful for all sorts of things and has a bunch of built in commands that can be seen by typing "help" and pressing enter after opening it.

Here's an example of using some features of the debugger in a game:

using Otter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DebuggerConsole {
  class Program {
    static void Main(string[] args) {
      // Make a game!
      var game = new Game("Debugger Console Yeehaw");

      // Make a scene!
      var scene = new Scene();

      // Put a player and a hud into the scene.
      scene.Add(new Player(game.HalfWidth, game.HalfHeight));
      scene.Add(new Hud());

      // Log a message to the console.
      game.Debugger.Log("Log to the console!");

      // Enable messages using the BATTLE tag.
      game.Debugger.LogTag("BATTLE");
      // log a message using the BATTLE tag.
      game.Debugger.Log("BATTLE", "Log with a tag!");

      // Disable messages using the BATTLE tag.
      game.Debugger.LogTag("BATTLE");
      // This will not be logged.
      game.Debugger.Log("BATTLE", "This wont show up! :(");

      // The default key to use for summoning the debugger can be changed.
      // game.Debugger.ToggleKey = Key.Home;
      
      // Start the game!
      game.Start(scene);
    }

    // The method used by the debugger to set the screen color.
    [OtterCommand(helpText: "Change the color of the game.", group: "game")]
    static void GameColor(string color) {
      // Set the game's color to the color from the command.
      Game.Instance.Color = new Color(color);
    }

    // The method used by the debugger to set the player's position.
    [OtterCommand(helpText: "Change the position of the player.", group: "player")]
    static void PlayerPosition(float x, float y) {
      // Get the player from the current scene.
      var player = Scene.Instance.GetEntity<Player>();
      // Use the parsed arguments to set the position.
      player.SetPosition(x, y);
    }

    // The method used by the debugger to set the player's score.
    [OtterCommand(helpText: "Change the player's score.", group: "player")]
    static void PlayerScore(int score) {
      // Get the hud from the current scene.
      var hud = Scene.Instance.GetEntity<Hud>();
      // Set the score to the parsed int.
      hud.SetScore(score);
    }
  }

  class Player : Entity {

    // Use WASD for movement.
    Axis axisMovement = Axis.CreateWASD();

    public Player(float x, float y) : base(x, y) {
      // Just use a circle.
      AddGraphic(Image.CreateCircle(20));
      Graphic.CenterOrigin();

      // Add the axis.
      AddComponent(axisMovement);
    }

    public override void Update() {
      base.Update();
      // Use the axis for movement.
      AddPosition(axisMovement, 5);
    }
  }

  class Hud : Entity {
    // Text to use for the score.
    Text textScore = new Text("00000", 16);

    public Hud() {
      // Just show the score text.
      AddGraphic(textScore);
    }

    public void SetScore(int score) {
      // Set the text to show the score.
      textScore.String = score.ToString("00000");
    }
  }
}

Commands are registered with the debugger through the OtterCommand attribute.  Using the magic of reflection the debugger will figure out the rest.  There are fields on the OtterCommand that can be set to provide things like help text, usage text, alias, group, and a bool to set if the command should be buffered or instant.  Commands will default to instant, and buffered commands will be executed when the console is dismissed.

When entering commands into the console the parameters must match the parameters of the method that has been registered.  If you enter a method without any parameters, and the method requires parameters, you will be shown the usage text instead of invoking the method.  You can always use "help" to see all available commands, and enter a command with no parameters to see what parameters it needs.

Examples