May 082012
 

Things are going to get a little quiet around here as far as XNA is concerned for a little while. I decided the other day that I am going to start looking at Unity and what all I can do with it. So far, I know almost nothing and have done nothing of note, and things might continue that way for a while. Hopefully, as I learn the system I can come up with a couple of write ups and keep this blog up to date!

May 022012
 

In the process of adding my shop, I realized that my item and inventory classes need to have some modifications made. Before we add in the buy and sell sections of the shop, it would be recommended to go ahead and make these changes. Please note that I did some weird things with these while I was troubleshooting, so there are definitely some areas for improvement. What was important to me at the time was that it worked.
The first problem was that every time we would try to buy an item from the shop, it would carry over the actual item class instantiation. What this means is that if you try to buy one, you will actually get however many the vendor has.
Add this to the inventory class to fix this:
Continue reading »

May 012012
 

Now that I have a basic house interior working, the next step is to add a shop to my game. This is something else that turned out to be much easier than I expected. I was able to handle this using additional game states/screens.

First thing, if you didn’t take a look at the game state management link that I posted, go check it out. It’s great and simple. To handle my menu selection, I studied some code around the internet (such as the platformer tutorial) and modified it. First create a new class named menuItem.cs


// 4-10-2012 Converted to automatic properties

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace FarmGame.ScreenManagement
{
    class MenuItem
    {
        public string Text { get; set; }

        public Vector2 Position { get; set; }

        public bool IsSelected { get; set; }

        public ContentManager Content { get; set; }

        public Texture2D Texture { get; set; }

        private bool Textured = false;

        public MenuItem(string text, ContentManager content)
        {
            this.Text = text;
            this.Content = content;
        }

        public MenuItem(string text, ContentManager content, Vector2 position)
        {
            this.Text = text;
            this.Content = content;
            this.Position = position;
        }

        public MenuItem(string text, ContentManager content, Vector2 position, string texture)
        {
            this.Text = text;
            this.Content = content;
            this.Position = position;
            this.Texture = content.Load<Texture2D>(texture);
            Textured = true;
        }

        public void Update(GameTime gameTime)
        {

        }

        public void Draw(SpriteBatch sb)
        {
            if (!Textured)
            {
                SpriteFont font = Content.Load<SpriteFont>(@"Fonts\SpriteFont1");
                Color color = IsSelected ? Color.Yellow : Color.White;
                float scale = IsSelected ? 1.5f : 1.0f;
                Vector2 origin = new Vector2(0, font.LineSpacing / 2);

                sb.DrawString(font, Text, Position, color, 0, origin, scale, SpriteEffects.None, 0);
            }
            else
            {
                Color color = IsSelected ? Color.Yellow : Color.White;

                sb.Draw(Texture, Position, color);
            }
        }
    }
}

This is basically just a text object, though I modified the class so that it can be a textured menu item as well, that is what the overloaded constructor is for.
The draw method basically checks to see if it is a textured sprite and will either draw the texture, or the text.

Before we add in our new game screen, here is my code for my screen class. I have made a few changes from what was done in the tutorial that I followed:


// 4-10-2012 Converted properties to automatic properties

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FarmGame.Inventory;

namespace FarmGame.ScreenManagement
{
    class Screen
    {
        public GraphicsDevice GraphicsDevice { get; set; }

        public String Name { get; set; }
        public Player Player { get; set; }
        public PlayerInventory Inventory { get; set; }

        //public Game Game { get; set; }

        //constructor
        public Screen(GraphicsDevice gd, string name)
        {
            this.Name = name;
            this.GraphicsDevice = gd;
            //this.Game = game;
        }

        public virtual bool Init()
        {
            return true;
        }

        public virtual void Shutdown()
        {
            
        }

        public virtual void Update(GameTime gameTime)
        {
        }

        public virtual void Draw(GameTime gameTime, SpriteBatch sb)
        {
        }
    }
}

The biggest difference from the tutorial is that I am passing in and storing my inventory and player objects here. This way, it is easier to pass them around when going inside my houes, into a shop, into the overworld, etc. Everything else is pretty basic.

Now, we need to add a new gamescreen named Shop


