Shiny new animation features in Unity 5.0

June 26, 2014 in Company News and InfoTechnologyUnity Products and Services by 

The animation team has been working hard to pull together an impressive feature set for Unity 5.0. Here’s a quick overview of the new animation features you can look forward to!

State Machine Behaviours

In Unity 5, you’ll be able to add StateMachineBehaviour scripts to your states, and receive the following callbacks when the states are played:

  • OnStateEnter
  • OnStateUpdate
  • OnStateExit
  • OnStateMove
  • OnStateIK

You can have as many StateMachineBehaviours in your State as you like. So to add IK on State, or to do some custom logic, simply drag the StateMachineBehaviour script on to it.

Basically, anything that requires some kind of StateMachine logic in your game – with or without animation – can use this.

mecUnity5-1
Another great thing about this feature is that you don’t need to have tons of

if(animator.GetCurrentAnimatorStateInfo(0).isName("Idle") )
    DoStuff()

(which I’m sure you have plenty of in your code),

you can just use StateMachineBehaviours instead!

State Machine Transitions

State Machines are growing more and more complex, so we introduced the concept of State Machine Transitions to provide a higher level of abstraction over the StateMachine logic.

In Unity 5, we’ve added Entry and Exit nodes to StateMachines. There are used during State Machine Transitions.

Entry:  When you transition to a StateMachine, the animation system will evaluate the Entry node and branch to the destination that its conditions meet.

Exit: When going to the Exit node, the animation system will look at the outgoing StateMachine transitions and branch to the proper destination.

Note that you can mix transitions: State->State, State->StateMachine, StateMachine->StateMachine…

mecUnity5-2

What’s more, we also revamped the UI for our tool so you can now re-order your parameters and layers.

Asset Creation API

In Unity 5 you can create animation assets; StateMachines, States, Controllers, Layers, Blentrees, etc., using scripts in the Editor!

There are two APIs, a high-level one, where the assets are managed by Unity and a low level one where you manage assets manually, and can perform external referencing.

Both APIs are documented, and I’ve put a small example of API usage at the end of this post.

Direct Blend Trees

We’ve added a new type of BlendTree that allows you to map an animator parameter to the weight of a BlendTree child directly.

mecUnity5-3

This can come in really handy if you’re working with BlendShape animations, or additive animations.

Root Motion Authoring (in generic mode)
Unity 5 also allows you to animate objects and convert their animator to root motion (ie Delta Animation). Simply create an animation – translation/rotation – on the topmost transform of an object then click Generate Root Motion Curve in the AnimationClip inspector!

More stuff that will make your life easier:

  • Improved animation previewer camera. The camera can now Pan, Orbit and Scale in the same way as the scene viewer.
  • Runtime access to parameters (name, default values etc..)
  • Gizmo in scene view for root position, ik position, etc…
  • Improved retargeting engine
  • Runtime optimizations
  • Tons and tons of bug fixes

Let us know what you think of these changes!

The Animation Team.

More about Unity 5.

 

Asset Creation API sample Code 

// Creates the controller
var controller = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath ("Assets/Mecanim/StateMachineTransitions.controller");

// Add parameters
controller.AddParameter(“TransitionNow”, UnityEditor.Animations.AnimatorControllerParameterType.Trigger);
controller.AddParameter(“Reset”, UnityEditor.Animations.AnimatorControllerParameterType.Trigger);
controller.AddParameter(“GotoB1″, UnityEditor.Animations.AnimatorControllerParameterType.Trigger);
controller.AddParameter(“GotoC”, UnityEditor.Animations.AnimatorControllerParameterType.Trigger);

// Add StateMachines
var rootStateMachine = controller.layers[0].stateMachine;
var stateMachineA = rootStateMachine.AddStateMachine(“smA”);
var stateMachineB = rootStateMachine.AddStateMachine(“smB”);
var stateMachineC = stateMachineB.AddStateMachine(“smC”);

// Add States
var stateA1 = stateMachineA.AddState(“stateA1″);
var stateB1 = stateMachineB.AddState(“stateB1″);
var stateB2 = stateMachineB.AddState(“stateB2″);
stateMachineC.AddState(“stateC1″);
var stateC2 = stateMachineC.AddState(“stateC2″); // don’t add an entry transition, should entry to state by default

// Add Transitions
var exitTransition = stateA1.AddExitTransition();
exitTransition.AddCondition(UnityEditor.Animations.AnimatorConditionMode.If, 0, “TransitionNow”);
exitTransition.duration = 0;

var resetTransition = stateMachineA.AddAnyStateTransition(stateA1);
resetTransition.AddCondition(UnityEditor.Animations.AnimatorConditionMode.If, 0, “Reset”);
resetTransition.duration = 0;

var transitionB1 = stateMachineB.AddEntryTransition(stateB1);
transitionB1.AddCondition(UnityEditor.Animations.AnimatorConditionMode.If, 0, “GotoB1″);
stateMachineB.AddEntryTransition(stateB2);
stateMachineC.defaultState = stateC2;
var exitTransitionC2 = stateC2.AddExitTransition();
exitTransitionC2.AddCondition(UnityEditor.Animations.AnimatorConditionMode.If, 0, “TransitionNow”);
exitTransitionC2.duration = 0;

var stateMachineTransition = rootStateMachine.AddStateMachineTransition(stateMachineA, stateMachineC);
stateMachineTransition.AddCondition(UnityEditor.Animations.AnimatorConditionMode.If, 0, “GotoC”);
rootStateMachine.AddStateMachineTransition(stateMachineA, stateMachineB);

 

Anúncios

Writing a Simple Role Playing Game with C# .NET and the State Design Pattern

Introduction

The State Pattern is an interesting design pattern in that it allows us to separate out portions of code into individual related modules, or states. This pattern is particularly useful for applications which need to retain state information, such as the current phase a program is in. While you can typically maintain this information using a basic integer variable, the State pattern helps abstract the specific state logic, reduces code complexity, and greatly increases code readability. This can make the difference between an application maintenance nightmare and a work of art.

This article describes how to use the State Pattern with C# to create a simple, console-based RPG role playing game. You’ll be able to see exactly how the State pattern fits into the flow of the rpg game and how it easily cleans up the code, in what might typically be a confusion of integer values and if-then statements.

 
C# .NET State Pattern RPG Role Playing Game

If Then Else What?

The core problem that the State pattern solves is reducing the complexity of if-then statements, which we ultimately need when managing state information. Since we’re going to be creating a role playing game, knowing if the character is in an exploratory or battle state is important.

For our simple role playing game, we’ll consider 2 states that our character may be in and 2 commands that he can perform. He can be Exploring or he can be in Battle and he can choose to Look Around or to Attack. Since we have 2 states and 2 command possibilities, we’ll naturally have 4 situations to check for. They are:

State: Exploring
Look
Attack

State: Battle
Look
Attack

Without design patterns, you might normally design a role playing game similar to the following:

void Main()
{
   int state = 0;
   string command = “”;

   while (command != “Quit”)
   {
      if (command == “Look” && state == 0)
      {
         // Explore the dungeon.
         DoExploreDungeon();
      }
      else if (command == “Attack” && state == 0)
      {
         // There’s nothing to attack when you’re just exploring!
         DoNothingToAttack();
      }
      else if (command == “Look” && state == 1)
      {
         // You can’t explore when a monster is attacking you!
         DoMonsterFreeHit();
      }
      else if (command == “Attack” && state == 1)
      {
         // Attack the monster.
         DoAttackEvilMonster();
      }
   }
}

You would then define the function for each situation listed above. While this would certainly work and might not look like much code, think about what would happen if you added another command, such as “Inventory”. You would have to add an additional two if-then statements. If you wanted to add another state, such as “InStore”, you would need to create even more if-then statements. You can see how the above code could end up becoming complex and more difficult to maintain. This is where the State Pattern comes in!

Cleaning House with the State Pattern

Let’s clean up the above code by implementing the State Pattern. Since we have two possible states, we’ll have two state classes which manage the details of each state, but the main loop will be reduced to the following:

void Main()
{
   RPGController rpg = new RPGController();
   string command = “”;

   while (command != “Quit”)
   {
      if (command == “Look”)
      {
         rpg.Explore();
      }
      else if (command == “Attack”)
      {
         rpg.Battle();
      }
   }
}

In the above C# code, using the State Pattern, we’ve already cut in half the number of if-then statements. In fact, we only need to check which command the user selected and pass call the proper function for that command. The State Pattern itself takes care of determining which specific state should act upon the command. As you can see, this greatly reduces the amount of code complexity. Let’s take a look at how we put the State Pattern together.

There’s Always an Interface

We start by constructing an interface for the State Pattern controller to use. All states will implement this interface so that they have the same list of functions which the controller class can call. Depending on which state is currently active, the controller will execute one of the interface functions. The functions in the interface can be considered the possible commands the user can choose. The concrete states we construct from this interface can be considered the possible states the character may be in.

As you can tell, we’ll need to define the function bodies for each possible function in the state interface. In the case of impossible states, such as being in the Battle state and trying to Explore, we can either throw an exception and leave the function empty, or display an entertaining message to the user. In either case, the state pattern still helps us manage the complexity.

Since we only have two commands, our interface for the State Pattern is defined as follows:

    public interface IState
    {
        int Explore();
        int Battle(int level);
    }

Exploring the State of the Explore State

We have two states to create implementations for: Explore and Battle. We’ll start with the Explore state. This will also be the initial state that the character will reside in. Since the character can select two commands (Look and Attack), and since we defined two functions in the interface (Explore and Battle), we can fill in the body for the user commands as follows:

    public class ExploreState : IState
    {
        private RPGController context;

        public ExploreState(RPGController context)
        {
            this.context = context;
        }

        #region IState Members

        public int Explore()
        {
            Console.WriteLine(“You look around for something to kill.”);

            int ran = RandomGenerator.GetRandomNumber(5);
            if (ran == 0)
            {
                Console.WriteLine(“A monster approaches! Prepare for battle!”);
                context.SetState(context.GetBattleState());
            }
            else if (ran == 1)
            {
                Console.WriteLine(“You find a golden jewel behind a tree!”);
                return 2;
            }

            return 0;
        }

        public int Battle(int level)
        {
            Console.WriteLine(“You find nothing to attack.”);
            return 0;
        }

        #endregion
    }

First, notice that the state implements IState. This means it has an Explore and Battle function, which are the two commands the user can do. When in the Explore state, upon exploring we’ll let the user either find a magical item which increases his experience, or he’ll find a monster that he must kill. For the code, we simply pick a random number, and depending on the value, let the user know he found a monster or magical item. If he found a monster, the user’s state will be changed to the Battle state. This allows us to call the same interface functions (Explore and Battle) but from a new state, the Battle state. On the other hand, if he found a magical item, his state remains in the Explore state. Notice that we also define the Battle function even though this is within the Explore state. Since the user can’t attack a tree, we’ll simply tell him there is nothing to attack. You could also throw an exception in the Battle() function if you wish, as long as the user interface prevents the user from choosing the Attack command while in the Explore state. In our case, the commands never change for the user, so we’ll define the bodies for all functions. At this point, you could easily draw a simple state diagram, that illustrates our game, but we’ll move on with the code.

Battling the Battle State

Just as we did with the Explore state, the Battle state will define the same two interface functions Explore and Battle. The difference is that since we’re now in a battle state, executing the Explore command should throw an exception (or display a message), and the Battle command will actually perform an attack. We define this state as follows:

    public class BattleState : IState
    {
        private RPGController context;
        private int rounds = 0;

        public BattleState(RPGController context)
        {
            this.context = context;
        }

        #region IState Members

        public int Explore()
        {
            Console.WriteLine(“You’d love to, but see, there’s this big ugly monster in front of you!”);
            return 0;
        }

        public int Battle(int level)
        {
            Console.Write(“You try to slay the monster.. “);
            
            rounds++;

            System.Threading.Thread.Sleep(1000);

            int maxRan = 10 – level;
            if (maxRan < 1)
            {
                maxRan = 1;
            }

            int ran = RandomGenerator.GetRandomNumber(maxRan);
            if (ran == 0)
            {
                Console.WriteLine(“he’s dead!”);
                context.SetState(context.GetExploreState());
                
                int tempRounds = rounds;
                rounds = 0;

                return tempRounds;
            }
            else
            {
                Console.WriteLine(“but fail.”);
            }

            if (rounds >= 9)
            {
                Console.WriteLine(“You panic and run away in fear.”);
                context.SetState(context.GetExploreState());

                rounds = 0;
            }

            return 0;
        }

        #endregion
    }

The beauty of the State Pattern is in how easy it is to add new states and commands to our application. Since the class implements the same interface (ie. the same commands), we can easily define this new Battle state. The only interesting part to this class is the contents of the Battle function, which simply picks a random number to tell if the user killed the monster. For each round the user fails to kill the monster (in one blow), the user loses potential experience. The faster a monster is killed, the more experience he gains.

It’s also important to note that in the Battle function we include a transition back to the Explore state (just as we did in the Explore state’s Explore() function if the user found a monster). Notice that we include a reference to the State controller’s context. This is just a pointer to the state controller, as the controller will ultimately handle which state we’re in and calling the desired functions. Let’s move on to describing how the controller works.

The Master Pattern Controller

As you noticed in the state definitions above, we have a reference to a “context” variable, which points to the state controller. The controller manages the current state and maipulates the state. Our main program will actually call the controller, not the individual states.

The controller can be defined as follows:

    public class RPGController
    {
        private IState exploreState;
        private IState battleState;
        private IState state;
        private int level = 1;

        public RPGController()
        {
            exploreState = new ExploreState(this);
            battleState = new BattleState(this);

            state = exploreState;
        }

        public int Explore()
        {
            return state.Explore();
        }

        public int Battle()
        {
            return state.Battle(level);
        }

        public void SetState(IState state)
        {
            this.state = state;
        }

        public void SetLevel(int level)
        {
            this.level = level;
        }

        public int GetLevel()
        {
            return level;
        }

        public IState GetExploreState()
        {
            return exploreState;
        }

        public IState GetBattleState()
        {
            return battleState;
        }
    }

