I moved to a new URL! Check it out!

posts tagged with: csharp

Dev Log: RPG and YAML Stuff

Dev Log: RPG and YAML Stuff
With the move to Denver pretty much complete I've gotten back into some sort of groove of working on stuff, but I guess my brain must've been pretty scrambled with this sudden weather change because now I'm taking some time to work on a completely different project again!

This is actually a project I've worked on here and there over the past year, but I think I finally have narrowed down some ideas in my head on more of the finer details and that's inspired me to work on it some more.

Without spoiling too much about it: it is some sort of RPG, and it does have some sort of procedural generation element to it. I've been digging into using YAML for the data since I've been looking for something easy to parse and easy to write out. I think the failings of JSON and XML are that it is a giant pain to write out by hand, so YAML seems to be covering that gap quite well.

Here's an example of some of my YAML data:
---
bob:
name: "Bob"
health: 10
money: 5
drop: [null, null, basicattack]
color: ff0000
combat:
- Attack 1
- Attack 1
- [Attack 1, Attack 1, Charge]
- Attack 1
- [Flee, Defend]
- Restart
...

And to parse it in Otter I'm using a library called YamlDotNet. It makes parsing YAML pretty easy but unfortunately it is lacking in documentation and community.

The parsing code for the above data looks like this:
// An enemy class to match the structure of the YAML
public class Enemy : DataObject {
public static string DataPath = Assets.Data.Enemies;

public int Health { get; set; }
public int Money { get; set; }
public List<string> Drop { get; set; }
public List<object> Combat { get; set; }
public string Color { get; set; }
}
...
// A method to load the data from the YAML
enemies = Load<Parsed.Enemy>();
...
// The method to load the data from YAML
static Dictionary<string, T> Load<T>() where T : Parsed.DataObject {
string dataPath = "";
try {
dataPath = (string)Util.GetFieldValue(typeof(T), "DataPath");
}
catch {
throw new Exception(string.Format("No data path found on type {0}", typeof(T)));
}

var dict = DD.Yaml.Deserialize<Dictionary<string, T>>(File.ReadAllText(dataPath));
dict.Each((k, v) => {
v.Id = k;
});
return dict;
}
Normally I would be using my Google Spreadsheet tools for data, but unfortunately spreadsheets break down at a certain point. When my data starts to need more than just scalar values in each field spreadsheets become a pain to use. Basically if I want an enemy to have a list of attacks to perform on the player I have to enter that list into a single cell of a spreadsheet which just doesn't look or feel good.

More updates on this and hopefully Super Sky Sisters coming soon!

Otter Example: Using Components

Otter Example: Using Components
Sometimes when making a video game you can end up with some pretty complicated classes. One way to try to counter act the giant behemoth of code that can easily creep up is to separate some of the functionality into components. In Otter an Entity can have a list of components to run each update.

It can be super useful to put things like movement patterns, weapon systems, health systems, and other stuff into different components and just compose Entities using these various components.

Image


This example goes into detail on how to use components in an Otter project. The example is nearly a game with a player character that can move around and shoot down targets. The example uses components for the movement system that the player uses, keeping track of health, input from the keyboard, using a weapon, and moving bullets fired from the weapon.

This is a pretty complex example compared to the others so far, but I hope it can shed some light on one of the possible ways to organize a bunch of code!

Otter Example: Shaders

Otter Example: Shaders
Welcome to shader town! One of the most exciting things about transitioning from flash to SFML was the use of GLSL shaders! Otter supports all the cool shader stuff that SFML does, and this example covers how to apply shaders to an image.

Check out some really quick example shaders being applied to a cool image of an otter.

Image

uniform sampler2D texture;

void main() {
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
float gray = (pixel.r + pixel.g + pixel.b) / 3;

gl_FragColor = vec4(gray, gray, gray, pixel.a) * gl_Color;
}

Image

uniform sampler2D texture;

void main() {
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);

gl_FragColor = vec4(1 - pixel.r, 1 - pixel.g, 1 - pixel.b, pixel.a) * gl_Color;
}

Image

uniform sampler2D texture;

// A weird way to generate a random number with a vec2 seed I guess.
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

void main() {
vec2 samplePos = gl_TexCoord[0].xy;
samplePos.x += rand(samplePos) * 0.05;
samplePos.y += rand(samplePos) * 0.05;
vec4 pixel = texture2D(texture, samplePos);

gl_FragColor = pixel * gl_Color;
}
Shaders are the best!

