For the first few weeks in our GSP 420 course me and my group have begun the "production" phase where we're beginning to work on our specified cores; Main framework Core, Graphics Core, and AI & Collision Core based on the class diagrams we've developed for them. To begin the core that I'm in, I started off doing the spriteContainer class and Tile class. The way me and my group wanted our game engine to be was as universal as possible, so the idea I had for the spriteContainer class was to have a storage where we can place Texture2D objects in and whenever we want to grab those images we can just invoke the variable from the class. To start this off as somewhat a template I created various Texture2D variables giving them a getter and setter such as; player, enemy, block1, and exitTile.
public static Texture2D player{get; private set;}
public static Texture2D enemy{get; private set;}
public static Texture2D block1{get; private set;}
public static Texture2D exitTile{get; private set;}
The reasoning for them having a getter and setter is simple, the name says it all. To get the value of the variable and or be able to assign something to the variable. Purposely having the setter private so only the spriteContainer class can assign the variables to something and any other class is inaccessible to doing so. After creating a couple of variables I created a function that loads the content into specified variables called Load(ContentManager content). So at the moment if we invoke these variables outside the class, nothing happens. The purpose of the Load(ContentManager content) is to be able to assign these Texture2D variables to images using XNA's content.Load. In this function I begun assigning these variables to be able to load an image by doing:
player = content.Load<Texture2D>("spriteContainer/player");
enemy = content.Load<Texture2D>("spriteContainer/enemy");
block1= content.Load<Texture2D>("spriteContainer/block1");
exitTile = content.Load<Texture2D>("spriteContainer/exitTile");
What is happening is where assigning Texture2D variables like player, enemy and or exitTile to be able to load .png files (because we're casting Texture2D) from the folder "spriteContainer" and specifying the actual file name. So now when we're outside of this class we can just do spriteContainer.player instead of doing it the long way; content.Load<Texture2D>("spriteContainer/player"); all the time. The best part about this class is considering this is a game engine... For any game speaking, we can just continuously create new variables and add them into the Load function to store them up in the system so we can use them universally. Thus finishes the spriteContainer class....Until we make a game!
After completing the spriteContainer class I decided to tackle down the Tile class. The purpose of the Tile class is simple...It's basically just identifying something to being a Tile in a .txt file. So this tile can be a variable from spriteContainer or just a simple string name with a collision. Now thanks to actually doing a class diagram for the graphics core I know there's going to be an association with Tile and the levelEditor class. So Tile is going to have somewhat a significance in the making. The way I thought of the Tile class was to identify something being a tile and deciding what collision type it was. So to begin this I created an enumeration called collisionType.
enum collisionType{ Passable = 0, Blocked = 1, Platform = 2, Trigger = 3}
The enumeration is pretty straight foward; to determine what collision type a tile has. If a tile has a collision type of passable, on a .txt file the player can pass through it. If the tile is Blocked, the player cannot pass through it. If it is a platform, the player can jump on it but keeping in mind the tile does have bounds. If the tile has a collision type of Trigger then that basically means the tile can cause an event. So this could be an item event for example. After doing this I created a Texture2D object called texture and an object of collisionType called collision. Then to be able to manipulate the size of an image/tile I did
public const int Width = 32;
public const int Height = 32;
public static readonly Vector2D Size = new Vector2D(width,Height);
I did this because in the levelEditor class I know there will be an association occuring in the Draw function where I can place Size in. So if I wanted to change the size of a tile I could always change the value of Width or Height. To continue this I created a simple constructor called;
Tile(Texture2D texture, collisionType collision)
Inside it I basically just assign the variables to eachother:
this.texture = texture;
this.collision = collision;
Doing this completed the Tile class. Now all that's left to complete are four classes; camera, levelEditor, Animate, and Render! Can't wait to begin on the Animate class.
Monday, November 24, 2014
Monday, November 10, 2014
Creating a Game Engine: Class Diagram and Requirements List
So to start this off, I am currently taking GSP 420 which is a course built on creating your own game engine. I have to say, before this class I've been eager in wanting to take this course because I've always wanted to make my own game engine. Into two weeks of the course me and my group have decided to create a game engine based around a platformer where we will be building it off of C# and XNA. The group I have is divided up into three cores; Main Framework Core, Graphics Core, as well as AI and Collision Core. Currently I am a part of the Graphics Core and I'm pretty comfortable with that only because I enjoy working with graphics! So to begin with our Game Engine we made sure to do some analysis planning through creating a class diagram and requirements list specific to our core. Being able to create a class diagram as well as a requirements list is a great way to get an idea of how the core's going to be structured as far as the system goes.
As you can see with the above picture we have quite a few things going on with the graphics core and that's just only the graphics core. Since we want things to be almost pretty universal my thought behind this was to create a class which holds all sprites and this class was called spriteContainer. With this class other classes can just load a texture on screen just by invoking a specific variable such as player or enemy1 such as the levelEditor class. The levelEditor's purpose is actually what the name says, it edit's the levels properties as well as reads .txt files. In this class we can grab textures and set them to be a tile that blocks the players path, or a tile which determines the sprites exit point of a level. After setting up everything as pleased we can just draw all "tiles" based on the level index read and the file streamed. The cool thing with this class is the ability to read .txt files. So let's say we set a certain sprite to have a character of "P". Placing P in a .txt file will actually tell the compiler oh hay this is a platform. As you can see with the picture above there is an association going on with levelEditor and Tile. The purpose of tile is to take in an image from spriteContainer class where you can determine if the image is a platform, has a trigger, is visible or invisible. Now since our game engine is a platformer and we do want to be able to universally have the engine create an animation based off a sprite sheet we created an animation class called Animate, which associates with the spriteContainer class. So in Animate, it will take into account any sprite sheet, create a cell which shifts left or right, as well as determining if the animation loops or not. Now just so I don't get to into detail, it all comes down to the Rendering class. The whole purpose of this class is to Draw, which will draw all tiles based on the level in level editor, as well as render and update the screen coming from ScreenManager. Thus finishes the class diagram for our Graphics Core.
Now it all comes down to the requirements List! I actually enjoy doing the requirements list a lot because it's great to use as a check off sheet such in a way when you begin testing you view your requirements list and see if the system follows all of the requirements. Usually when it comes to creating a requirements list, you want to get as thorough as possible because if there's a bug in your system and it has nothing to do with your requirements then that can go on the programmers fault. So when you look at the requirements list above, it doesn't look as thorough only because this is part of only the graphics core. The way me and my partner did it was pretty organize; labeling things by a requirement I.D as well as giving each description a status so we can use it as a check off sheet. When doing the requirements list, we did try to get as detail oriented as possible so in the instance when we test the engine we can make sure everything is running the way it should.
Graphics Core |
Requirements List |
Overall I'd have to say when it comes to creating some sort of system, whether its a software, program and or game engine...It's probably wise to do some planning before hand rather than diving into the production phase because then you might run into more errors versus if you had plan things out. A great way to actually plan things out can come from creating Class Diagrams, Use Cases, Requirement lists, as well as a Risk Assessment Table.
Tuesday, November 4, 2014
Getting started with FX Composer 2.5
One of the things I enjoy a lot as a programmer is being able to handle things on the Graphics end. This can come from many things such as creating a user interface for games or handling 2D and 3D graphics and implementing them through a game engine or Direct X. Staring this new course excites me because we begin to approach more of the three dimensional aspects of Direct X such as messing with Shaders. One of the things we were first introduced to was something called FX Composer and I'd have to say the professor wasn't lying, it seriously looks like a combination of 3ds Max and a programming language combine together! FX Composer is basically a tool where developers on the graphics end can create or modify shaders through the use of creating an Effect file. The Effect file is then associated with a Direct3D program where a programmer can utilize that shader on a 3D model. With the use of DirectX Standard Annotations and Semantics (DXSAS) programmers are allowed to edit values of Annotations on a "host application" where they can actually modify the shader for their own use. So in other words we can utilize a shader on two different objects and have two different looks to it through tweaking the parameters of annotations.
As you can see with the picture above, this is FX Composer and it really does look like a combination of 3DS max and C++! The middle window is the Editor or where all the programming lies where as the top left window is the material window. The top right window is the propeties window which gives you the properties of a material and the bottom right is the perspective window where you can see a mesh with the shader/material applied to it. So to start this all off, looking at the Phong effect file we can see quite a few things such as Lamp0Pos, Ambient, Bump, Ect. Under these you see annotations such as UIName, UIMin, UIMax and so on. These annotations have values which can be messed with through FX Composer or even through C++ which is great because that means you can dynamically change these values!
So the question you may ask yourself is how do you grab these annotations in C++? Well one way you can do this is through determining the annotations data type and then create a variable with that same data type and another variable which is a handler. So for instance, in this project we worked with the Gooch Bump Shader type. The shader has things where you can change it's warm color and cool color and it's data type dealt with color. So what I did was create four variables of type D3DXCOLOR and D3DXHANDLE and named it warmColor, coolColor, hWarmColor, hCoolColor. In the function where we load the effect file of the shader I grab the two handlers and had them call getParameterByName which took in the names of the semantics. Doing so basically said... okay we're going to assign these handlers to the semantics allowing you to edit their values as you please.
Thus leading me to the Renderer Function where I messed with the parameters setting warmColor to D3DXCOLOR(0.7f, 0.03f, 0.01f, 1.0f) and coolColor to D3DXCOLOR(0.01f, 0.05f, 0.25f, 1.0f). After setting the colors you have to set in the values which then you take into account the handler and the variable which you stored the color. With this I did
m_pEffect->SetValue(hWarmColor, &warmColor, sizeof(D3DXCOLOR));
m_pEffect->SetValue(hCoolColor, &coolColor, sizeof(D3DXCOLOR));
Which gave me the picture below:
For a first assignment I'd have to say this was quite fun and I look foward to what else FX Composer brings to the table!
FX Composer |
Effect Skeleton |
Renderer |
m_pEffect->SetValue(hWarmColor, &warmColor, sizeof(D3DXCOLOR));
m_pEffect->SetValue(hCoolColor, &coolColor, sizeof(D3DXCOLOR));
Which gave me the picture below:
Result |
Subscribe to:
Posts (Atom)