Showing posts with label game-dev. Show all posts
Showing posts with label game-dev. Show all posts

Tuesday, November 09, 2010

This isn't Jersey!

Reading:
Book 13 of WoT came out on November 2nd. It was really damn good. Since book 14 is going to the finale BS was able to focus on finishing long running story arcs. This book was EPIC.

About 80% through Theodore Rex. Colonel Roosevelt comes out this month, but I'm not going to get it until it comes out in paperback.

Brewing:
Tomorrow I'm going to check out a local homebrewes club. I'm excited. Then on Thursday me and Andy Tasso are brewing up 2 batches of beer. Awesome.

Game Development:
I spent last weekend uninstalling most of my development tools and and I installed the nice little bundle that Microsoft's new 'AppHub' offers. I'll play around with this soon.


Other:
Tanya and I are living in MD now, yikes.
AMC premiered 'The Walking Dead'. It's awesome, watch it.
Now that I'm in a 1st floor apartment I can work out my kettle-bells like a fiend.

Tuesday, July 13, 2010

Abilities (Extending the XNA Content Pipeline)

Over the past few weeks I have been learning how to extend the XNA Content Pipeline.

XNA has a central component to handle importing content like fonts, 3d models, images, audio etc. This is called the Content Pipeline. When we want to define a new type of content, for example a map file or an ability file we need to extend the pipeline.

Before I go into the explanation of how to do this, let me explain some of the pros and cons that I have found. This is probably not definitive, and definitely subjective. One of the reasons I would rather bring in an ability through the pipeline rather than any other way is that content gets processed at compile time rather than during runtime. When the game is compiled the original file gets processed into a proprietary file that is more difficult to hack/edit. This helps stop people from editing an ability file to make it do more damage, or edit a character class to give it abilities it shouldn't have. One of my favorite pros is that you can add all your content files right into the content folder in Visual Studio and organize them in folders. This makes it easier to maintain things for me. The main con is that it can sometimes be a lot of work to learn how to extend the pipeline and you need to extend it every time you add a new content type. Furthermore you need to edit a few files if you decide to make changes to what is held in a file (like if you decide that now an ability file also needs to hold another bit of info you didn't think of before.)

So what does it take to extend the pipeline? Lets walk through the files I made for holding and processing ability information.

XML Example - WolfsHowl.abil
<Ability>
  <Name>Wolf's Howl</Name>
  <Description>
    Frightens Nearby Enemies.
  </Description>
  <Type>Attack</Type>
  <Cost MP="5" HP="0" />
  <Effects>
    <Effect Attribute="Def" Modifier="-2" />
  </Effects>
</Ability>

Here is the sample ability "Wolf's Howl". As you can see it holds information like the name, description, cost, and effects of the ability. In the future I want to expand this to hold the "shape" and range of an ability and other things, but this is a sample.

This xml file is saved as an ".abil" file. Therefore in my trpgProcessors project I need to define an importer that tells the project how .abil files should be handled.

AbilityImporter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;

// TODO: replace this with the type you want to import.
using TImport = System.Xml.XmlDocument;
using System.Xml;

namespace trpgProcessors.Ability
{
    /// <summary>
    /// This class will be instantiated by the XNA Framework Content Pipeline
    /// to import a file from disk into the specified type, TImport.
    ///
    /// This should be part of a Content Pipeline Extension Library project.
    /// </summary>
    [ContentImporter(".abil", DisplayName = "Ability Importer", DefaultProcessor = "AbilityProcessor")]
    public class AbilityImporter : ContentImporter<TImport>
    {
        public override TImport Import(string filename, ContentImporterContext context)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filename);
            return xmlDoc;
        }
    }
}

This file just tells the content pipeline that .abil files are xml docs that get processed by "AbilityProcessor", shown below

AbilityProcessor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

// TODO: replace these with the processor input and output types.
using TInput = System.Xml.XmlDocument;
using TOutput = trpgProcessors.Ability.AbilityContent;
using System.Xml;
using trpgData;