Otter Example: Surfaces

Otter Example: Surfaces
Another Otter example has washed ashore. This one deals with understanding how to use Surfaces. Check out the full example right here to see how to make pretty pictures using Surfaces.

Image


Image


Surfaces are essentially just wrappers for a render texture. I like to think of them as canvases that can be drawn to. Otter by default uses one big Surface the size of the game window to render the game. Surfaces can be a great way to add something like a minimap or HUD to your game, or make use of shaders. I often use multiple surfaces when making my games so that I can zoom in and out on the main Surface and keep things on the HUD unaffected by the zooming.

Otter Example: Sound and Music

Otter Example: Sound and Music
Another Otter example coming fresh off the ovens! This one marks the 14th example, and covers playing sound and music using the framework. The full example is right here, and here's a glimpse at the codes:
using Otter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoundStuff {
class Program {
static void Main(string[] args) {
// Create a Game.
var game = new Game("Sound and Music");
// Start the game with a new SoundScene.
game.Start(new SoundScene());
}
}

class SoundScene : Scene {
// Load the sounds into individual Sound objects.
public Sound SoundOne = new Sound("sound1.wav");
public Sound SoundTwo = new Sound("sound2.wav");
public Sound SoundThree = new Sound("sound3.wav");

// Load the music into a Music object.
public Music Music = new Music("music.ogg");

public override void Update() {
base.Update();

// Play sounds for the 1, 2, and 3 keys being pressed.
if (Input.KeyPressed(Key.Num1)) {
SoundOne.Play();
}
if (Input.KeyPressed(Key.Num2)) {
SoundTwo.Play();
}
if (Input.KeyPressed(Key.Num3)) {
SoundThree.Play();
}

// Pause or play the music on the spacebar being pressed.
if (Input.KeyPressed(Key.Space)) {
if (Music.IsPlaying) {
Music.Pause();
}
else {
Music.Play();
}
}

// Adjust the volume of the sounds with up and down keys.
if (Input.KeyDown(Key.Up)) {
Sound.GlobalVolume += 0.02f;
}
if (Input.KeyDown(Key.Down)) {
Sound.GlobalVolume -= 0.02f;
}

// Adjust the volume of the music with left and right keys.
if (Input.KeyDown(Key.Right)) {
Music.GlobalVolume += 0.02f;
}
if (Input.KeyDown(Key.Left)) {
Music.GlobalVolume -= 0.02f;
}
}
}
}
So easy!

Now there's almost nothing holding you back from making a video game using Otter if you so choose. There's still a handful of examples to go, but this one I believe marks the last in the series that is necessary to make a complete thing. Input, graphics, collision, and sound should cover a pretty large portion of making a game, right?

Otter Updates!

Otter Updates!
I've been pretty productive on coding stuff lately so with that comes some updates for Otter! Here's some of the things that have changed or been added lately in the dev branch:

* OgmoProject has a lot more utility methods now like GetValue() and GetLayerData(). If you need to check out level data before actually loading a level into a Scene this can be pretty useful.

* Added OgmoProject.RemapAsset() for when you need to assign a different path for an asset being referenced in your Ogmo projects. For example if you need to take the path of a tilemap from the ogmo project and reassign it to something else when being loaded into the game.

* Fixed a thing that I broke in SetHibox on Entities.

* Util.Clamp now supports Vector2 input and output.

* Added shortcuts to Scene methods like GetEntity<> on Entity just to make code a little bit less verbose at times.

* Added Button.LastPressed and Button.LastReleased. These are both timers that will count up since the last button press and release respectively. Pretty useful for doing input buffering type stuff, or waiting until an input has been released for some amount of time before changing state, and all that kind of stuff.

* Added GetFillRect() to NineSlice.

* Made Debugger.RegisterInstantCommand() public and added Util methods to go along with it. You can now add debug commands that can be used immediately instead of executing them at the next update. Also fixed some bugs in the debugger related to this.

* Fixed the rendering of GridCollider (it was too large by 1 pixel for each cell.)

* Added GetTileIndex() to Tilemap and GetIndex() to TileInfo.

* Texture.CopyPixels now actually works (warning: blittng operations are very slow.)

* More Collider parameter options in all of the Collide, Overlap, etc methods.

* Added Scene.GetEntitiesWith<> which is a weird way to grab a list of Entities that have a specific set of Components. This is probably very slow and should be used sparlingly, but it might be useful to some folk.

* Various small fixes and tweaks that don't really effect end users.