The first point to note is that we define an instance of each state within the controller. We define exploreState and battleState. We instantiate these variables to their designated concrete state (Explore and Battle). We also define a state pointer, which holds our current state. This is similar to defining the integer variable in the original example above.

Next, we define functions for each command that the user can select (or just copy the functions we used in the interface which coorespond to the same thing): Explore and Battle. For the body to these functions, we simply execute the current state’s method for that command. So for Explore(), we simply call state.Explore() and for Battle, we simply call state.Battle(). Remember, state is our current state and will point to either exploreState or battleState. Regardless of which concrete state it points to, the functions it can call are the same.

We also define a few helper functions, such as the SetState() function, which lets us change our active state, and the GetExploreState() and GetBattleState() functions, which return a concrete instance of the particular state. These are used during the state transitions when we reference the “context” variable to change states.

Putting it All Together, I Think We’ve Got a Game

You might be surprised at this point to realize we pretty much have a fully functional state-aware game. The state pattern hides and abstracts much of the complexity that we normally have to manage in the main code. Since the states are tucked away in individual modules managed by the controller, we only have to use the controller to handle our game states. We can define the main program loop as follows:

    class Program
    {
        static RPGController rpg = new RPGController();
        static int score = 0;
        static int nextLevel = 10;

        static void Main(string[] args)
        {
            ConsoleKeyInfo key;

            Console.WriteLine(“-=-=- Simple Battle Adventure v1.0 -=-=-“);

            do
            {
                Console.WriteLine();
                Console.WriteLine(“L = Look Around, A = Attack, Q = Quit”);
                Console.Write(“Score [” + score + “] Level [” + rpg.GetLevel() + “] Action [L,A,Q]: “);

                key = Console.ReadKey();

                Console.WriteLine();

                DoAction(key.Key);
            }
            while (key.Key != ConsoleKey.Q && rpg.GetLevel() < 10);

            if (rpg.GetLevel() >= 10)
            {
                Console.WriteLine();
                Console.WriteLine(“You WIN! Final score [” + score + “]”);
            }

            Console.ReadKey();
        }

        static void DoAction(ConsoleKey key)
        {
            if (key == ConsoleKey.L)
            {
                int points = rpg.Explore();
                if (points > 0)
                {
                    Console.WriteLine(“You gain ” + points + ” heroic points!”);
                    score += points;
                }
            }
            else if (key == ConsoleKey.A)
            {
                int rounds = rpg.Battle();
                if (rounds > 0)
                {
                    int points = 10 – rounds;
                    if (points < 0)
                    {
                        points = 0;
                    }

                    score += points;

                    Console.WriteLine(“You gain ” + points + ” heroic points!”);
                }
            }

            if (score >= nextLevel)
            {
                rpg.SetLevel(rpg.GetLevel() + 1);
                nextLevel = rpg.GetLevel() * 10;

                Console.WriteLine(“Your wonderous experience has gained you a level! Level ” + rpg.GetLevel());
            }
        }
    }

The first thing we do is include a variable for the RPG controller. This is our key to using the state pattern controller. Next, we display a basic menu to the user and allow him to select a command on the keyboard. Our state pattern comes into play when we process the command in the DoAction() function. Depending on the command selected, we call the controller’s designated function for that command (Explore or Battle). The controller (and its concrete states) handle the actual details about what to do based upon the user’s input. So, when the user chooses to Look, we just tell the controller to execute a Look and it tells the current state to execute a “Look”.

There is one additional utility class left out from the above code, which manages selecting random numbers. This class is defined as follows:

    public static class RandomGenerator
    {
        private static Random random = new Random();

        public static int GetRandomNumber(int maxValue)
        {
            return random.Next(maxValue);
        }
    }

Output

If you’d like to try the game yourself, you can download a copy of the compiled game by clicking here. Of course, you’ll need to have the .NET framework on your PC. Once you put together the above code and run the program, the output of our rpg game using the State Pattern, will look like the following:

-=-=- Simple Battle Adventure v1.0 -=-=-

L = Look Around, A = Attack, Q = Quit
Score [0] Level [1] Action [L,A,Q]: L
You look around for something to kill.
You find a golden jewel behind a tree!
You gain 2 heroic points!

L = Look Around, A = Attack, Q = Quit
Score [2] Level [1] Action [L,A,Q]: L
You look around for something to kill.
A monster approaches! Prepare for battle!

L = Look Around, A = Attack, Q = Quit
Score [2] Level [1] Action [L,A,Q]: A
You try to slay the monster.. but fail.

L = Look Around, A = Attack, Q = Quit
Score [2] Level [1] Action [L,A,Q]: A
You try to slay the monster.. but fail.

L = Look Around, A = Attack, Q = Quit
Score [2] Level [1] Action [L,A,Q]: A
You try to slay the monster.. he’s dead!
You gain 5 heroic points!

L = Look Around, A = Attack, Q = Quit
Score [7] Level [1] Action [L,A,Q]: A
You find nothing to attack.

L = Look Around, A = Attack, Q = Quit
Score [7] Level [1] Action [L,A,Q]: L
You look around for something to kill.
You find a golden jewel behind a tree!
You gain 2 heroic points!

L = Look Around, A = Attack, Q = Quit
Score [9] Level [1] Action [L,A,Q]: L
You look around for something to kill.

L = Look Around, A = Attack, Q = Quit
Score [9] Level [1] Action [L,A,Q]: L
You look around for something to kill.
A monster approaches! Prepare for battle!

In the above output, you can guess which state the user was in when he performed each command and which action was called. For example, after slaying the monster, the user was returned to the Explore state, but selected the Attack command anyway. The response was “You find nothing to attack”, indicating the state transitioned from Battle to Explore successfully.

 

Conclusion

Managing state in an application typically requires utilizing an integer index variable with a series of if-then or case statements, which can often add to code complexity and maintenance issues. The State Pattern in C# helps us organize our states into individual modules with a single controller and helps us abstract away the details behind the state implementation. This allows us to reduce code complexity, increase readability, and ultimately reduce maintenance in the future. The State Pattern is an easy addition to your design patterns toolkit and can be used in any stateful object oriented application.

 

About the Author

This article was written by , founder and chief developer of Primary Objects, a software and web application development company. You can contact Primary Objects regarding your software development needs athttp://www.primaryobjects.com

Reinventing myself after attending #CSharpConf14

Code Wala

C# Corner hosted the C# Corner Annual Conference (#CSharpConf14) during 11-13th April at Noida. I privileged to get a chance to attend the event as an attendee and as a Speaker. The event was a huge success where around 850+ people joined from various cities across India. Everybody got a chance to learn from some of the most popular speakers from India and abroad.