using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using FarmGame.ScreenManagement;
using FarmGame.TileEngine;
//using FarmGame.Tile_Engine2;
using FarmGame.Inventory;
using Microsoft.Xna.Framework.Input;

namespace FarmGame
{
    class ShopScreen : Screen
    {
        public ContentManager Content { get; set; }

        public ScreenManager Screens { get; set; }

        GraphicsDeviceManager Graphics { get; set; }

        GraphicsDevice Device { get; set; }

        private List<MenuItem> Menu = new List<MenuItem>();

        //text handler object to handle all of our text drawing
        public Text TextHandler { get; set; }

        KeyboardState keyState;
        KeyboardState prevState;

        int selectedEntry = 0;

        public ShopScreen(GraphicsDevice device, ContentManager content, ScreenManager screenManager, GraphicsDeviceManager graphics)
            : base(device, "ShopScreen")
        {
            this.Content = content;
            this.Screens = screenManager;
            this.Graphics = graphics;
            this.Device = device;

            //this.menu.Add(new MenuItem(menuTitle, content, new Vector2(200, 200)));
            this.Menu.Add(new MenuItem("Buy", Content, new Vector2(200, 240), @"UI\buyBtn"));
            this.Menu.Add(new MenuItem("Sell", Content, new Vector2(200, 320), @"UI\sellBtn"));
            this.Menu.Add(new MenuItem("Exit", Content, new Vector2(200, 400), @"UI\exitBtn"));

            this.Menu[0].IsSelected = true;
        }

        public override bool Init()
        {
            TextHandler = new Text(this.Content, @"Fonts\SpriteFont1");
            TextHandler.TextColor = Color.Black;

            // keyState = Keyboard.GetState();

            return base.Init();
        }

        public override void Shutdown()
        {
            base.Shutdown();
        }

        public override void Draw(GameTime gameTime, SpriteBatch sb)
        {
            base.GraphicsDevice.Clear(Color.CornflowerBlue);

            sb.Begin();
            foreach (MenuItem mi in this.Menu)
                mi.Draw(sb);

            TextHandler.FontPos = new Vector2(120, 150);
            TextHandler.Output = "Welcome to the shop.";
            TextHandler.DrawText(sb);

            TextHandler.FontPos = new Vector2(TextHandler.FontPos.X, TextHandler.FontPos.Y + 30);
            TextHandler.Output = "What would you like to do?";
            TextHandler.DrawText(sb);

            sb.End();

            base.Draw(gameTime, sb);
        }

        public override void Update(GameTime gameTime)
        {
            prevState = keyState;
            keyState = Keyboard.GetState();

            //move our selection up or down
            if (keyState.IsKeyDown(Keys.Up) && !prevState.IsKeyDown(Keys.Up))
                selectedEntry--;
            else if (keyState.IsKeyDown(Keys.Down) && !prevState.IsKeyDown(Keys.Down))
                selectedEntry++;
            else if (keyState.IsKeyDown(Keys.Enter) && !prevState.IsKeyDown(Keys.Enter))
            {
                if (this.Menu[0].IsSelected)
                {
                    throw new NotImplementedException();
                }
                else if (this.Menu[1].IsSelected)
                {
                    Screens.GoToScreen("SellScreen", Inventory, Player);
                }
                else if (this.Menu[2].IsSelected)
                {
                    Screens.GoToScreen("GameScreen", Inventory, Player);
                }
            }

            //go to the beginning or end of the list
            if (selectedEntry < 0)
                selectedEntry = this.Menu.Count - 1;
            if (selectedEntry == this.Menu.Count )
                selectedEntry = 0;

            foreach (MenuItem mi in this.Menu)
            {
                if (mi == this.Menu[selectedEntry])
                    mi.IsSelected = true;
                else
                    mi.IsSelected = false;

                mi.Update(gameTime);
            }
            base.Update(gameTime);
        }
    }
}