namespace trpgProcessors.Ability
{
    /// <summary>
    /// This class will be instantiated by the XNA Framework Content Pipeline
    /// to apply custom processing to content data, converting an object of
    /// type TInput to TOutput. The input and output types may be the same if
    /// the processor wishes to alter data without changing its type.
    ///
    /// This should be part of a Content Pipeline Extension Library project.
    ///
    /// TODO: change the ContentProcessor attribute to specify the correct
    /// display name for this processor.
    /// </summary>
    [ContentProcessor(DisplayName = "trpgProcessors.Ability.AbilityProcessor")]
    public class AbilityProcessor : ContentProcessor<TInput, TOutput>
    {
        public override TOutput Process(TInput input, ContentProcessorContext context)
        {
            AbilityContent abilityContent = new AbilityContent();
            List<AbilityEffect> effects = new List<AbilityEffect>();
            AbilityEffect ae;
           
            foreach (XmlNode node in input.DocumentElement.ChildNodes)
            {
                if (node.Name == "Name")
                {
                    abilityContent.Name = node.InnerText;
                }
                if (node.Name == "Description")
                {
                    abilityContent.Description = node.InnerText;
                }
                if (node.Name == "Type")
                {
                    abilityContent.Type = node.InnerText;
                }
                if (node.Name == "Cost")
                {
                    abilityContent.CostMP = Convert.ToInt32(node.Attributes["MP"].Value);
                    abilityContent.CostHP = Convert.ToInt32(node.Attributes["HP"].Value);
                }
                if (node.Name == "Effects")
                {
                    foreach (XmlNode tNode in node.ChildNodes)
                    {
                        if (tNode.Name == "Effect")
                        {
                            ae = new AbilityEffect();
                            ae.Attribute = tNode.Attributes["Attribute"].Value;
                            ae.Modifier = Convert.ToDouble(tNode.Attributes["Modifier"].Value);
                            effects.Add(ae);
                        }
                    }
                    abilityContent.AbilityEffects = effects;
                }
            }
            return abilityContent;
        }
    }
}

This function goes through the xml file examining the nodes and processing the information into an AbilityContent file.

AbilityContent.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using trpgData;

namespace trpgProcessors.Ability
{
    public class AbilityContent
    {
        public string Name;
        public string Description;
        public string Type;
        public int CostMP;
        public int CostHP;
        public List<AbilityEffect> AbilityEffects;
    }
}

This while then gets sent to the AbilityWriter which writes the information out into an xnb file.

AbilityWriter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;

// TODO: replace this with the type you want to write out.
using TWrite = trpgProcessors.Ability.AbilityContent;
using trpgData;

namespace trpgProcessors.Ability
{
    /// <summary>
    /// This class will be instantiated by the XNA Framework Content Pipeline
    /// to write the specified data type into binary .xnb format.
    ///
    /// This should be part of a Content Pipeline Extension Library project.
    /// </summary>
    [ContentTypeWriter]
    public class AbilityWriter : ContentTypeWriter<TWrite>
    {
        protected override void Write(ContentWriter output, TWrite value)
        {
            output.Write(value.Name);
            output.Write(value.Description);
            output.Write(value.Type);
            output.Write(value.CostMP);
            output.Write(value.CostHP);
            output.Write(value.AbilityEffects.Count);

            foreach (AbilityEffect effect in value.AbilityEffects)
            {
                output.Write(effect.Attribute);
                output.Write(effect.Modifier);
            }
        }
        public override string GetRuntimeReader(TargetPlatform targetPlatform)
        {
            return typeof(trpgData.AbilityReader).AssemblyQualifiedName;
        }
    }
}

All the above processing happens when the game is compiled.


Now let's switch our attention to what happens at runtime when the game goes to load the actual content that was processed and created at compile time.

Ability.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;

namespace trpgData
{
    public class Ability
    {
        //Info
        public string Name { set; get; }
        public string Description { set; get; }

        //Can be: Attack, Buff, Util
        public string Type { set; get; }

        //Cost
        public int CostMP { set; get; }
        public int CostHP { set; get; }

        //Attack shape


        //Attack effects
        public List<AbilityEffect> AbilityEffects = new List<AbilityEffect>();


        public Ability()
        {
        }
    }

    public class AbilityEffect
    {
        public string Attribute { set; get; }
        public double Modifier { set; get; }

        public AbilityEffect()
        {
        }
    }