This year speakers list was full of legends like Pinal Dave , Mahesh Chand , Prabhjot Singh Bakshi, Gaurav Mantri, Chris Eargle, Jason beres.There was 18 sessions delivered by around 10 speakers and I feel honored to be one of them. This list cannot be complete without taking a name DJ who worked tirelessly for months to make the event grand and successful.

For me, 11-13 April was few of the best days of life where I enjoyed every moment and got a…

Ver o post original 648 mais palavras

Understanding C#: Use System.Console to build text-mode games

I’m a sucker for an old-school text-mode console game. Text-mode games rendered their “graphics” by drawing text characters at different positions on the screen using 16 background and foreground colors. They’re also easier than ever to build in C# and .NET, thanks to theSystem.Console class, which lets you position the cursor, do animation by moving blocks of the buffer, use colors and special characters, and handle input from the user. In this tutorial post, I’ll walk you through all of the tools you need to create a retro MS-DOS style text-mode video game, including a complete game that you can build yourself.

One thing I learned while I was writing on Head First C# is that building video games is a great way to improve your C# skills. (I wrote that post on Building Better Software just after the first edition went to press.) I put a lot of effort into helping people learn C#, and I often get the question, “What should I build to get practice?” The reason games make great projects for learning and experimenting because you start out with a good idea of what you’re going to be building. So one goal of this post is to give you a new—and fun, I hope!—way to get some great practice honing your C# skills.

Head First C# CoverContents: What you need to build a text-mode game in C#

This post is structured like a tutorial, with a bunch of examples that should give you all of the pieces you need to create a great text-mode game. Here’s what I’ll cover:

A little history

There are a lot of .NET developers who, when they built console applications at all, have only ever used Console.ReadLine() and Console.WriteLine(). The System.Console class does so much more than just read and write text. It gives you enough control over the console window to build a complete text-mode game.

If you grew up in a world that always included a mouse—if you’ve never used a computer that only displayed text and not graphics—then take a minute and have a look at Snipes. It’s one of the classic text-mode games from the 80s. You can download it from textmodegames.com—it runs just fine under DOSBox, and it’s actually worth taking a minute to play if you haven’t before. Here’s a screenshot:

Snipes_-_Text_mode_game_by_Novell_-_screen_grab_Apr05.gif
Snipes screenshot courtesy of the Snipes entry on Wikipedia
I may be showing my age, but I think I love text-mode games because I grew up playing them.As a kid, I grew up playing Star Trek and Adventure on a VAX 11/780, which I dialed into using my parents’ VT-180 Robin. (We eventually replaced it with a Rainbow 100, and at some point there was a Tektronix 4052, along with a couple of TRS-80s – a Model 100 and aCoCo2…) Finally, sometime in the mid-80s, we made it to the world of IBM PC clones. The family PC was an AT&T PC-6300 with a massive 20 megabyte hard drive that I did my best to fill up with games. And while games were increasingly taking advantage of those great 320×200 16-color CGA graphics, there were plenty of them that used text mode graphics.

There’s one thing I need to bring up before we dig into the programming. Every variant of windows, going back at least to Windows 3.1, has a command prompt. Some people (like me) use it all the time, but I’ve worked with many really good developers who rarely use it at all. So just to make sure we’re all on the same page, open the command prompt now. It lives in Start >> All Programs >> Accessories. When you run a text-mode game, you’ll see it in that window. If you’ve only ever built Windows Forms applications in Visual Studio, this will be new—you’ll be building console applications, and they’ll run in a command prompt.

Positioning text

The first step in making a text mode game is drawing text anywhere you want on the screen. To do this, you’ll move the cursor to a coordinate that’s measured in columns from the left side of the screen and rows from the top of the screen using a few useful methods and properties from the Console class:

Those two properties are useful when you want to save the current location, write some text somewhere else on the screen, and then jump back to that location. Just save the values of the CursorLeft and CursorTop properties, draw what you need to draw, and then set them back (or use SetCursorPosition(), which does the same thing as setting those properties) to reset the position.

Here’s a simple program that does exactly that. Normally, I’d ask you to create a new Console Application in Visual Studio and paste some code into its Main() method. But since we’re talking about console applications, I think it’s useful to actually create one from the ground up outside of Visual Studio, because it really reinforces just how basic and fundamental console applications are. Here’s what to do:

First, open up Notepad and paste the following code into it:

PositionText.cs:

using System;

class PositionText
{
     static void Main(string[] args)
     {
          Console.WriteLine("It's time to enter some text.");
          Console.Write("Enter it here: ");
          string text = Console.ReadLine();
          int left = Console.CursorLeft;
          int top = Console.CursorTop;
          Console.SetCursorPosition(15, 20);
          Console.Write("You entered -> {0} <-", text);
          Console.SetCursorPosition(left, top);
          Console.WriteLine("Continuing where I left off.");
      }
}

Compiling and running a C# program from the command prompt

Save the file as PositionText.cs (I put it in the C:\temp\ folder). Next, open a command prompt, go to the folder where you saved the program, and run the following command:

%SYSTEMROOT%\Microsoft.NET\Framework\v3.5\csc.exe PositionText.cs

(You might notice that I’m using .NET Framework v3.5 to compile these programs. That’s because the basic the System.Console class has remained stable, and really hasn’t changed over the last few versions of the .NET Framework. But all of this code will work just fine in .NET 4.0 and Visual Studio 2010.)

Running CSC should create PositionText.exe. Now you can run it. Here’s what it should look like when it runs:

Screenshot - PositionText.pngNotice how the program draws the text near the bottom of the window, then continues writing lines as usual. That’s all the cursor positioning you need for a text-mode game.

Colors

Life is dull in monochrome, even for colorblind people like me. I may see the wrong colors, but I still see them! And if you’re like me and you have trouble seeing colors, you’ll love text mode—there are only 16 colors that you need to keep track of. You can do it with these System.Console members:

  • The ForegroundColor property sets the color of the letters
  • The BackgroundColor property sets the color of the background behind the letters
  • Both of those properties use the ConsoleColor enum,
  • The ResetColor() method resets the foreground and background colors

Go to your PositionText.cs program and replace this line:

Console.Write("You entered -> {0} <-", text);

with the following code:

        Console.ForegroundColor = ConsoleColor.DarkBlue;
        Console.BackgroundColor = ConsoleColor.Yellow;
        Console.Write("You entered -> ");
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.BackgroundColor = ConsoleColor.DarkGray;
        Console.Write(text);
        Console.ForegroundColor = ConsoleColor.Magenta;
        Console.BackgroundColor = ConsoleColor.Cyan;
        Console.Write(" <- ");
        Console.ResetColor();

Now when you run your program, the text it prints near the bottom of the screen should be colorful. (If you want, you can also add code to set the background color of the console using theConsole.BackgroundColor property.)

Screenshot - PositionText in color.pngThere’s one more thing to try with your program. Fill up your command window by runningdir %SYSTEMROOT%. Then run PositionText.exe again. Hey, wait a minute – where’s the text? It should really stand out with those colors, but it doesn’t seem to be anywhere.

