Deadlyevilryu's Blog

Trying to become a video game developer

DBP 2010: Update #4

For the past 3 or 4 days I have worked on fixing an annoying frame rate issue that has been plaguing my game.  After some looking over my code and getting some help from the xna community I have the problem contained for now.  So far the game is looking pretty good, and I have no idea what game modes will be in the game.  I have weapons, enemies, projectiles, and even some level hazards that are in the game.  This game is turning out to be a lot better looking and feeling than the first one that I made.  Starfield Battle 2 will be a better game to play.  Maybe it will be harder maybe not.  I know so far that there will be multiple levels to play on, but I still don’t know if there will be any multiplayer.

In order to make the game even better I would like to know from anyone reading this post.  If you have played StarFiled Battle I would like to know 3 things

  1. What did you like about it? (If anything)
  2. What didn’t you like about it? (If anything)
  3. What could have been done to make it more playable and fun.

any feedback would be very helpful and I don’t care if it sounds mean I can take criticism.  If you think that the game sucks go right ahead and tell me.  Be honest you don’t have to spare my feelings or anything.  So leave a comment if you like.

January 29, 2010 Posted by deadlyevilryu | Dream Build Play, XNA | | No Comments Yet

DBP 2010: Update #3

I just finished porting the prototype of StarField Battle 2 to the 360 and so far everything is working great.  There is still a framerate issue that I am trying to fix,  The controls still need a little smoothing out, and then I can start working on adding all the features that I sould have put in the first StarField Battle.  I’m not sure if I want multiplayer or not, but it is a possibility that I will put it in.

January 17, 2010 Posted by deadlyevilryu | Dream Build Play, XNA | | No Comments Yet

DBP 2010: Update #2

For the last fiew weeks I have been really lazy. I haven’t really did any work on my DBP entry, and to make matters worse. My hard drive decided it needed to die on me so I had to reinstall everything and all of my xna projects got trashed. So I have to start over with my DBP entry. The good news is I can start from scrach and make the engine that I used for StarField Battle even better. I will be making a seaqual to StarField Battle and it will be way better. As of now I have a basic engine with the player ship and enemies. I’m thinking of adding in a co-op mode and an arena mode. Other than that I have nothing else to say about my DBP project.

January 5, 2010 Posted by deadlyevilryu | Dream Build Play, XNA | | 1 Comment

DBP 2010: Update #1

OK today I’m working on the single player component of my DBP entry.  I’m still thinking that this entry will be a sequel to my first game StarField Battle.  If it is then I think its going to be way better than StarField Battle is, and I am hoping that it will be.  What I am working on today is enemy placement and movement patterns.  each enemy will have the own unique movement pattern and placement in the game world.  I’m not sure if the placement will be random or depend on where the players position is in the game world.  I am hoping to have the prototype of the single player mode done by Sunday.

December 11, 2009 Posted by deadlyevilryu | Dream Build Play, XNA | | No Comments Yet

Dream Build Play 2010

A lot of people know about the DBP 2010 contest that started yesterday, but they didn’t announce it until today. I’m thinking of making a sequel to the game I entered in the last one. So I will be posting about my progress if I make any for the next 4 months. Wish me luck, and if anyone else that is reading this is entering Good Luck.

December 9, 2009 Posted by deadlyevilryu | XNA | | No Comments Yet

XNA 2D HLSL Tutorial 1: Part 4

Ok This is the final part of the 2D HLSL tutorial 1.  Hopefully you have not been confused by any of the code that I showed you.  So without further delay lets get into what we are doing for this part in the tutorial.  So far I have only showed you how to create a single light with the custom shader.  Here is the fun part what about more than one light.  Well it can be done with few additions to the code we have now.  But there is a problem we are working with pixel shader model 2.0  This limits us to working with maybe 2 or 3 lights.  Its not bad if you only need 2 or 3 lights per scene.  If you use PS 3.0 you can many more lights.  I have experimented with it and I can get about 30 – 50 lights no problem.  If you have a PC that doesn’t support PS 3.0 that’s OK I will only be showing an example of code in PS 2.0, but that doesn’t mean you can’t try and test it on the 360.  It works fine for the 360 if you write your custom effect in PS 3.0. If you don’t have a texture that you can use I have provided a Color Map and Depth map for your use. I should have posted those for use in the earlier post for this tutorial, but I forgot to upload them.

