Silverlight Game Controls

by calbert 11/19/2008 11:44:47 PM

While building the Silverlight UI for Perenthia I have been building some re-usable game controls that I plan on posting before too long. One of the controls I created is a Window control that is just a control that provides a title bar with a close button and provides a Content section to add custom controls. I needed it to provide menu windows or panels but it could be used outside of games for just about anything. The control is draggable, as long as the parent control is a Canvas and will position itself as the top window when clicked, provided other windows exist in the same parent.

The Window control is featured in the screen shot below, the "Spellbook", "Character Sheet" and "Adenturer's"** are the windows. They contain custom controls that determine the content of the windows. The small icons at the very bottom of the screen shot are Slot controls that allow for a background image, primary image and object Item to be set on them. They also respond to clicks so click events can be handled on them. The ChatPanel under the windows is also a re-usable control and allows for adding any type of UIElement as content for the main chat area, not just text.

I hope to get these controls commented and the source up soon.

** The "Adventurer's" window is actually "Adventurer's Backpack", have a font sizing issue :)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Perenthia PBBG | Silverlight 2 Development | Silverlight Games

Happy Birthday to MUD

by calbert 10/20/2008 6:25:49 PM

MUD is 30 years old today. For those who don't know what MUD is, it is the forerunner to the virtual worlds and MMORPGs we love and play today.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

General

Silverlight 2 Release

by calbert 10/14/2008 7:12:39 PM

Silverlight 2 has officially been released. I've upgraded both Joust and Cameron's Dungeon as well as the Perenthia client. Work on Perenthia continues, albeit a little slow but it does continue. :)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Perenthia PBBG | Silverlight 2 Development | Silverlight Games

Game Scripting in IronPython

by calbert 9/16/2008 6:20:14 PM

Since my last post about game scripting I have had the chance to play around more with IronPython. I wrote a quick MUD type demo game that utilizes C# and IronPython on the server and uses Silverlight 2 as the user interface.

Play Cameron's Dungeon!

I wanted to explore this scripting for Perenthia because I want to be able to add dynamic functions or scripts to objects. I wrote this sample to test out using C# as base classes for IronPython classes and passing operations back and forth between the two. As such the source is kind of loose but the concepts are demonstrated.

What I have is a basic framework of C# classes that define an Actor (any object in the game), a Client (a connected player), a Game (the logic of the game) and a Server (for handling HTTP communication, etc.). The Actor, Client and Game classes also server as the base classes for IronPython classes or Creatures, NPCs, Players and Rooms.

Server is the main C# class and gets initialized in the global.asax file like so:

protected void Application_Start(object sender, EventArgs e)
        {
            SLGameEngine.Server.Start(Server.MapPath("python/startup.py"),
                new string[] 
                { 
                    Server.MapPath("python"), 
                    Server.MapPath("bin"),
                    System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
                });
        }

Inside the Server class a static class called PyEngine handles all the execution of the IronPython code. The Start method inside the server class makes a few calls into the PyEngine that starts the engine and executes the code in the /python/startup.py script:

public static void Start(string startupFilePath, string[] searchPaths)
        {
            try
            {
                PyEngine.Startup(searchPaths);
                PyEngine.AddAssembly(typeof(Game).Assembly);

                PyEngine.ExecuteFile(startupFilePath);

                _timer = new Timer(300000);
                _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
                _timer.Start();
            }
            catch (Exception ex)
            {
                Log.Write(ex.ToString());
            }
        }

The first two lines initialize the scripting engine while the third actually executes the startup.py script. Inside the startup script is called to create a global instance of the Game class and to start the game running. The timer stuff is used to remove inactive players. After the game is started any input sent from the user to the server is handled by an IHttpHandler class called CommandHandler. This class parses the request and send the input to the Server class that will actually pass the handling of the input to the IronPython Game class.

public void ProcessRequest(HttpContext context)
        {
            string response = "Invalid Command";
            try
            {
                string cmd = context.Request.Form["cmd"];
                string ip = context.Request.UserHostAddress;
                if (!String.IsNullOrEmpty(cmd))
                {
                    if (cmd.StartsWith("NEW"))
                    {
                        response = Intro.GetIntro(context);
                    }
                    else if (cmd.StartsWith("NAME "))
                    {
                        string name = cmd.Substring(5);
                        if (Server.NameExists(name))
                        {
                            response = "That name has already been used, please choose another.";
                        }
                        else
                        {
                            Server.AddClient(ip, name);
                            response = String.Format("Welcome {0}!{1}{2}", name, Environment.NewLine, Server.GetClientOutput(ip));
                        }
                    }
                    else
                    {
                        Server.ProcessInput(ip, cmd);
                        response = Server.GetClientOutput(ip);
                    }
                }

                if (String.IsNullOrEmpty(response))
                {
                    response = "Internal Error";
                }
            }
            catch (Exception ex)
            {
                Log.Write(ex.ToString());
                response = "Internal Error";
            }
            finally
            {
                context.Response.ContentType = "text/plain";
                context.Response.Write(response);
            }
        }

