Touch Input in Windows 7 or 8 desktop mode.

I am the proud owner of a Surface Pro 128GB, a Lumia 822, and I had an HTC Trophy Windows Phone 7 when it first came out. I have been an XNA enthusiast since about 3.1, and I have blogged about input management before. I only mention this because I am a fan of the Gesture API that the XNA team released for WP7. A decision they made, though, was to release that API only for WP7 and left it out of the XNA 4 PC libraries. I decided to write a library to do gesture sampling in a very similar way!

I am excited to announce a new project I am working on! Though named FRBTouch (because eventually it will aim to integrate with the FlatRedBall engine), will have components that will work on any system with the XNA libraries installed. It already detects gestures like tap, freedrag, and pinch, providing GestureSample objects that are identical to the XNA WP7 implementation!

Here is some example code that already uses the library in an XNA game:

    public partial class TouchScreen
    {
        private GestureProvider _gestureProvider;

        void CustomInitialize()
        {
            _gestureProvider = new GestureProvider(new QueueingTouchEventProvider(FlatRedBallServices.Game.Window.Handle));
        }

        void CustomActivity(bool firstTimeCalled)
        {
            var gestures = _gestureProvider.GetSamples();

            if (gestures != null)
            {
                foreach (var gestureSample in gestures)
                {
                    switch (gestureSample.GestureType)
                    {
                        case GestureType.Tap:
                            FlatRedBall.Debugging.Debugger.CommandLineWrite("Tap");
                            break;
                        case GestureType.FreeDrag:
                            FlatRedBall.Debugging.Debugger.CommandLineWrite("Drag");
                            break;
                        case GestureType.Pinch:
                            FlatRedBall.Debugging.Debugger.CommandLineWrite("Pinch");
                            break;
                        case GestureType.DragComplete:
                            FlatRedBall.Debugging.Debugger.CommandLineWrite("DragComplete");
                            break;
                        case GestureType.PinchComplete:
                            FlatRedBall.Debugging.Debugger.CommandLineWrite("PinchComplete");
                            break;
                    }
                }
            }
        }
    }

Think of the CustomInitialize function as the constructor,and the CustomActivity function as the game loop (this is just how Glue from FRBDK organizes a screen).

I hope to be completing out the gestures and adding flags to enable and disable certain gestures as time goes on!

Separation of responsibilities: Ability, AbilityEffect, and EffectManager

After talking with @Sunflash93 on twitter (find their blog here), I got to thinking I should post about how I designed the ability system in my game Z-Com. See my previous blog post for more info about the game.

In my coding adventures, I like to attempt to stick to the SOLID principles of OOD as outlined here. Namely, my favorite and arguably the easiest of the principles to smell is the Single Responsibility Principle. In short, A class should have one, and only one, reason to change. This can and should be applied to all facets of OO programming, including game development.

When first trying to flesh out the details of how I would do abilities, I knew I wanted a few things:

  • Single target abilities
  • AOE/Multi target abilities
  • Friendly abilities (heals)
  • Damage/Healing over time abilities
  • Constant effects (increases your speed by x for y seconds)

Starting with single target abilities, I thought perhaps I would just do it all in one class (Ability). A TacticalEntity (my movable player and zombie object) would get a list of abilities that one could fire at will (zombies through their AI, and players through some GUI). What is so wrong with this approach? For starters, it would would fine for a single target or aoe instant ability,  but how would a single method on a single instance of an ability apply a damage over time effect (e.g. Does 10 damage per second for 4 seconds)? You have to apply something to an entity and have it stick: AbilityEffect.

That was the biggest revelation for me: separate the responsibility of applying effects and the actual damage/healing effect to a different object altogether. Ok great… now I can just put a collection of effects on a TacticalEntity and an ability can apply effects to the entity! Wait… who is responsible for removing the effects once they expire? For that matter, who is responsible for keeping track of all the effects?