First the code for the pixel shader:

struct Light
{
	float3 position;
	float4 color;
	float power;
};

texture colortexture;
texture normaltexture;

int numberOfLights;
Light lights[3];

float ambient;
float4 ambientColor;

float screenWidth;
float screenHeight;

sampler ColorMap = sampler_state
{
	Texture = <colortexture>;
};

sampler NormalMap = sampler_state
{
	Texture = <normaltexture>;
};

float4 FlatColorPS(float2 texCoords : TEXCOORD0) : COLOR
{
    return ambientColor * ambient;
}

float4 AmbientLightPS(float2 texCoords : TEXCOORD0) : COLOR
{
	float4 base = tex2D(ColorMap, texCoords);

	return (base) + (ambientColor * ambient);
}

float4 CalculateLight(Light light, float4 base, float3 normal,
					float3 pixelPosition)
{
	float3 direction = light.position - pixelPosition;
	float distance = 1 / length(light.position - pixelPosition) * light.power;
	float amount = max(dot(base + normal, normalize(distance)), 0);

	return base * distance * amount * light.color * ambient;
}

float4 DeferredNormalPS(float2 texCoords : TEXCOORD0) : COLOR
{
	float4 base = tex2D(ColorMap, texCoords);
	float3 normal = tex2D(NormalMap, texCoords);

	float3 pixelPosition = float3(screenWidth * texCoords.x,
							screenHeight * texCoords.y,0);

	float4 finalColor = (base * ambientColor * ambient);
	for (int i=0;i<numberOfLights;i++)
	{
		finalColor += CalculateLight(lights[i], base, normal, pixelPosition);
	}

	return finalColor;
}

technique Simple
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 FlatColorPS();
    }
}

technique Colored
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 AmbientLightPS();
    }
}

technique Deferred
{
	pass Pass0
	{
		PixelShader = compile ps_2_0 FlatColorPS();
	}

    pass Pass1
    {
        PixelShader = compile ps_2_0 DeferredNormalPS();
    }
}

Ok so what is so different from the last custom effect is we have added in a light structure so that we can keep track of multiple lights. We added a CalculateLight function/Method (Whatever you want to call it.) This will calculate the distance, direction, and amount of light that is generated by each light. Then it will return the base color of the pixel the light is hitting *the distance of the light from the pixel * the amount of light * the color of the light * the ambient factor. Each light will keep track of its own power, position, and color. So now lets move on to the game code.

First we need to create a class for the lights

namespace lightDemo2
{
    public class Light
    {
        public Vector3 position;
        public Vector4 color;
        public float power;

        internal void UpdateEffect(EffectParameter effectParameter)
        {
            effectParameter.StructureMembers["position"].SetValue(position);
            effectParameter.StructureMembers["color"].SetValue(color);
            effectParameter.StructureMembers["power"].SetValue(power);
        }
    }
}

Ok so the only thing that you need to know about here is the UpdateEffect Method. We will be passing in a EffectParameter so that we can manipulate the Light in the custom effect file. So for example if we call effectParameter.StructureMembers["position"].SetValue(position); this will pass in the position of the light to the pixel shader.

Ok now we add code to the game class.

RenderTarget2D gameRT;
RenderTarget2D normalRT;

Effect effect;
EffectParameter lightParameter;

Texture2D colorTexture;
Texture2D normalTexture;

int currentLight = 0;
Light[] lights = new Light[3];

KeyboardState oldState;

Ok so we have some know variables that we are adding. We are now going to use an int called currentLight to keep track of what light we will be updating the position and power for. Also we will be using a Light array called lights and we will set the size to 3.

In the LoadContent Method add:

effect = Content.Load<Effect>("CustomEffect");

colorTexture = Content.Load<Texture2D>("cloud");
normalTexture = Content.Load<Texture2D>("cloud_depth");