The Server class calls methods on the PyEngine class to actually execute IronPython method calls:

public static void ProcessInput(string ipAddress, string input)
        {
            PyEngine.CallMethod("game", "ProcessInput", ipAddress, input);
        }

From PyEngine:

public static void CallMethod(string variableName, string methodName, params object[] args)
        {
            try
            {
                ObjectOperations ops = _engine.Operations;
                if (_scope.ContainsVariable(variableName))
                {
                    object instance = _scope.GetVariable(variableName);
                    if (instance != null)
                    {
                        if (ops.ContainsMember(instance, methodName))
                        {
                            object method = ops.GetMember(instance, methodName);
                            ops.Call(method, args);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Write(ex.ToString());
            }
        }

The IronPython Game class ProcessInput method:

def ProcessInput(self, ip, input):
        words = input.split(' ')
        client = self.Clients[ip]
        
        # Update the stored date on the client so it will stay active.
        client.LastUpdateDate = DateTime.Now;
        
        # Get the remainder of the words as a string for chat messages.
        index = 0
        sb = StringBuilder()
        for w in words:
            if index > 0:
                sb.Append(w).Append(" ")
            index += 1
        message = sb.AppendLine().ToString()

        # Setup potential movement realted variables.
        prevRoom = client.player.room
        exit = -1
        direction = ""
        if words[0] == "n":
            exit = 0
            direction = "north"
        elif words[0] == "s":
            exit = 1
            direction = "south"
        elif words[0] == "e":
            exit = 2
            direction = "east"
        elif words[0] == "w":
            exit = 3
            direction = "west"
        elif words[0] == "look":
            client.Write(ROOMS[client.player.room].ToString(client.player))
        elif words[0] == "say":
            # Send the say message to all players in the game.
            for item in self.Clients:
                c = item.Value
                if c.player.name != client.player.name:
                    c.Write(String.Format("{0} says: {1}", client.player.name, message))
                elif c.player.name == client.player.name:
                    client.Write(String.Format("You say: {0}", message))
        elif words[0] == "who":
            # Print a list of players online.
            client.Write("Who's Online:\n")
            for item in self.Clients:
                client.Write("%s\n"%(item.Value.player.name))
        else:
            client.Write("\nInvalid Command\n")
        
        if exit > -1:
            if ROOMS[client.player.room].exits[exit] > -1:
                # Remove the player from the previous room
                if prevRoom > -1:
                    ROOMS[prevRoom].avatars.remove(client.player)
                
                # Add the player to the current room
                client.player.room = ROOMS[client.player.room].exits[exit]
                ROOMS[client.player.room].avatars.append(client.player)
                
                # Output the resuls to the client
                client.Write("You move %s\n"%(direction))
                client.Write(ROOMS[client.player.room].ToString(client.player))
            else:
                client.Write("You can not move in that direction.\n")

The client.Write statements actually pass control back to C# to write the text into a StringBuilder so that all the text can be retrieved at once before sending the response down to the client. On the client side or Silverlight 2 side, input from the user is sent to the server using my HttpHelper class.

private void ExecuteCommand(string cmd)
        {
            HttpHelper helper = new HttpHelper(new Uri((App.Current as App).ServerUrl), "POST",
                new KeyValuePair<string, string>("cmd", cmd));
            helper.ResponseComplete += new HttpResponseCompleteEventHandler(helper_ResponseComplete);
            helper.Execute();
        }

All responses from the server are just output to the chat window:

void helper_ResponseComplete(HttpResponseCompleteEventArgs e)
        {
            switch (_state)
            {
                case GameState.NewConnection:
                    _state = GameState.Name;
                    break;
                case GameState.Name:
                    _state = GameState.Play;
                    break;    
            }

            if (e.Response.Equals("That name has already been used, please choose another."))
            {
                _state = GameState.Name;
            }
            
            this.UpdateConsole(e.Response);
        }

        private delegate void UpdateConsoleDelegate(string text);
        private void UpdateConsole(string text)
        {
            if (this.CheckAccess())
            {
                _content.Append(text);
                txtConsole.Content = _content.ToString() + Environment.NewLine;

                double scrollOffset = txtConsole.VerticalOffset;
                scrollOffset += txtConsole.ScrollableHeight + txtConsole.ViewportHeight;
                txtConsole.ScrollToVerticalOffset(scrollOffset);
            }
            else
            {
                this.Dispatcher.BeginInvoke(new UpdateConsoleDelegate(this.UpdateConsole), text);
            }
        }

The source is not commented very well and lacks consistency because I was trying different things but does lend as a primer and provide something to build from. Of course, this could handle other client interfaces such as AJAX, etc. but I used Silverlight since Perenthia is going to use Silverlight as its UI.

And, because I am good like that, you can download Cameron's Dungeon Source Code (6MB)!

Or just play Cameron's Dungeon!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

ASP.NET Development | Game Development | General | Perenthia PBBG | Silverlight 2 Development | Silverlight Games

Perenthia Development Update

by calbert 9/13/2008 10:52:46 PM

Perenthia development is still moving along, doing a good portion of content planning and development recently since most of the game engine is complete. I am still hoping to have the alpha up very soon. I am testing out some of the content, primarily quests and once I settle on a solution I will be able to get the alpha area complete and online. I may release the character creator and a simple chat room before the alpha area is ready, just depends on how much time I can devote to it.

Perenthia Development - 89%

User Interface (UI) - 88%

  • Main Chat Window - 92%
    • Colored Text - 100%
    • Clickable Text - 85%
  • Mini-Map - 100%
  • Current Place Details (Was Who's Online) 75%
  • Character Creation - 85%

Server (Includes Authentication, World State and Object Model) - 86%

  • Authentication - 100%
  • Character Creation - 95%
  • Content (Rooms, NPCs, Monsters, Quests) - 65%
  • Combat System - 85%
  • Magic/Ability System - 85%

Database - 95%

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Perenthia PBBG | Silverlight 2 Development | Silverlight Games

Joust : A Silverlight 2 Game - Source Code

by calbert 9/8/2008 11:39:09 PM

I didn't get a chance to work on Joust any more before the contest deadline and won't have enough time in the next hour and half. Anyway, as promised here is the source code:

Joust Source Code

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Silverlight 2 Development | Silverlight Games

Joust : A Silverlight 2 Game

by calbert 9/6/2008 9:51:26 PM

I was working on a simple sports game for the Team Zone Sports Silverlight 2 Game Contest. The rules specified a sports theme but did not specify a century or the type of sports so I created a jousting game. I haven't completely finished the game, it doesn't have everything I wanted it to have and the horse kind of drives like a car :) The dust trail behind the horse actually adds to the car effect!

The game is Silverlight 2, C# and makes use of the Farseer Physics engine.

Anyway, I am hoping to get it cleaned up a little more before the contest submission deadline but not sure that is going to happen given my current workload.

I will post the source once the submission deadline is over, I want to try and get it completely finished by then but if not I will post the source anyway.

Play Joust

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Silverlight 2 Development | Silverlight Games

Scripting for Games

by calbert 8/26/2008 1:02:00 AM

Scripting in games is not a new concept, most games do this on some level. Scripting allows game objects to execute code that is not compiled as part of the object. In the realm of roe playing games scripting gives objects the ability to react to the world around them. For instance, an object could execute script whenever a player gets near it, allowing a vender to hawk their wares, creatures to attack, etc. There are a variety of scripting languages currently being implement in games such as Lua and Python. Recently I have been researching these two for possible addition to Perenthia to provide me the ability to add custom behavior to objects and NPCs.

Edit: Thanks to some helpful insight and information from Michael Foord I was able to get an IronPython sample working. The sample adds scripting support to an object; the code is very basic but accomplishes the task. Thanks Michael!

Here is a snippet of a console app using the latest IronPython Beta4:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Scripting;

using IronPython;
using IronPython.Hosting;
using IronPython.Runtime;
using IronPython.Runtime.Exceptions;

using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

namespace IronPythonGameScripting
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Actor player = new Actor("Cam");
                Actor mob = new Actor("Mob");
                mob.Script = @"class Mob:
    def onEncounter(self, *value):
        value[0].Name = ""Mr Groovy""";

                Console.WriteLine("Player name was '{0}'", player.Name);

                mob.Execute(Actor.EVENT_ON_ENCOUNTER, player);

                Console.WriteLine("Player name is now '{0}'", player.Name);

                mob.Execute("Test", player);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }
        }
    }

    public static class Engine
    {
        private static ScriptEngine _engine;
        private static ScriptScope _scope;

        static Engine()
        {
            _engine = PythonEngine.CurrentEngine;
            _scope = _engine.CreateScope();
        }

        public static void Initialize()
        {
        }

        public static void Execute(string script)
        {
            ScriptSource source = _engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements);
            source.Execute(_scope);
        }

        public static void Execute(string script, string className, string methodName, params object[] args)
        {
            ObjectOperations ops = _engine.Operations;
            ScriptSource source = _engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements);
            source.Execute(_scope);

            if (_scope.ContainsVariable(className))
            {
                object @class = _scope.GetVariable(className);
                object instance = ops.Call(@class);
                if (instance != null)
                {
                    if (ops.ContainsMember(instance, methodName))
                    {
                        object method = ops.GetMember(instance, methodName);
                        ops.Call(method, args);
                    }
                }
            }
        }
    }

    public class Actor
    {
        public const string EVENT_ON_ENCOUNTER = "onEncounter";

        public string Name { get; set; }
        public string Script { get; set; }

        public Actor(string name)
        {
            this.Name = name;
        }

        public void Execute(string methodName, params object[] args)
        {
            Engine.Execute(this.Script, "Mob", methodName, args);
        }
    }
}

 

As it turns out I was attempting to use the IronPython libraries compiled against the Silverlight framework rather than the libraries compiled against the normal .NET framework. I was also using an older beta 1 version of the IronPython library which may have attributed to the exceptions I was seeing. Got to make sure you reference the correct assemblies when working in both .NET and Silverlight. Surprised this is the first time I've done this...

I reviewed IronPython because it has Silverlight support with the DLR but it is really designed to be used instead of C# not as a scripting language executed from within C#. With Lua though I may be able to get it working although it still seems like everything was designed to simply execute the game in lua scripts using C# as the core instead of augmenting C# classes.

I really want to just be able to raise events on the mobile objects and have instances handle those events in a custom way. I certainly don't want to compile C# on the fly either as that has its own set of issues. Compiling C# on the fly is like running an exe for each script that is executed and would be way too costly in both execution time to compile and memory consumption.

Also, since both the client and server will need to execute scripts the scripting language needs to work in both Silverlight and ASP.NET.

Perenthia currently handles commands using a Dictionary<int, Command> where the int is command value, from a list of constants, and the Command is a method pointer (delegate). When the game loads up the first time the list of commands is constructed and the methods pointers are set to methods that related to the command. An example would be a chat command. When the command comes in and is validated the method pointer is found using this dictionary and then executed in the context of the connected player. I was thinking of doing the same thing with mobiles and the actions they can take and respond to based on the world around them. It is a bit more complex with mobiles than commands since commands do a specific thing whereas every mobile could execute a different block of code for a given event. I still have some work to do on it but this will probably be what I use in place of scripting. I loose the flexibility of writing quick scripts, changing them on the fly, etc. but gain the ability to have it work within my code framework, rely on only .NET and work in both Silverlight and ASP.NET.

Currently rated 1.0 by 1 people

  • Currently 1/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Perenthia PBBG | Silverlight 2 Development | Silverlight Games

Silverlight Game Contest

by calbert 8/23/2008 12:01:00 AM

I thought I would take a little break from working on Perenthia and take part in a Silverlight Game Contest for a sports theme game. This will push out the alpha release date a little but I need a little change of pace.

I am a little late in deciding to do this but figured I would give it a try and see if I can come up with something fun by September 8th. I have an idea for a simple game, hopefully I can make it fun to play because I know it will be fun to build.

Once the game is finished I will also post the source code.

More Perenthia Screen Shots

by calbert 8/9/2008 1:36:48 AM

Here are a few more screen shots of the Perenthia UI. The three screen shots are dialog windows that popup as a result of clicking on icons or buttons in UI. They are use a reusable control I created that has the title bar and X button and then just has a ContentControl for the guts of the dialog. The dialog window is draggable and does the hide and show thing. I need to do some cleanup on it and then I will post the source. I will also post the source for the stat bars shown on the skills dialog screen shot.

Also, I am hoping to have some time to blog about some of what I am doing with the overall game engine. I wanted to provide a development update but haven't moved the development along all that much due to working out some networking issues and trying to clean up some of the code.

The goal for Alpha is to get a working zone complete with quests, monsters, npcs, etc. However, I may do some smaller tests with the alpha registrants before all of this is complete. I was thinking of setting up a tiny zone just for testing where players could login, create a Character and accept a quest, which would be to enter a room where enemies spawn randomly and in various numbers. This would allow me to test a lot of things in one place; Character Creation, Quests, Spawning, Combat and NPC interaction.

Anyway, here are the screen shots; this first one is the Character Sheet that will display your character stats, equipped items and skills. The empty box will show the skills once I bind them to it. :)

This next screen is the actual skills screen where you can see you skill rank and all available skills. If you have Skill Points you can increase or learn new skills from this window.

This last image is just the backpack dialog, all I have is a starting candle right now. :)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Game Development | General | Perenthia PBBG | Silverlight 2 Development | Silverlight Games

Powered by BlogEngine.NET 1.3.1.0
Theme by Mads Kristensen

About the author

I am Senior Software Engineer specializing in the Microsoft .NET Framework and PBBG development.

E-mail me Send mail

Calendar

<<  December 2008  >>
MoTuWeThFrSaSu
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar

Recent posts

Recent comments