Like usual, i’m not going to explain all the code as it should be pretty simple. What’s important is that we start out with a list of menu items. This is how we will display and select the menu items. Like many of my other tutorials, I am using a custom made text object to handle my non-menu text output.

            this.Menu.Add(new MenuItem("Buy", Content, new Vector2(200, 240), @"UI\buyBtn"));
            this.Menu.Add(new MenuItem("Sell", Content, new Vector2(200, 320), @"UI\sellBtn"));
            this.Menu.Add(new MenuItem("Exit", Content, new Vector2(200, 400), @"UI\exitBtn"));

            this.Menu[0].IsSelected = true;

This code is how we add new menu items and the last line is flagging the first item as selected. If you go back to the first section of code for our menu item class, you can see that if the isSelected boolean is true, the tint of the texture or the color of the font will be different. The update code is pretty basic too. Currently, the buy portion of my shop is not implemented so it throws an appropriate error. Selling takes you to a different screen and exiting takes you back to the game screen. The code does check the selected index and makes sure it is within the bounds of our list. If it goes past, we set it back to 0, if we go below, we set it to the end. That way there is always a menu item selected.

That’s it. You can now have a pretty basic shop. I’m still working on tweaking the code for my “sell shop.” Once this is done I’ll try to get the code posted.

Apr 282012
 

A couple of screenshots to wrap up Saturday. Unfortunately, I did not spend too much time this week coding, but I did get something accomplished at least. This screenshot shows my current overworld.

And this one is what the inside of the house looks like currently. The next steps are to implement a shop, remove the player starting items and make them earn them, and a time cycle of sorts.

Apr 282012
 

I don’t have the time to post any code, but I did want to share a concept I pulled off today that involved walking into a house, which is something that I imagine would be used in pretty much any sort of rpg type game. I’m not sure what the proper way to accomplish this would be, but I handled it using game states/screens. Basically, I created a new game screen called playerhouse. I then put an invisible portal object on my map. Whenever the player collides with this portal, the game screen will switch to the playerhouse screen. I pass in the player and the inventory object so that they player will still have access to their inventory. I’ll see if I can get some code posted tomorrow sometime.

Apr 252012
 

To further build on our tutorials for our basic inventory system, let’s add a basic system to harvest our resources. In my code, I have added a new folder named crafting which I intend to use for anything even remotely crafting related. I then created a new class called Harvesting.cs. Here is the code:


using System;
using FarmGame.Inventory;
using FarmGame.TileEngine;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace FarmGame.Crafting
{
    static class Harvesting
    {
        public static void Harvest(GameObject go, ref PlayerInventory CurrentInventory, ref List<GameObject> objects, ContentManager cm)
        {
            if (go.thisType == GameObject.ObjectType.rock)
               HarvestRock(go, ref CurrentInventory, ref objects, cm);
            if (go.thisType == GameObject.ObjectType.bush)
                HarvestBerryBush(go, ref CurrentInventory, ref objects, cm);
            if (go.thisType == GameObject.ObjectType.tree)
                HarvestTree(go, ref CurrentInventory, ref objects, cm);
        }

        private static void HarvestTree(GameObject g, ref PlayerInventory inventory, ref List<GameObject> objects, ContentManager cm)
        {
            objects.Remove(g);

            inventory.AddItemToInventory(new InventoryItem("wood", 5, cm.Load<Texture2D>(@"Objects\wood"), InventoryItem.InventoryType.craft));
        }

        private static void HarvestBerryBush(GameObject g, ref PlayerInventory inventory, ref List<GameObject> objects, ContentManager cm)
        {
            objects.Remove(g);

            inventory.AddItemToInventory(new InventoryItem("berry", 5, cm.Load<Texture2D>(@"Objects\berries"), InventoryItem.InventoryType.craft));
        }

        private static void HarvestRock(GameObject g, ref PlayerInventory inventory, ref List<GameObject> objects, ContentManager cm)
        {
            objects.Remove(g);

            inventory.AddItemToInventory(new InventoryItem("stone", 2, cm.Load<Texture2D>(@"Objects\stones"), InventoryItem.InventoryType.craft));
        }
    }
}

As per usual, the code should be simple and easy to understand. The one difference here compared to most of my other code is that this is a static class. To put it simply, this means that you do not need to declare a new instance of the class before you call a method, it is loaded in memory when the game launches. Simply just call Harvesting.Harvest, pass in the object you are trying to harvest and the player ineventory. I’m also passing in the list of game objects so that we can handle all object manipulation (such as removing the object from the game) directly from this class.