lights[0] = new Light();
lights[0].position = new Vector3(20, 30, 0);
lights[0].power = 50f;
lights[0].color = new Vector4(1, 0, 0, 1);

lights[1] = new Light();
lights[1].position = new Vector3(300, 300, 0);
lights[1].power = 50f;
lights[1].color = new Vector4(0, 1, 0, 1);

lights[2] = new Light();
lights[2].position = new Vector3(700, 500, 0);
lights[2].power = 50f;
lights[2].color = new Vector4(0, 0, 1, 1);

PresentationParameters pp = GraphicsDevice.PresentationParameters;
int width = pp.BackBufferWidth;
int height = pp.BackBufferHeight;
SurfaceFormat format = pp.BackBufferFormat;

gameRT = new RenderTarget2D(GraphicsDevice, width, height, 1, format);
normalRT = new RenderTarget2D(GraphicsDevice, width, height, 1, format);

The only thing that we are adding here is the setting up of the lights.

In the Update Method we will be adding some input code to control the lights.

KeyboardState newState = Keyboard.GetState();

if (newState.IsKeyDown(Keys.Enter) &&
    oldState.IsKeyUp(Keys.Enter))
{
     currentLight++;

     if (currentLight > lights.Length - 1)
         currentLight = 0;
}

if (newState.IsKeyDown(Keys.A))
     lights[currentLight].power -= 5f;
if (newState.IsKeyDown(Keys.S))
     lights[currentLight].power += 5f;
if (newState.IsKeyDown(Keys.Left))
     lights[currentLight].position.X -= 5f;
if (newState.IsKeyDown(Keys.Right))
     lights[currentLight].position.X += 5f;
if (newState.IsKeyDown(Keys.Up))
     lights[currentLight].position.Y -= 5f;
if (newState.IsKeyDown(Keys.Down))
     lights[currentLight].position.Y += 5f;

oldState = newState;

Now finally The Draw Method:

GraphicsDevice.Clear(Color.CornflowerBlue);

RenderNormalTarget();
RenderGameTarget();

GraphicsDevice.SetRenderTarget(0, null);
GraphicsDevice.Clear(Color.Black);

effect.CurrentTechnique = effect.Techniques["Deferred"];
effect.Parameters["screenWidth"].SetValue(GraphicsDevice.Viewport.Width);
effect.Parameters["screenHeight"].SetValue(GraphicsDevice.Viewport.Height);
effect.Parameters["colortexture"].SetValue(gameRT.GetTexture());
effect.Parameters["normaltexture"].SetValue(normalRT.GetTexture());
effect.Parameters["ambient"].SetValue(0.01f);
effect.Parameters["ambientColor"].SetValue(new Vector4(1, 1, 1, 1));
effect.Parameters["numberOfLights"].SetValue(lights.Length);

lightParameter = effect.Parameters["lights"];
for (int i = 0; i < lights.Length; i++)
{
     Light l = lights[i];
     l.Update(lightParameter.Elements[i]);
}

foreach(EffectPass pass in effect.CurrentTechnique.Passes)
{
     spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
     effect.Begin();
     pass.Begin();
     spriteBatch.Draw(gameRT.GetTexture(), Vector2.Zero, Color.White);
     spriteBatch.End();
     pass.End();
     effect.End();
}

Ok so now if you run the code you should be able to use the arrow keys to more a light, space to change lights, and A/Z to change a lights power. OK now that I have shown you how to do 2D lighting with deferred normal mapping you can do all sorts of things. Go nuts, and use your imagination to come up with some cool game concepts, or just create a really cool 2D scene for a level in your game.

If you found this helpful leave a comment, or tell me what I could do to make any tutorials that I do in the future helpful to you.

November 20, 2009 Posted by deadlyevilryu | XNA | | 6 Comments

XNA 2D HLSL Tutorial 1: Part 3