Scroll up to the top of the buffer. The missing text should be up there at the top. If you run PositionText.exe a few times, you’ll see it overwrite the same line over and over again. The reason is that when you set the cursor position, you’re setting it relative to the buffer. In a minute, I’ll show you how to change the size of the buffer and the size of the window.

Animation and Sound

Setting the cursor position and changing the text color is definitely enough for simple text and even basic animation. But if you want to do some more advanced animation, though, you’ll need a few more tools:

  • The Console.MoveBufferArea() method moves a rectangular area of the console, leaving an empty space where the moved text was
  • It’s got an overload that takes three extra parameters to let you leave a rectangle filled with characters (with a foreground and background color) instead of an empty space

Here’s another quick program called HappyFaces that draws a simple animation using both overloads of the MoveBufferArea() method. You can compile and run HappyFaces.cs it just like you did with PositionText.cs.

HappyFaces.cs:

using System;
 
class HappyFaces
{
     static void Main(string[] args)
     {
          Console.Clear();
          Console.SetCursorPosition(0, 0);
          Console.ForegroundColor = ConsoleColor.Magenta;
          Console.WriteLine("o o        . .");
          Console.WriteLine(" )          ) ");
          Console.WriteLine("___        ###");
          for (int i = 0; i < 20; i++)
          {
               Console.MoveBufferArea(i + 11, i, 3, 3, i + 12, i + 1,
                   'x', ConsoleColor.Red, ConsoleColor.White);
               Console.MoveBufferArea(i, i, 3, 3, i + 1, i + 1);
               Console.Beep((i+10)*100, 100);
           }
          Console.SetCursorPosition(0, 23);
          Console.ResetColor();
      }
}

Did you notice the great—let’s face it, awesome—sound? That’s thanks to the Console.Beep()method, which emits a beep at a certain frequency for a certain number of milliseconds. I’m using it here to slow down the animation. If you call Beep() without arguments, it emits the standard system beep. And depending on your machine, it might send the beep out of the speaker inside your computer case instead of your speakers!

Special characters

Take another look at the screenshot from Snipes. Notice how there are lines, circles, triangles, boxes, and smiley faces? Those aren’t letters or numbers! What gives?

Here’s an experiment you can run. If you open up a command prompt, open up the Windows menu by clicking on the “C:\” icon in the upper right-hand corner, and choose “Properties” from the menu, you’ll see that the command prompt typically uses the Lucida Console font. Open up Character Map (Start >> Run >> charmap.exe) and choose Lucida Console from the Font dropdown. Scroll down to the Greek letters and double-click on one of them (say, Theta: Θ) so it shows up in the “Characters to copy” box. Then scroll down to the Cyrillic letters and double-click on one of them (Zhe: Ж). Click the “Copy” button to copy them into the buffer. Now go back to the command prompt window, open the Windows menu again, and choose “Edit >> Paste”. Notice what happens:

Screenshot - Theta question mark.pngNotice how the theta is pasted in just fine, but the zhe ends up being pasted as a question mark? That’s because the MS-DOS console—and all of its descendant Windows consoles—can only display 250 characters. They were originally ASCII characters, 255 characters including 250 visible ones, plus six non-printing ones: beep, tab, null, backspace, line feed, and carriage return. Now they’re represented by Unicode code page 437. If you’re one of our Head First C# readers, then you learned chapter 9 about how Unicode works in chapter 9. But if not, don’t worry—all you need to know is that you can convert a byte value (from 0 to 255) to its associated MS-DOS ASCII character:

// Convert an array of bytes to an array of MS-DOS characters
char[] charArray = Encoding.GetEncoding(437).GetChars(byteArray);

Here’s a program that prints out an MS-DOS ASCII table, which is something that used to be printed on the inside cover of most programming books back in the ’80s and early ’90s. Luckily, you can just copy and paste characters right out of the command window. (Try turning on QuickEdit mode in the command window’s Properties menu—that lets you select and copy by clicking and dragging, and you can paste by right-clicking.)

CodePage437.cs

using System;
using System.Text;

class CodePage437
{
     public static void Main(string[] args)
     {
          // Set the window size and title
          Console.Title = "Code Page 437: MS-DOS ASCII Characters";
      
          for (byte b = 0; b < byte.MaxValue; b++)
          {
               char c = Encoding.GetEncoding(437).GetChars(new byte[] {b})[0];
               switch (b)
               {
                    case 8: // Backspace
                    case 9: // Tab
                    case 10: // Line feed
                    case 13: // Carriage return
                        c = '.';
                        break;
                }
       
               Console.Write("{0:000} {1}   ", b, c);
       
               // 7 is a beep -- Console.Beep() also works
               if (b == 7) Console.Write("");
       
               if ((b + 1) % 8 == 0)
                   Console.WriteLine();
           }
          Console.WriteLine();
      }
}

You can see the screenshot in the next section. Pay special attention to characters 176, 177, and 178. They’re especially useful for drawing text-mode graphics, especially when you combine them with different background and foreground colors. You can achieve some really intricate dithering effects. You can see an example of dithering using these characters if you look closely at the screenshot on the TheDraw Wiki page The half-block characters (219 through 223) are also useful, especially when you combine foreground and background colors. They make it possible to do intricate shadowing, piping, and checkerboard patterns.

There’s one other thing you need to know about these characters. If you read chapter 9 of Head First C#, then you know that you can paste Unicode characters into Visual Studio and it knows how to handle them—it even knows that Hebrew or Arabic characters work right to left. If you paste line characters (179 through 218) into Visual Studio, they look correct. But if you paste them into Notepad, something really neat happens: Notepad knows how to convert the line characters to +, – and |. Be careful with this if you’re pasting the WordFinder code at the bottom of this post into Notepad. It will still look okay, but you won’t get the line characters.

You’ll be amazed at how intricate text-mode graphics can get. When I was doing text-mode animation, I used to get a lot of use out of the shaded block characters which, when combined with colors, let me do some pretty intricate dithering. Do yourself a favor—have a look at some screenshots from The Amazing Adventures of ANSI Dude. You can download the gamehere, and it runs fine in DOSBox.

Scrolling the Window Contents

It’s a little prettier if you resize the window so that it’s just slightly larger than the contents. You can do that by calling SetWindowSize() and setting the BufferWidth and BufferHeightproperties. Add this code to the top of the Main() method in CodePage437.cs:

        // Get rid of the scroll bars by making the buffer the same size as the window
        Console.Clear();
        Console.SetWindowSize(65, 33);
        Console.BufferWidth = 65;
        Console.BufferHeight = 33;

Here’s what your program should look like when it runs. Notice how it says Press any key to continue . . . at the bottom? That’s because I ran it from inside Visual Studio 2010. Normally, when you run a console application from inside Visual Studio, it disappears when it’s done. But if you run it outside the debugger by pressing Ctrl-F5, it displays that prompt. But it also disables the debugger!