Of course the effect could probably have handled all of this, and the entity itself could have removed effects from itself when they expire, but that’s not the responsibility of the TacticalEntity. It already has a lot of code and does enough. That is where EffectManager comes along. It’s a static class that has an Activity() method that gets called every frame, and it gets the honor of keeping track of a Dictionary<TacticalEntity, List> which holds all effects that are applied to all TacticalEntities.

In both of the examples above, adhering to the Single Responsibility Principle drove me to make decisions which keep my code more concise and maintainable. Any time you hear yourself saying you can use a single class to do multiple different things, you should ask yourself if it would work better split into separate responsibilities.

I haven’t done an AOE ability yet, but that is all about targetting and figuring out which entities to apply effects to outside of the whole ability/effect/manager classes as described above. Without rambling any further, here is the code as it stands right now:

BasicAbility.cs:

    public class BasicAbility : IAbility
    {
        public BasicAbility(List effects)
        {
            Effects = effects;
        }

        public void execute(TacticalEntity source, List destination)
        {
            foreach (TacticalEntity entity in destination)
            {
                execute(source, entity);
            }
        }

        public void execute(TacticalEntity source, TacticalEntity destination)
        {
            Projectile projectile = Factories.ProjectileFactory.CreateNew();
            projectile.Position = source.Position;
            projectile.SourceEntity = source;
            projectile.TargetEntity = destination;
            projectile.SpriteAnimate = true;
            projectile.Ability = this;
        }

        public List Effects
        {
            get;
            private set;
        }
    }

AbilityEffect.cs:

    public class AbilityEffect : IAbilityEffect
    {
        private bool ConstantEffectsApplied = false;

        public AbilityEffect()
        {
            ConstantEffectsApplied = false;
        }

        public AbilityEffect(bool tickImmediately, int healthPerTick, int speedEffect, int defenseEffect, float aggroRadiusEffect, int strengthEffect, int totalticks, string name)
        {
            TickImmediately = tickImmediately;
            HealthEffectPerTick = healthPerTick;
            SpeedEffectWhileActive = speedEffect;
            DefenseEffectWhileActive = defenseEffect;
            AggroRadiusEffectWhileActive = aggroRadiusEffect;
            StrengthEffectWhileActive = strengthEffect;
            TotalTicks = totalticks;
            Name = name;
            ConstantEffectsApplied = false;
        }

        public AbilityEffect(TacticalEntity source, TacticalEntity affectedEntity, IAbilityEffect that)
            : this(that.TickImmediately, that.HealthEffectPerTick, that.SpeedEffectWhileActive, that.DefenseEffectWhileActive, that.AggroRadiusEffectWhileActive, that.StrengthEffectWhileActive, that.TotalTicks, that.Name)
        {
            AffectedEntity = affectedEntity;
            SourceEntity = source;
        }

        public int HealthEffectPerTick
        {
            set;
            get;
        }

        public int SpeedEffectWhileActive
        {
            set;
            get;
        }

        public int DefenseEffectWhileActive
        {
            set;
            get;
        }

        public float AggroRadiusEffectWhileActive
        {
            set;
            get;
        }

        public int StrengthEffectWhileActive
        {
            set;
            get;
        }

        private int _TotalTicks;
        public int TotalTicks
        {
            get
            {
                return _TotalTicks;
            }
            private set
            {
                _TotalTicks = value;
                TicksRemaining = value;
            }
        }

        public int TicksRemaining
        {
            get;
            private set;
        }

        public string Name
        {
            get;
            set;
        }

        public bool Active
        {
            get
            {
                return TicksRemaining > 0;
            }
        }

        public TacticalEntity AffectedEntity
        {
            get;
            set;
        }

        public void ApplyConstantEffects()
        {
            AffectedEntity.strengthEffects += StrengthEffectWhileActive;
            AffectedEntity.defenseEffects += DefenseEffectWhileActive;
            AffectedEntity.speedEffects += SpeedEffectWhileActive;
            AffectedEntity.aggroCircleRadiusEffects += AggroRadiusEffectWhileActive;
        }

        public void RemoveConstantEffects()
        {
            AffectedEntity.strengthEffects -= StrengthEffectWhileActive;
            AffectedEntity.defenseEffects -= DefenseEffectWhileActive;
            AffectedEntity.speedEffects -= SpeedEffectWhileActive;
            AffectedEntity.aggroCircleRadiusEffects -= AggroRadiusEffectWhileActive;
        }

        public void ApplyEffectTick()
        {
            if (!ConstantEffectsApplied)
            {
                ApplyConstantEffects();
                ConstantEffectsApplied = true;
            }
            if (Active)
            {
                AffectedEntity.health += HealthEffectPerTick;
                --TicksRemaining;
            }
        }

        public IAbilityEffect Clone(TacticalEntity source, TacticalEntity entity)
        {
            return new AbilityEffect(SourceEntity, entity, this);
        }

        public TacticalEntity SourceEntity
        {
            get;
            private set;
        }

        public bool TickImmediately { get; set; }
    }