Ok so in the last post that I wrote.  I showed you how to apply a texture that you loaded into your XNA project, and apply a custom shader to that texture.  Then display that texture to a render target.  This time we will be rendering a light so we can have some cool effects.  You can use it for all types of things like having a character walk through a dungeon that is only lit by candle light, give a 2D scene a cool lit backdrop, ect.  Ok first we start with the custom shader from last time,  but with some added code.

texture colortexture;
texture normaltexture;

float ambient;
float4 ambientColor;

float3 lightPosition;
float4 lightColor;
float lightPower;

float screenWidth;
float screenHeight;

sampler ColorMap = sampler_state
{
 Texture = <colortexture>;
};

sampler NormalMap = sampler_state
{
 Texture = <normaltexture>;
};

float4 FlatColorPS(float2 texCoords : TEXCOORD0) : COLOR
{
 return ambientColor * ambient;
}

float4 AmbientLightPS(float2 texCoords : TEXCOORD0) : COLOR
{
 float4 base = tex2D(ColorMap, texCoords);

 return (base) + (ambientColor * ambient);
}

float4 DeferredNormalPS(float2 texCoords : TEXCOORD0) : COLOR
{
 float4 base = tex2D(ColorMap, texCoords);
 float3 normal = tex2D(NormalMap, texCoords);

 float3 pixelPosition = float3(screenWidth * texCoords.x,
 screenHeight * texCoords.y,0);

 float3 direction = lightPosition - pixelPosition;
 float distance = 1 / length(lightPosition - pixelPosition) * lightPower;
 float amount = max(dot(base + normal, normalize(distance)), 0);
 lightColor *= lightPower;

 float4 finalColor = (base * ambientColor * ambient) +
 (base * distance * amount * lightColor * ambient);

 return finalColor;
}

technique Simple
{
 pass Pass1
 {
 PixelShader = compile ps_2_0 FlatColorPS();
 }
}

technique Colored
{
 pass Pass1
 {
 PixelShader = compile ps_2_0 AmbientLightPS();
 }
}

technique Deferred
{
 pass Pass1
 {
 PixelShader = compile ps_2_0 DeferredNormalPS();
 }
}

Ok lets go over what was added to the custom effects file.

lightColor is the color of the light that we will create, lightPosition is the current position of the light, and lightPower is going to let us set how much light will be generated.

The DeferredNormalPS works like this.  Fist we get the base color for the color map. Then the color for the normal map.  Get the positi0n of the pixels in the texture.  Get the direction of the light by subtracting the light position from the pixel position. (We have no real direction since the light will be going from the position of the light outward, but we still need it.)  The distance of the light is 1 / length(lightPosition – pixelPosition) * lightPower.  We get the amount of light by getting the max of dot(base color * normal color) and 0.  To keep the color of the light bright we multiply it by the light power.  Now the final color we will get comes in two parts

  1. base color * ambient color * ambient.
  2. base color * distance * amount * light color * ambient

Then we add the two parts together to get the final color that will be the output for the custom shader.  So now we add some stuff to the game project.

First we declare some variables.

RenderTarget2D gameRT;
RenderTarget2D normalRT;

Effect effect;

Texture2D colorTexture;
Texture2D normalTexture;

Vector3 lightPos;
float lightPow = 10f;

Most of this you have seen. The only new stuff is the normalRT, normalTexture, lightPos, and lightPow.  With that in place we move on to the loadContent Method

effect = Content.Load<Effect>("CustomEffect");

colorTexture = Content.Load<Texture2D>("circuit_board");
normalTexture = Content.Load<Texture2D>("circuit_board_depth");

PresentationParameters pp = GraphicsDevice.PresentationParameters;
int width = pp.BackBufferWidth;
int height = pp.BackBufferHeight;
SurfaceFormat format = pp.BackBufferFormat;

gameRT = new RenderTarget2D(GraphicsDevice, width, height, 1, format);
normalRT = new RenderTarget2D(GraphicsDevice, width, height, 1, format);

Here the only new code is the loading of the normalTexture and creating the normalRT.

Now we have to create a Method to render the normalRT