Screenshot - Code page 437.pngYou’ll need to be a little careful with those buffer properties, because if you resize the window so it’s larger than the buffer, your code will throw an exception. The reason is because the window always needs to be smaller than the buffer—that way it can scroll around. Plenty of text-mode games scroll around a maze or a battlefield. You can use the WindowLeft and WindowTopproperties to do it. Add this code to the bottom of CodePage437.cs to see how scrolling works:

        // Make the window much smaller than the buffer and scroll around
        Console.SetWindowSize(20, 5);
        for (int left = 5; left < 25; left++)
        {
             Console.WindowLeft = left;
             System.Threading.Thread.Sleep(100);
         }
        for (int top = 5; top < 20; top++)
        {
             Console.WindowTop = top;
             System.Threading.Thread.Sleep(100);
         }
        Console.SetWindowSize(65, 33);

(One side note about these characters. It’s possible to change the output encoding using theConsole.OutputEncoding property: Console.OutputEncoding = new System.Text.UTF8Encoding();. But an old-school text-mode game will stick to the original MS-DOS ASCII characters.)

The Main Loop

There’s one more thing you need to think about when you’re building a text-mode game that runs in a console window: the main loop. Games typically have a main loop that keeps running until the game is over. Here’s a useful pattern that you can use:

  • Use the Console.CursorVisible to make your cursor invisible—that way, you avoid annoying flickering
  • The Console.CancelKeyPress event is raised whenever the user hits ^C—unless you set the Console.TreatControlCAInput property to true
  • See the comments in the code below for a little more information on how to handle the CancelKeyPress event
  • Call System.Threading.Thread.Sleep() in the main loop to add a small delay, and also to make your game CPU cycle friendly
  • The Console.KeyAvailable property is true if there’s a key waiting to be processed. If there is, you can read it using the Console.ReadKey() method.
  • Look in the code below for the comments that show you where to initialize the game and where to handle user input and update the screen
/// <summary>
/// Set this static field to true to quit the game
/// </summary>
static bool quit = false;

/// <summary>
/// The entry point sets up the screen, initializes the game, and kicks off the main loop
/// </summary>
static void Main(string[] args)
{
     // Make sure the game quits if the user hits ^C
     // Set Console.TreatControlCAsInput to true if you want to use ^C as a valid input value
     Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
 
     Console.CursorVisible = false;
             
     /*** Initialize the game here! ***/
 
     MainLoop();
}

/// <summary>
/// Event handler for ^C key press
/// </summary>
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
     // Unfortunately, due to a bug in .NET Framework v4.0.30319 you can't debug this 
     // because Visual Studio 2010 gives a "No Source Available" error. 
     // http://connect.microsoft.com/VisualStudio/feedback/details/524889/debugging-c-console-application-that-handles-console-cancelkeypress-is-broken-in-net-4-0
     Console.WriteLine("{0} hit, quitting...", e.SpecialKey);
     quit = true;
     e.Cancel = true; // Set this to true to keep the process from quitting immediately
}

/// <summary>
/// The main gameloop
/// </summary>
static void MainLoop()
{
     int elapsedMilliseconds = 0;
     int totalMilliseconds = TIME_LIMIT_SECONDS * 1000;
     const int INTERVAL = 100;
 
     while (elapsedMilliseconds < totalMilliseconds && !quit)
     {
          // Sleep for a short period
          Thread.Sleep(INTERVAL);
          elapsedMilliseconds += INTERVAL;
  
          /*** Update the screen and handle input here! ***/
      }
 
     Console.WriteLine("Game over!");
}

Putting it all together: Building the WordFinder game

Screenshot - Word finder.pngNow you’ve got all the pieces you need to build a great text-mode game! That’s everything I needed to create my own game, WordFinder. It’s a “find the word” puzzle, where the player has 60 seconds to find all of the words in a grid of random letters.

You can load all of these games into a Visual Studio 2010 project called WordFinder. If you do, you’ll want to add a text file called words.txt to the project. Make sure to set its Copy to Output Directory property to Copy Always.

But you can also compile it from the command line, just like the programs above. Here’s how:

  1. Save each of the following four files into a folder.
  2. Use Notepad to create a text file in the same folder. Save it as words.txt, and fill it with all the valid words for the game (I used this list).
  3. Compile your program like this:
    %SYSTEMROOT%\Microsoft.NET\Framework\v3.5\csc.exe /out:WordFinder.exe Program.cs Game.cs Puzzle.cs WordChecker.cs
  4. Make sure the words.txt fie is in the same folder as WordFinder.exe when you run it. (Yes, there are more elegant solutions to this—like using resource files—but I wanted my game to be quick and dirty!)

One note—if you’re using Notepad to save the four files, you’ll get a warning about Unicode characters that will be lost. That’s because the Game.cs code contains line drawing characters that I pasted in. You have two choices. You can save it using Notepad using its default settings, which will automatically convert the characters to +’s, -‘s, and |’s. But if you want to save the Unicode characters properly, make sure you choose “Unicode” from the Encoding dropdown in the “Save As…” window in Notepad.

Between everything I wrote above and the comments in the code, you should be able to figure out how this game works. Good luck writing your own text-mode games! If you come up with something cool, definitely let me know about it.

Program.cs

using System;
using System.IO;
using System.Threading;

namespace WordFinder
{
     /// <summary>
     /// The Program class contains the main loop, ending the game, running the timer,
     /// and handling it when the user presses ^C to quit. All of the gameplay and drawing
     /// is handled in the Game class.
     /// </summary>
     class Program
     {
          /// <summary>
          /// Length of the puzzle in letters
          /// </summary>
          const int PUZZLE_LENGTH = 49;
  
          /// <summary>
          /// Every nth letter must be a vowel
          /// </summary>
          const int VOWEL_EVERY = 5;
  
          /// <summary>
          /// The time limit for the puzzle
          /// </summary>
          const int TIME_LIMIT_SECONDS = 60;
  
          /// <summary>
          /// The word list -- I downloaded it from http://unix-tree.huihoo.org/V7/usr/dict/words.html 
          /// and pasted it into words.txt, making sure to set the Copy to Output Directory property
          /// to "Copy Always" (so it ends up in the same foler as the executable). We could also use
          /// a resource, but this makes it easy to expand the game to use any word list.
          /// </summary>
          static string[] words = File.ReadAllLines("words.txt");
  
          /// <summary>
          /// Game object to track the gameplay
          /// </summary>
          static Game game;
  
          /// <summary>
          /// Set this static field to true to quit the game
          /// </summary>
          static bool quit = false;
  
          /// <summary>
          /// The player's current input
          /// </summary>
          static string word = String.Empty;
  
          /// <summary>
          /// The entry point sets up the screen, initializes the game, and kicks off the main loop
          /// </summary>
          static void Main(string[] args)
          {
               // Make sure the game quits if the user hits ^C
               // Set Console.TreatControlCAsInput to true if you want to use ^C as a valid input value
               Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
   
               Console.CursorVisible = false;
               
               game = new Game(PUZZLE_LENGTH, VOWEL_EVERY, words);
               game.DrawInititalScreen();
               MainLoop();
           }
  