For my implementation, I am checking for a space key press when it is checking all of my game objects. Here is the relevant code:


if (tileRect.Intersects(Player.fowardBox()))
                {
                    bool harvestable;

                    box.Position = new Vector2(tileRect.X + 5, tileRect.Y + 5);

                    //box.textHandler.Output = "Press space to mine this rock.";
                    box.textHandler.Output = GameObjectDialogue.GetOutput(Inventory.EquippedItem, go, out harvestable);
                    dialogBoxNeeded = true;

                    //check for action key
                    if (keyState.IsKeyDown(Keys.Space) && !prevKeyState.IsKeyDown(Keys.Space))
                    {
                        //add additional code here to return items 
                        if (harvestable)
                        {
                            Harvesting.Harvest(go, ref Inventory, ref GameObjects,CM);                    //this.GameObjects.Remove(go);
                            return;
                        }
                    }
                }

Apr 242012
 

One thing that was important to me in my latest game was to have actual dialog show on the screen. When the player interacts with objects, I want a box to display on the screen to give them immediate feedback. Granted, my implementation makes some basic assumptions and is quite simple, it is working and scaling quite well for me. Here is a basic implementation:


using System;
using FarmGame.Inventory;
using FarmGame.TileEngine;

namespace FarmGame.Dialogue
{
    static class GameObjectDialogue
    {

        static public string GetOutput(InventoryItem item, GameObject go, out bool harvestable)
        {
            harvestable = false;

            if (go.thisType == GameObject.ObjectType.rock)
                return GetRockOutput(item, out harvestable);
            if (go.thisType == GameObject.ObjectType.bush)
                return GetBushOutput(item, out harvestable);
            if (go.thisType == GameObject.ObjectType.tree)
                return GetTreeOutput(item, out harvestable);
            if (go.thisType == GameObject.ObjectType.house)
                return GetHouseOutput(out harvestable);
            
            return string.Empty;
        }

        private static string GetHouseOutput(out bool harvestable)
        {
            harvestable = false;
            return "This is your house.";    
        }

        private static string GetTreeOutput(InventoryItem ii, out bool harvestable)
        {
            if (ii.ItemName == "axe")
            {
                harvestable = true;
                return "Press space to chop this tree.";
            }
            else
            {
                harvestable = false;
                return "You must have the axe equipped.";
            }
        }

        static public string GetRockOutput(InventoryItem ii, out bool harvestable)
        {
            if (ii.ItemName == "pickaxe")
            {
                harvestable = true;
                return "Press space to mine this rock.";
            }
            else
            {
                harvestable = false;
                return "You must have the pickaxe equipped.";
            }
        }

        static public string GetBushOutput(InventoryItem ii, out bool harvestable)
        {
            if (ii.ItemName == "scythe")
            {
                harvestable = true;
                return "Press space to harvest berries.";
            }
            else
            {
                harvestable = false;
                return "You must have the scythe equipped.";
            }
        }
    }
}

I won’t get too into the details as it should be self explanatory. In this case, you are passing in the equipped item and the object you are interacting with. It will then return if the object is harvestable. In my case, I have rocks, bushes, trees, and a house.

Calling it from your code is equally as simple. I have this in the update method of my level class:


            bool dialogBoxNeeded = false;

if (tileRect.Intersects(Player.fowardBox()))
                {
                    bool harvestable;

                    box.Position = new Vector2(tileRect.X + 5, tileRect.Y + 5);

                    //box.textHandler.Output = "Press space to mine this rock.";
                    box.textHandler.Output = GameObjectDialogue.GetOutput(Inventory.EquippedItem, go, out harvestable);
                    dialogBoxNeeded = true;

                    //check for action key
                    if (keyState.IsKeyDown(Keys.Space) && !prevKeyState.IsKeyDown(Keys.Space))
                    {
                        //add additional code here to return items 
                        if (harvestable)
                        {
                            Harvesting.Harvest(go, ref Inventory, ref GameObjects, CM);
                            //this.GameObjects.Remove(go);
                            return;
                        }
                    }
                }

                box.DrawBox = dialogBoxNeeded;