private void RenderNormalTarget()
{
       GraphicsDevice.SetRenderTarget(0, normalRT);
       GraphicsDevice.Clear(Color.TransparentBlack);

       spriteBatch.Begin();
       spriteBatch.Draw(normalTexture, Vector2.Zero, Color.White);
       spriteBatch.End();
}

This Method looks just like the RenderGameTarget Method. Pretty simple stuff. Now to finish off the Draw Method. Your Draw Method should look like this

GraphicsDevice.Clear(Color.CornflowerBlue);

RenderNormalTarget();
RenderGameTarget();

GraphicsDevice.SetRenderTarget(0, null);
GraphicsDevice.Clear(Color.Black);

effect.CurrentTechnique = effect.Techniques["Deferred"];
effect.Parameters["screenWidth"].SetValue(GraphicsDevice.Viewport.Width);
effect.Parameters["screenHeight"].SetValue(GraphicsDevice.Viewport.Height);
effect.Parameters["colortexture"].SetValue(gameRT.GetTexture());
effect.Parameters["normaltexture"].SetValue(normalRT.GetTexture());
effect.Parameters["ambient"].SetValue(0.1f);
effect.Parameters["ambientColor"].SetValue(new Vector4(1, 1, 1, 1));
effect.Parameters["lightPosition"].SetValue(lightPos);
effect.Parameters["lightColor"].SetValue(new Vector4(1, 1, 1, 1));
effect.Parameters["lightPower"].SetValue(lightPow);

foreach(EffectPass pass in effect.CurrentTechnique.Passes)
{
           spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
           effect.Begin();
           pass.Begin();
           spriteBatch.Draw(gameRT.GetTexture(), Vector2.Zero, Color.White);
           spriteBatch.End();
           pass.End();
           effect.End();
}

Ok now if you want you can add this code to your Update Method so you can see the light in action

lightPos = new Vector3(Mouse.GetState().X, Mouse.GetState().Y, 0);

if (Mouse.GetState().LeftButton == ButtonState.Pressed)
       lightPow -= 0.5f;
 if (Mouse.GetState().RightButton == ButtonState.Pressed)
       lightPow += 0.5f;

November 19, 2009 Posted by deadlyevilryu | Uncategorized | | No Comments Yet

XNA 2D HLSL Tutorial 1: Part 2a

I forgot to include the code for the custom effects file in the last post.  LOL :) anyway.  The only thing that we are adding here is we are returning a base color added to the ambientColor * ambient.  See its really simple and easy to code.

texture colortexture;

float ambient;
float4 ambientColor;

sampler ColorMap = sampler_state
{
 Texture = <colortexture>;
};

float4 AmbientLightPS(float2 texCoords : TEXCOORD0) : COLOR
{
 float4 base = tex2D(ColorMap, texCoords);

 return (base) + (ambientColor * ambient);
}

technique Colored
{
 pass Pass1
 {
 PixelShader = compile ps_1_1 AmbientLightPS();
 }
}

November 19, 2009 Posted by deadlyevilryu | XNA | | No Comments Yet

XNA 2D HLSL Tutorial 1: Part 2

In my last post I showed how to use a custom fx file to apply a pixel shader to a render target.  This time I will show how to add in a texture that will be loaded in and apply the pixel shader to that texture.  If you read my last post you may have noticed a Texture2D field called colorTexture.  This will be the texture that is rendered to the render target and displayed on screen with the ambient lighting.  So first lets get that texture into the project

You can just add this to your loadContent Method.

 

colorTexture = Content.Load<Texture2D>("circuit_board");

 

Next in the RenderGameTarget Method in between the spritebatch.begin and spritebatch.end calls add.

spriteBatch.Draw(colorTexture, Vector2.Zero, Color.White);

 

This will draw our colorTexture and any other texture that is placed in RenderGameTarget method to the render target.

Next in the Draw Method if you haven’t added it in.

effect.CurrentTechnique = effect.Techniques["Colored"];
effect.Parameters["colortexture"].SetValue(gameRT.GetTexture());