          /// <summary>
          /// Event handler for ^C key press
          /// </summary>
          static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
          {
               // Unfortunately, due to a bug in .NET Framework v4.0.30319 you can't debug this 
               // because Visual Studio 2010 gives a "No Source Available" error. 
               // http://connect.microsoft.com/VisualStudio/feedback/details/524889/debugging-c-console-application-that-handles-console-cancelkeypress-is-broken-in-net-4-0
               Console.SetCursorPosition(0, 19);
               Console.WriteLine("{0} hit, quitting...", e.SpecialKey);
               quit = true;
               e.Cancel = true; // Set this to true to keep the process from quitting immediately
           }
  
          /// <summary>
          /// The main gameloop
          /// </summary>
          static void MainLoop()
          {
               int elapsedMilliseconds = 0;
               int totalMilliseconds = TIME_LIMIT_SECONDS * 1000;
               const int INTERVAL = 100;
   
               while (elapsedMilliseconds < totalMilliseconds && !quit)
               {
                    // Sleep for a short period
                    Thread.Sleep(INTERVAL);
                    elapsedMilliseconds += INTERVAL;
    
                    HandleInput();
    
                    PrintRemainingTime(elapsedMilliseconds, totalMilliseconds);
                }
   
               Console.SetCursorPosition(0, 20);
               Console.WriteLine(Environment.NewLine + Environment.NewLine
                   + "Game over! You found {0} words.", game.NumberFound);
           }
  
          /// <summary>
          /// Write the remaining time at the top right corner of the screen
          /// </summary>
          /// <param name="elapsedMilliseconds">Time elapsed since the start of the game</param>
          /// <param name="totalMilliseconds">Total milliseconds allowed for the game</param>
          private static void PrintRemainingTime(int elapsedMilliseconds, int totalMilliseconds)
          {
               int milliSecondsLeft = totalMilliseconds - elapsedMilliseconds;
               double secondsLeft = (double)milliSecondsLeft / 1000;
               string timeString = String.Format("{0:00.0} seconds left", secondsLeft);
   
               // Save the current cursor position
               int left = Console.CursorLeft;
               int top = Console.CursorTop;
   
               // Draw the time in the upper right-hand corner
               Console.SetCursorPosition(Console.WindowWidth - timeString.Length, 0);
               Console.ForegroundColor = ConsoleColor.Magenta;
               Console.Write(timeString);
   
               // Restore the console text color and put the cursor back where we found it
               Console.ResetColor();
               Console.SetCursorPosition(left, top);
           }
  
          /// <summary>
          /// Handle any waiting user keystrokes 
          /// </summary>
          static void HandleInput()
          {
               Thread.Sleep(50);
               if (Console.KeyAvailable)
               {
                    ConsoleKeyInfo keyInfo = Console.ReadKey(true);
                    if (keyInfo.Key == ConsoleKey.Backspace)
                    {
                         if (word.Length > 0)
                             word = word.Substring(0, word.Length - 1);
                     }
                    else if (keyInfo.Key == ConsoleKey.Escape)
                    {
                         word = String.Empty;
                     }
                    else
                    {
                         string key = keyInfo.KeyChar.ToString().ToUpper();
                         if (game.IsValidLetter(key))
                         {
                              word = word + key;
                          }
                     }
                    game.CurrentInput = word;
                    game.ProcessInput();
                    game.UpdateScreen();
                }
           }
      }
}

Game.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace WordFinder
{
     /// <summary>
     /// The Game class keeps track of the state of the game and draws the screen
     /// updates. It uses an instance of the Puzzle class to keep track of the letters on
     /// the puzzle grid, and an instance of WordChecker to keep track of the valid
     /// words and check the player's answers.
     /// </summary>
     class Game
     {
          /// <summary>
          /// The WordChecker object to check the words that were found
          /// </summary>
          private WordChecker wordChecker;
  
          /// <summary>
          /// Get the number of words that were found
          /// </summary>
          public int NumberFound
          {
               // The WordChecker object keeps track of this
               get { return wordChecker.NumberFound; }
           }
  
          /// <summary>
          /// The Puzzle object keeps track of the random letters and checks words
          /// </summary>
          private Puzzle puzzle;
  
          /// <summary>
          /// The player's current input
          /// </summary>
          public string CurrentInput { private get; set; }
  
          /// <summary>
          /// Game constructor
          /// </summary>
          /// <param name="puzzleLength">The number of letters in the puzzle</param>
          /// <param name="vowelEvery">Add a vowel every Nth letter</param>
          /// <param name="validWords">The sequence of valid words</param>
          public Game(int puzzleLength, int vowelEvery, IEnumerable<string> validWords)
          {
               this.wordChecker = new WordChecker(validWords);
               this.puzzle = new Puzzle(puzzleLength, vowelEvery);
               CurrentInput = String.Empty;
           }
  
          /// <summary>
          /// Draw the screen to the console when the program starts
          /// </summary>
          public void DrawInititalScreen()
          {
               Console.Clear();
               Console.Title = "Word finder";
               puzzle.Draw(25, 3);
               Console.SetCursorPosition(7, 11);
               Console.Write("┌───────────────────────────────────────────────────────╖");
               Console.SetCursorPosition(7, 12);
               Console.Write("");
               Console.SetCursorPosition(63, 12);
               Console.Write("");
               Console.SetCursorPosition(7, 13);
               Console.Write("╘═══════════════════════════════════════════════════════╝");
               UpdateScreen();
           }
  
          /// <summary>
          /// Update the screen when it's refreshed
          /// </summary>
          public void UpdateScreen()
          {
               // Use String.PadRight() to make sure the yellow entry box remains a constant
               // size, no matter how long the word is or the word number
               Console.SetCursorPosition(8, 12);
               Console.ForegroundColor = ConsoleColor.DarkGray;
               Console.BackgroundColor = ConsoleColor.Yellow;
               string message = String.Format("Enter word #{0}: {1}", 
                       wordChecker.NumberFound, CurrentInput);
               Console.Write(message.PadRight(54));
               Console.ResetColor();
   
               Console.SetCursorPosition(0, 17);
               Console.Write("Found words: ");
               foreach (string word in wordChecker.FoundWords)
                   Console.Write("{0} ", word);
   
               Console.SetCursorPosition(7, 14);
               Console.Write("Type in any words you find, press <ESC> to clear the line");
           }
  
          /// <summary>
          /// Process input any time the player enters a new letter
          /// </summary>
          public void ProcessInput()
          {
               wordChecker.CheckAnswer(CurrentInput, puzzle);
           }
  
          /// <summary>
          /// Return true if a key press is a valid letter
          /// </summary>
          /// <param name="key">Key that was pressed</param>
          /// <returns>True only if the key is a valid consonant or vowel in the puzzle</returns>
          public bool IsValidLetter(string key)
          {
               if (key.Length == 1)
               {
                    char c = key.ToCharArray()[0];
                    return Puzzle.Consonants.Contains(c) || Puzzle.Vowels.Contains(c);
                }
               return false;
           }
  
      }
}