Basically, the player has a seperate bounding box that projects in front of them. We are checking this bounding box to see if it interacts with a game object. If so, we note the position for our box, determine the text, and flag the code as needing a dialog box.

Now we need to call the draw method:


            if (this.box.DrawBox)
                this.box.Draw(sb);

I’m not going to step through it, but here is the box class:


using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Text;
using Microsoft.Xna.Framework.Content;

namespace FarmGame.UI_Elements
{
    class Box
    {
        public Text textHandler { get; set; }
        public Texture2D Texture { get; set; }
        public Vector2 Position { get; set; }
        public bool DrawBox { get; set; }

        //private int TextureWidth { get; set; }
        //private int TextureHeight { get; set; }

        private string Output;
        //StringBuilder sb;

        public Box(ContentManager cm)
        {
            this.Texture = cm.Load<Texture2D>(@"UI\popuptext");

            textHandler = new Text(cm, @"Fonts\boxSpriteFont");
            textHandler.TextColor = Color.White;
        }

        public Box(ContentManager cm, string output, Vector2 coords)
        {
            this.Texture = cm.Load<Texture2D>(@"UI\popuptext");
            this.Output = output;
            this.Position = coords;

            textHandler = new Text(cm, @"Fonts\boxSpriteFont");
            textHandler.TextColor = Color.White;
        }

        public void Draw(SpriteBatch sb)
        {
            sb.Draw(this.Texture, this.Position, null, Color.White );

            textHandler.FontPos = new Vector2(Position.X + 15, Position.Y + 15);
            textHandler.DrawText(sb);
        }
    }
}

Apr 202012
 

So, you’ve started working on a game and have decided that you need an inventory system. What I have found is that this task really doesn’t have to be as difficult as it sounds. The first thing we need to do is create a class that will hold our inventory items.


using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace game.Inventory
{
    class InventoryItem
    {

I’ve created an enum to hold what type of item it is. In my case, I’ve got tools, crafting items, furnitue, etc.

        
//what type of item is it
        public enum InventoryType
        {
            craft,
            consumable,
            furniture,
            tool
        };
        public InventoryType thisType { get; set; }

        //the texture for any tool tips
        public Texture2D Texture { get; set; }

        //the number of the item that you have
        public int NumAvailable { get; set; }
        public string ItemName { get; set; }

        private int MaxQuantity = 99;

Everything else is basic properties and variables and should be pretty self explanatory. Texture is the texture that we will use to draw the icon for the onscreen inventory, numavailable is how many you have, itemname is the name of the item, and maxquantity is the maximum number allowed.

We have an empty constructor, and another one that populates the pertinent fields


        public InventoryItem()
        {
           //empty constructor
        }

        public InventoryItem(string name, int numAvailable, Texture2D texture, InventoryType type)
        {
            this.NumAvailable = numAvailable;
            this.Texture = texture;
            this.thisType = type;
            this.ItemName = name;
        }

Two add methods. One of this simply increments the quantity available and the other increments it by a set amount


        public void AddItems()
        {
            this.NumAvailable++;
            CheckMaxQuantity();
        }

        public void AddItems(int numToAdd)
        {
            this.NumAvailable += numToAdd;
            CheckMaxQuantity();
        }

Then we have our basic draw method and a simple method to make sure we never exceed our maximum quantity.

        public void Draw(SpriteBatch sb, Vector2 position)
        {
            sb.Draw(this.Texture, position, Color.White);
        }

        private void CheckMaxQuantity()
        {
            if (this.NumAvailable > MaxQuantity)
                NumAvailable = MaxQuantity;
        }

That’s it. In the next post, I’ll show how I pulled together the actual inventory class and how I am handling the inventory control, drawing of the ui, etc.

Apr 192012
 

One of the many challenges that I have faced with my new game is to scroll the tiles efficiently. When you do any google search, you will find that the recommended approach is to implement a 2d camera to handle this. Honestly, I looked at several implementations and ran through several tutorials and found all of them to be entirely too complex for what I need. After thinking about it for some time, I was able to come up with an implementation that worked for me. It’s not without it’s flaws, but it works and it is simple: Continue reading »