First change the effect.CurrentTechnique to Colored.  We will add that in the custom shader in a minute.  and set the colortexture in the shader to gameRT.GetTexture.  This will pass in the game render target to the custom shader.  So now you have a texture being blended with your ambient and ambientColor.  Also you can add as many textures as you want to the RenderGameTarget, and they will all get blended properly.  This post is kind of short, and I could have added this part in the last post, but I didn’t think about it.  next time we will be adding in lighting with deferred normal mapping.

November 19, 2009 Posted by deadlyevilryu | XNA | | 1 Comment

XNA 2D HLSL Tutorial 1: Part 1

Someone asked me about documentation that would help them learn how to do 2d lighing in xna.  When I learned how to do the lighting I had to find out how to do most of that myself.  I did find this helpful.  Nick Gravelyn’s Deferred Normal Mapping Tutorial

I’m not going to go into how a pixel shader or any of the code works.  IMO its really simple once you start to understand it a bit.  So first the simple stuff.

I will start with the effect file.  I called mine CustomEffect.FX you can call yours whatever you want.

texture colortexture;

float ambient;
float4 ambientColor;

sampler ColorMap = sampler_state
{
	Texture = <colortexture>;
};

float4 FlatColorPS(float2 texCoords : TEXCOORD0) : COLOR
{
    return ambientColor * ambient;
}

technique Simple
{
    pass Pass1
    {
        PixelShader = compile ps_1_1 FlatColorPS();
    }
}

What this pixel shader will do is tint your screen a color that is provided to the pixel shader by the ambientColor and multiply it by the ambient power. so if you ambientColor = Vector4(1,1,1,1) and your ambient = 0.5f the screen will be grey.

Next we add it to the game.

Here is the game code.

RenderTarget2D gameRT;

Effect effect;

Texture2D colorTexture;

We will be rendering a texture to a Render Target so that way it will be easy to add other effects later if you want to.

in your LoadContent Method add:

effect = Content.Load<Effect>("CustomEffect");

PresentationParameters pp = GraphicsDevice.PresentationParameters;
int width = pp.BackBufferWidth;
int height = pp.BackBufferHeight;
SurfaceFormat format = pp.BackBufferFormat;

gameRT = new RenderTarget2D(GraphicsDevice, width, height, 1, format);

This will load your effect file and create your Render Target, and set the render target to the screens width, height, and surface format.

private void RenderGameTarget()
{
GraphicsDevice.SetRenderTarget(0, gameRT);
GraphicsDevice.Clear(Color.TransparentBlack);

spriteBatch.Begin();
spriteBatch.Draw(colorTexture, Vector2.Zero, Color.White);
spriteBatch.End();
}

This method will be where you place all your texture that will be drawn onto the screen right now we have none, but that’s OK.

In your Draw Method Add

GraphicsDevice.Clear(Color.CornflowerBlue);

RenderGameTarget();

GraphicsDevice.SetRenderTarget(0, null);
GraphicsDevice.Clear(Color.Black);

effect.CurrentTechnique = effect.Techniques["Colored"];
effect.Parameters["colortexture"].SetValue(colorTexture);
effect.Parameters["ambient"].SetValue(0.4f);
effect.Parameters["ambientColor"].SetValue(new Vector4(0, 0, 1, 1));

foreach(EffectPass pass in effect.CurrentTechnique.Passes)
{
     spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
     effect.Begin();
     pass.Begin();
     spriteBatch.Draw(gameRT.GetTexture(), Vector2.Zero, Color.White);
     spriteBatch.End();
     pass.End();
     effect.End();
}

First we clear the GraphicsDevice to a Color then we render the textures to be drawn.  Next we set the render target to null and clear the GraphicsDevice again.  After that is done we set our effect parameters to pass in the ambientColor you ambient to the effect file then we loop through the effect passes in the effect file and draw the render target for the game sprites.  Right now all it shows is a blank screen with a flat color.  For example if you have a ambientColor of Vector4(1,0,0,1) and set ambient to 1f your screen will be red.

Next time I will show how to add textures to the screen.  I hope this helps you out with your graphics programing.  It took me a few days to learn how to do this, and I think It helped me a lot.

November 19, 2009 Posted by deadlyevilryu | XNA | | No Comments Yet