    public class AbilityReader : ContentTypeReader<Ability>
    {
        protected override Ability Read(
            ContentReader input, Ability existingInstance)
        {
            Ability m = new Ability();
            m.Name = input.ReadString();
            m.Description = input.ReadString();
            m.Type = input.ReadString();

            m.CostMP = input.ReadInt32();
            m.CostHP = input.ReadInt32();

            int effectCount = input.ReadInt32();

            List<AbilityEffect> effects = new List<AbilityEffect>();
            AbilityEffect ae;

            for (int i = 0; i < effectCount; i++)
            {
                ae = new AbilityEffect();
                ae.Attribute = input.ReadString();
                ae.Modifier = input.ReadDouble();

                effects.Add(ae);
            }
            m.AbilityEffects = effects;

            return m;

        }
    }
}

As you can see this file contains 3 classes. The first class is our ability class. The second is our AbilityEffect class that we use to make lists of effects. The last is the important one, the AbilityReader. This class goes through the xnb file and populates our Ability.


All of this stuff might seem like a lot but when we load the actual abilities into the game the actual code just looks like this:
Ability WolfHowl = Content.Load<Ability>(@"Abilities\\WolfHowl");

Sorry if this post was really code heavy, but code is what has taken up a lot of my time lately making all these files for both maps and abilities. Next I will be doing the same for Unit and CharacterClasses.

My next post will be focused more on design than code, so stay tuned.

Thursday, June 17, 2010

Reading

Sorry for the lack of posts as of late. I've been spending a large amount of spare time reading. Mays book was 'Guns, Germs, and Steel' by Jared Diamond. This month I am reading 'The Rise of Theodore Roosevelt' by Edmund Morris.

On the brewing front:
Almost out of American Wheat. Loved this one, will be brewing it again many times.
Gotta bottle 'Starcraft 2 Release: The Beer' this weekend I hope.

On the coding front:
Got maps to import through the content pipeline but the list of tiles is coming up blank, an odd problem. I'm having trouble figuring out why this is happening. Going to post my code to see if people on the XNA forums can help.

On the personal front:
Spent last weekend looking at towns in MD. Getting excited to go house hunting. Looking forward to the move.
Also, reading about TR has me wanting to keep a journal, so I'm keeping one using Evernote. I doubt it will last, frankly. Lastly, kettlebells and situps have been paying off, I've lost about 10-12 pounds over a very slow amount of time, (i started with pushups and situps in January). My pants and shirts are all fitting better lol. Still got a long way to go on the beer belly though.

I think my hobbies are rather well rounded lately. (reading, brewing, working out, coding: mind and body both very active) Tiring as hell though, feels like I'm always at full speed. Possibly part of why I really like reading about TR.

Wednesday, May 12, 2010

Norse TRPG

As I mentioned in my most recent post, I am working on a game in my spare time. I have been a full time developer for years now, but this is the first time I am truly working on something for myself. The game is an amalgam of some of my favorite things: tactical rpgs and Norse mythology. 

I am currently working on the engine a few weeknights a week. I am also trying to work on the earliest pieces of documentation, including: a concept document, a proposal document, and a technical design doc.

I'll discuss some story concepts in my next post, but until then I'll leave you with some concept art drawn up by my babyboy Bryan Glynn:

This is the concept for the main character, yet to be named.


Wednesday, April 21, 2010

Getting in the Game (what a corny title!)

My first gaming system was the NES. I got my first computer when I was 9. It was my xmas gift, not a family PC. I've always been a geek. Me and Dan started trying to make games using shitty 'make your own game' apps when we were in grammar school. I started learning c++ and html when I was in about 6th grade. I've been coding ever since. I've been gaming and I've been coding. So why haven't I started learning actual game development until now?


Back in November 2009 I was listening to the first episode of 1ups Oddcast and heard a fantastic interview with James Silva. James is an experienced developer from Ska Studios, the team that made The Dishwasher: Dead Samurai. He talked about how he made the game: I MAED A GAM3 W1TH Z0MB1ES 1NIT!!!1 in just a few days using the XNA framework. He talked about how all you need is the free version of Microsoft Visual Studio C# Express, the free XNA framework, and some knowledge of coding (c# in particular would be good.) Well Shit. I've been making webapps in C# at work for a while now, and I've got at least 10 years of coding under my belt (although the first 5 years are bullshit lol). I headed out to B&N and picked up a book about XNA and started learning about how the whole thing works.

Most tutorials are really boring. I learn a ton, but it is never focused towards what I want to make. So sometime around the end of March or so I started working on my own project. It's not pretty, and it's not good, but it's mine. I'll keep working on other tutorials as well, but I'll keep feeding everything I learn into my game, and I'll focus on learning things in such a way that it moves my game forward. I'm working on My game idea for once.

More to come.