EffectManager.cs:

    public static class EffectManager
    {
        private static Dictionary<TacticalEntity, List> entityEffects = new Dictionary<TacticalEntity, List>(20);
        private static double lasttick = TimeManager.CurrentTime;

        public static void AddEffectsToEntity(TacticalEntity source, TacticalEntity entity, List effects)
        {
            if (!entityEffects.ContainsKey(entity))
            {
                entityEffects.Add(entity, new List(effects.Count));
            }
            foreach (IAbilityEffect effect in effects)
            {
                AddEffectToEntity(source, entity, effect);
            }
        }

        public static void AddEffectToEntity(TacticalEntity source, TacticalEntity entity, IAbilityEffect effect)
        {
            IAbilityEffect newEffect = effect.Clone(source, entity);
            List effects;
            if (!entityEffects.ContainsKey(entity))
            {
                effects = new List(1);
                entityEffects.Add(entity, effects);
            }
            else
            {
                effects = entityEffects[entity];
            }
            effects.Add(newEffect);

            if (newEffect.Active && newEffect.TickImmediately)
            {
                newEffect.ApplyEffectTick();
            }
        }

        public static void Activity()
        {
            if ((TimeManager.CurrentTime - lasttick) > 1.0)
            {
                lasttick = TimeManager.CurrentTime;
                foreach (KeyValuePair<TacticalEntity, List> pair in entityEffects)
                {
                    TickAndRemoveInactiveEffects(pair);
                }
            }
        }

        private static void TickAndRemoveInactiveEffects(KeyValuePair<TacticalEntity, List> pair)
        {
            foreach (IAbilityEffect effect in pair.Value)
            {
                effect.ApplyEffectTick();
            }

            for (int x = pair.Value.Count - 1; x >= 0; --x)
            {
                if (!pair.Value[x].Active)
                {
                    pair.Value[x].RemoveConstantEffects();
                    pair.Value.RemoveAt(x);
                }
            }
        }
    }

And the call to attack another entity:

        public virtual void attack(TacticalEntity attackableEntity)
        {
            if (this.currentAbility != null &&
                this.attackCircle.CollideAgainst(attackableEntity.hitCircle))
            {
                this.currentAbility.execute(this, attackableEntity);                
            }
        }

FlatRedBall game engine

In speaking with Joel Martinez about my most recent game project, we got to the point of talking about finishing a game, and he mentioned something about animation. A friend of mine had developed part of a game engine I had always planned to use which had a pretty intuitive and well laid out library. When I mentioned that to him, he pointed me toward FlatRedBall.com.

I was blown away.

This game engine / framework has it all:

At first I was feeling a bit like using this type of thing would mean that I was giving up something, like I had lost that “cool” factor or some form of virtual street cred. Developing with flatredball would be nothing more than using some tool where you drag and drop a bunch of things and make a game and claim you’re an indie dev; however, I’ve been reading the wiki a little bit here and there today, and I have to say I am over that hump… Joel said it best:

… I felt exactly like that in 2010 … then I got over it and released 3 games last year 🙂

Ok… I’m sold. now to start playing, or finding the time to play!

Update: I’m having a bit of trouble creating a project with “Glue” at the moment, so we’ll see how it pans out.

New game I’ve been working on

Back in the MS-DOS era, I was a PC gamer. One of my favorites was a cult classic called UFO: Enemy Unknown, which introduced the entire X-COM series. I still play it to this day… it has major replay value. The graphics are cheesy, the plot line is vague at best, but the gameplay is so amazing that it keeps me and many fans coming back for more.

I do not want to “remake” the X-COM games at all… I simply love the idea of their gameplay model: geoscape/battlescape. Basically, as described from the Wikipedia page:

The game takes place within two main views: the Geoscape and the Battlescape.[4] Gameplay begins on January 1, 1999, with the player choosing a location for their first base on the Geoscape screen: a global view representation of Earth as seen from space (displaying X-COM bases and aircraft, detected UFOs, alien bases, and sites of alien activity). The player can view the X-COM bases, make changes to them, equip fighter aircraft, order supplies and personnel (soldiers, scientists and engineers), direct research efforts, schedule manufacturing of advanced equipment, sell alien artifacts to raise money, and deploy X-COM aircraft to either patrol designated locations, intercept UFOs, or send X-COM ground troops to a mission (using transport aircraft)….

Gameplay switches to its tactical combat phase whenever X-COM ground forces come in contact with aliens.[4] In the Battlescape screen the player commands his soldiers against the aliens in an isometricturn-based battle. One of three outcomes is possible: either the X-COM forces are eliminated, the alien forces are neutralised, or the player chooses to withdraw. The mission is scored based on the number of X-COM units lost, civilians saved or lost, aliens killed or captured, and the number and quality of alien artifacts obtained. Troops may also increase in rank or abilities, if they made successful use of their primary attributes (e.g. killing enemies). Instead of experience points, the combatants gain points in skills like Psi or Accuracy, a semi-random amount depending on how much of the action they participated in. In addition to personnel, the player may use unmanned ground vehicles, outfitted with heavy weapons and armour but not gaining experience. Recovered alien artifacts can then be researched and possibly reproduced. Captured live aliens may produce information, possibly leading to new technology including psionic warfare.

I am taking this type of game play and introducing a few different concepts (subject to change):

  1. Class specialization – The type of specialization you see in RPG games, referred to sometimes as the “holy trinity” in MMORPG games such as World of Warcraft. In this scenario, you would have something like the following classes:
    • Defender – Charges into combat, drawing the attention of attackers away from others and absorbing attacks. (your tank)
    • Sniper – Fires from a safe distance doing massive amounts of damage by targeting vital spots (ranged dps)
    • Combat Medic – I haven’t figured out how this guy will heal from a distance and make sense. Psionics perhaps? (healer)
  2. Experience points – As missions are completed, experience points are awarded and soldiers will gain levels.
  3. Talent trees – Enhance natural abilities as you progress in levels, choosing to further specialize. Combat medic specializing in close proximity and self preservation, or a tank who wants to go high damage because you’ve hired two medics.

I have always wanted to be able to play X-COM style games on a portable device, so I am targetting Windows Phone 7, but I am doing all development in a PC screen, and abstracting all platform specific elements so it should be fairly easy to market it as a PC game if there is any interest.

I have a history of unfinished prototypes. I don’t want to do that anymore, which is why my 2012 new year’s resolution is to finish this thing. This is one game idea that should hold my attention. There is plenty to do, and I have a solid vision for how the game mechanics will work, give or take a few features. Please leave a comment if you are interested!