Puzzle.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace WordFinder
{
     /// <summary>
     /// The Puzzle class keeps track of the puzzle grid. The Game uses it to draw
     /// the initial grid to the screen, and the WordFinder class uses it to check if the
     /// player's input contains only letters from the grid.
     /// </summary>
     class Puzzle
     {
          /// <summary>
          /// Randomizer
          /// </summary>
          private Random random = new Random();
  
          /// <summary>
          /// Consonants (including Y)
          /// </summary>
          public static readonly char[] Consonants = { 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 
               'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z' };
  
          /// <summary>
          /// Vowels (including Y)
          /// </summary>
          public static readonly char[] Vowels = { 'A', 'E', 'I', 'O', 'U', 'Y' };
  
          /// <summary>
          /// Backing field for Letters property
          /// </summary>
          char[] letters;
  
          /// <summary>
          /// Get the letters in the puzzle
          /// </summary>
          public IEnumerable<char> Letters
          {
               get { return letters; }
           }
  
          /// <summary>
          /// The number of letters in the puzzle
          /// </summary>
          private int puzzleLength;
  
          /// <summary>
          /// Puzzle Constructor
          /// </summary>
          /// <param name="puzzleLength">The number of letters in the puzzle</param>
          /// <param name="vowelEvery">Every nth letter is a vowel</param>
          public Puzzle(int puzzleLength, int vowelEvery)
          {
               this.puzzleLength = puzzleLength;
   
               letters = new char[puzzleLength];
   
               for (int i = 0; i < puzzleLength; i++)
               {
                    if (i % vowelEvery == 0)
                        letters[i] = Vowels[random.Next(Vowels.Length)];
                    else
                        letters[i] = Consonants[random.Next(Consonants.Length)];
                }
           }
  
          /// <summary>
          /// Draw the puzzle at a specific point on the screen
          /// </summary>
          /// <param name="left">The column position of the cursor</param>
          /// <param name="top">The row position of the cursor</param>
          public void Draw(int left, int top)
          {
               int oldTop = Console.CursorTop;
               int oldLeft = Console.CursorLeft;
   
               Console.BackgroundColor = ConsoleColor.Gray;
   
               // Create the random puzzle using random letters and print them
               for (int i = 0; i < puzzleLength; i++)
               {
                    // Use cursor movement to draw the rows of the square puzzle grid
                    if (i % Math.Floor(Math.Sqrt(puzzleLength)) == 0)
                    {
                         Console.CursorTop = top++;
                         Console.CursorLeft = left;
                     }
    
                    if (Vowels.Contains(letters[i]))
                        Console.ForegroundColor = ConsoleColor.DarkRed;
                    else
                        Console.ForegroundColor = ConsoleColor.DarkBlue;
    
                    Console.Write(" {0} ", letters[i]);
                }
   
               Console.ResetColor();
   
               Console.CursorTop = oldTop;
               Console.CursorLeft = oldLeft;
           }
      }
}

WordChecker.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace WordFinder
{
     /// <summary>
     /// The WordChecker class keeps track of the list of valid words and checks 
     /// to see if a given word is valid and only made up of letters from the grid.
     /// </summary>
     class WordChecker
     {
          /// <summary>
          /// The valid words
          /// </summary>
          private List<string> words = new List<string>();
  
          /// <summary>
          /// The found words
          /// </summary>
          private List<string> foundWords = new List<string>();
  
          /// <summary>
          /// Return the number of words that were found
          /// </summary>
          public int NumberFound
          {
               get { return foundWords.Count; }
           }
  
          /// <summary>
          /// Get the set of words that were found
          /// </summary>
          public IEnumerable<string> FoundWords {
               get
               {
                    List<string> value = new List<string>();
                    foreach (string word in foundWords)
                    {
                         value.Add(word.ToUpper());
                     }
                    return value;
                }
           }
  
          /// <summary>
          /// WordChecker Constructor
          /// </summary>
          /// <param name="validWords">The set of valid words</param>
          public WordChecker(IEnumerable<string> validWords)
          {
               // Make each word uppercase and add it to the word list
               foreach(string word in validWords)
                   this.words.Add(word.ToUpper());
           }
  
          /// <summary>
          /// Check if a player's word is a valid word that's contained in the puzzle
          /// </summary>
          /// <param name="word">Word to check</param>
          /// <param name="puzzle">Reference to the Puzzle object</param>
          public void CheckAnswer(string word, Puzzle puzzle)
          {
               // Make sure the word is a non-empty, valid word that's at least 4 characters long
               if (String.IsNullOrEmpty(word) || foundWords.Contains(word) || word.Length < 4)
                   return;
   
               // Make sure the word is upper case -- and the upperCaseWord string will be destroyed
               // so we need to make a copy. We'll remove each puzzle letter from the word. If any
               // letters are left over, the word is not in the puzzle.
               string upperCaseWord = word.ToUpper();
               if (words.Contains(upperCaseWord))
               {
                    // Make sure it's made up entirely of letters in the puzzle
                    foreach (char letter in puzzle.Letters)
                    {
                         // Remove each puzzle letter from the word
                         if (upperCaseWord.Contains(letter))
                         {
                              // If the word starts with the letter, Substring(0, index - 1) will throw an exception
                              if (upperCaseWord.StartsWith(letter.ToString()))
                                  upperCaseWord = upperCaseWord.Substring(1);
                              else
                              {
                                   int index = upperCaseWord.IndexOf(letter);
                                   upperCaseWord = upperCaseWord.Substring(0, index - 1) + upperCaseWord.Substring(index + 1);
                               }
                          }
                     }
                }
   
               // If removing all the puzzle letters from upperCaseWord left us with an empty string,
               // we found a word. Beep and add it to the found words list.
               if (String.IsNullOrEmpty(upperCaseWord))
               {
                    Console.Beep();
                    foundWords.Add(word);
                }
           }
      }
}

Good luck building your own text-mode games! If you come up with something cool, definitely share!

Andrew Stellman is the author of Head First C# and other books from O’Reilly. You can read more from Andrew at Building Better Software.

 

Common Pitfalls with IDisposable and the Using Statement

Super Development

Memory management with .NET is generally simpler than it is in languages like C++ where the developer has to explicitly handle memory usage.  Microsoft added a garbage collector to the .NET framework to clean up objects and memory usage from managed code when it was no longer needed.  However, since the garbage collector does not deal with resource allocation due to unmanaged code, such as COM object interaction or calls to external unmanaged assemblies, the IDisposable pattern was introduced to provide developers a way to ensure that those unmanaged resources were properly handled.  Any class that deals with unmanaged code is supposed to implement the IDisposable interface and provide a Dispose() method that explicitly cleans up the memory usage from any unmanaged code.  Probably the most common way that developers dispose of these objects is through the using statement.

Ver o post original 1.153 mais palavras

Unity and C#: Game Loop (Awake,Start,Update)

OneStopDotnet

Introduction

The central component of any game, from a programming standpoint, is the game loop. It allows the game to run smoothly regardless of a user’s input or lack thereof.

Every game must and should have a game loop because a game must continue regardless of a user;s input. In this article i will be talking about two important event functions in unity3D i.e., Awake() and Start()

game loop

Ver o post original 518 mais palavras