Thursday, December 5, 2013

Unity Tutorial: Find the edges of the screen.

Recently I have been working on a 2D project in Unity. I came across a problem where I wanted the player to move a square on screen but not have the square disappear off the edges of the screen. It took a while to figure it out but eventually I managed to do it. I'm posting here in case anyone else come across this problem.

In this project you should set up a camera and an object you want the player to be able to move. Create a script and attach it to the object you want to move and open the script.

The first this we do is add the following line to the update method.
Vector3 screenPosition =
Camera.main.WorldToViewportPoint(transform.position);
view raw Player.cs hosted with ❤ by GitHub
Here we pass in the transform of the moving object. ScreenPosition will contain values for the x, y, and z position of the object. These values will range from between 0 to 1. I found it easier to work with pixels so that's what we will convert it to now.
float posX = screenSpace.x * maxX;
float posY = screenSpace.y * maxY;
view raw Player.cs hosted with ❤ by GitHub
Next we need to find the width and height, in pixels, of the screen.
float maxX = Screen.width - pixelWidth;
float maxY = Screen.height - pixelWidth;
view raw Player.cs hosted with ❤ by GitHub
That's all the data we need to make sure the object always stays on screen. The next thing you need to do is check player input and then if the objects transform.position + movementSpeed is less that maxX/maxY and greater that 0.

Monday, December 2, 2013

Find the maximum screen resolution in Monogame or XNA

There are many ways to find the max screen resolution in XNA, however many of these do not work with Monogame. After some experimentation I have managed to find one that does.

GraphicsDevice.DisplayMode.Width;
GraphicsDevice.DisplayMode.Height;
view raw Settings.cs hosted with ❤ by GitHub
The lines of code above should give you the actual width and height of the screen in pixels.

Saturday, January 26, 2013

Random 2D Terrain in XNA

I've been messing around with xna again recently after a brief spell with the UDK. I have been a long time fan of Terraira and was wondering how they managed to create the random terrain for their game. I searched around and came across this. The midpoint displacement algorithm. I tried doing this for a while to no avail. I was confident that I could get it to work given enough time however since going back to college I have very little time for side projects. This got me thinking, there had to be an easier way to do this. Instead of starting off with one line and then breaking it up into smaller and smaller ones, why not just start off small and use a similar technique to randomise the height of the next small line. This was the result.
The white line is the random terrain. I started off by stating the total map width. This is in pixels. Then I stated how detailed I want the map by giving a total number of points to be generated. I then  calculated how far apart the points should be by dividing the width in pixels by the number of points. I then generated the first line. I used the end point of the first line as the start point of the next line and generated a random height for the end point of that line within a certain predetermined range. Repeat this for as long as you want and you get the result above. It is also possible to get a better result by increasing the random height range.
The result is kinda cool. I may post source code someday but for now I will continue my experiments.

Update: As requested here is the source code.

Friday, January 25, 2013

XNA Tutorial:2D Shooting Part 2

A while ago I created a tutorial for shooting bullets out of a rocket in nay direction. The method used, while functional, is not very re-usable. In this tutorial we are going to re-factor the previous shooting tutorial. It is recommended that you finish this previous tutorial as we will be using that project.

Firstly you need to create a new game component. Call it ProjectileManager. This will be the place where we will manage our bullets.
public class ProjectileManager : DrawableGameComponent
You need to ensure that instead of just inheriting from Microsoft.Xna.Framework.GameComponent change it to DrawableGameComponent as this will allow us to add a draw method to this game component.

You must then add a draw method to the game component just like the following.
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
}
In here we will draw our bullets.

Next we will add a few variables and instantiate them in the constructor.
static List<Bullet> bullets = new List<Bullet>();
static Texture2D playerBulletTexture;
SpriteBatch spriteBatch;
public ProjectileManager(Game game, SpriteBatch spriteBatch)
: base(game)
{
game.Components.Add(this);
playerBulletTexture = game.Content.Load<Texture2D>("Bullet");
this.spriteBatch = spriteBatch;
}
As you can see, the list of bullets and the texture are both static. This is because we will be referencing them later is a static method. I'll explain further later.

Now we need to add an enum for bullet types. Enums are types that allow you to assign names to integer values. Add the following line to Bullet.cs file. Add is so that it is outside the bullet class.
public enum BulletType { Player, Enemy }
public class Bullet
{
view raw Bullet.cs hosted with ❤ by GitHub
Next we will need to add a new property to the bullet class. This will be of type BulletType. We will need this if at some point in the future we create enemies that are capable of shooting back at the player.
public BulletType Type { get; set; }
view raw Bullet.cs hosted with ❤ by GitHub
With this new property we will need to modify the constructor for the bullet class. We need to add a new parameter for the bullet type. Modify the constructor so it looks like this:
public Bullet(Texture2D texture, Vector2 position, Vector2 direction, float speed, int activeTime, BulletType type)
{
this.DrawTexture = texture;
this.Position = position;
this.Direction = direction;
this.Speed = speed;
this.ActiveTime = activeTime;
this.Type = type;
this.TotalActiveTime = 0;
}
view raw Bullet.cs hosted with ❤ by GitHub
Go back to the ProjectileManager. The next thing we need to do is add a public static method to add a new bullet to the bullet list. A public static method allows us to be able to access this method anywhere in the code. In this case by just typing ProjectileManager.AddBullet(methodParameters). Create a new method and make sure it looks like the following code.
public static void AddBullet(Vector2 position, Vector2 direction, float speed, int activeTime, BulletType type)
{
bullets.Add(new Bullet(playerBulletTexture, position, direction, speed, activeTime, type));
}
Next we need to be able to update the bullets in the projectile manager. We have pretty much already written this code in the rocket class all you really need to do is cut and paste the bullet update loop code over to the update loop of the projectile manager. Within the update for the projectile manager you should have to following code.
for(int i = 0; i < bullets.Count; i++)
{
bullets[i].Update(gameTime);
if (bullets[i].TotalActiveTime > bullets[i].ActiveTime)
bullets.RemoveAt(i);
}
Make sure you have also removed this code from the rocket class.

The exact same needs to be done for the drawing loop. Cut and paste the bullet drawing loop from the rocket class to the projectile manager draw method. The following code should now be in your draw method for the projectile manager.
foreach (Bullet b in bullets)
{
b.Draw(spriteBatch);
}
Before we continue make sure you no longer have code in the rocket class for updating and drawing bullets. You may also remove the list of bullets and bulletTex from the rocket class. You must also remove the bulletTex parameter from the rocket constructor and any other bulletTex code from the constructor. The constructor should now look like the following.
public Rocket(Texture2D texture, Vector2 position, Vector2 direction, float rotation, float Speed)
{
this.DrawTexture = texture;
this.Position = position;
this.Direction = direction;
this.Rotation = rotation;
this.Speed = Speed;
this.IsShooting = false;
}
view raw Rocket.cs hosted with ❤ by GitHub
next we need to use the new method we created in the ProjectileManager class. The rocket update method should now look like this:
public void Update(GameTime gameTime)
{
this.Position += Direction * Speed;
if (IsShooting)
{
shotTimer += gameTime.ElapsedGameTime.Milliseconds;
if (shotTimer > timeBetweenShots)
{
shotTimer = 0;
ProjectileManager.AddBullet(this.Position, this.Direction, 12, 2000, BulletType.Player);
}
}
}
view raw Rocket.cs hosted with ❤ by GitHub
You may have notices that if you build your project you are still getting a few errors. We will work on fixing these next.

Go to the Game1 class. Go to the load content method to where we are instantiating the rocket. Remove the parameter for the bullet texture. It should now look like this.
rocket = new Rocket(
Content.Load<Texture2D>("rocket"),
new Vector2(200, 200),
Vector2.Zero,
0f,
0f);
view raw Game1.cs hosted with ❤ by GitHub
Next just above this line of code, still within the load content method, Create a new instance of the projectile manager.
ProjectileManager pj = new ProjectileManager(this, spriteBatch);
view raw Game1.cs hosted with ❤ by GitHub
Now go down to the draw method in the Game1 class and move the spritebatch.end so that is appears after the base.Draw(). We do this to allow our projectile manager to draw with the same spritebatch. The base.Draw() updated the draw method of all the game components.

You should now be able to run the game. You may have noticed that the bullets are being drawn on top of the rocket. To fix this go back to your code. We must change the draw order. Go to the bullet class and to the draw method. change the last parameter to be less that 1.0f. I put it to 0.8f.
spriteBatch.Draw(
DrawTexture,
Position,
null,
Color.White,
0f,
new Vector2(
DrawTexture.Width / 2,
DrawTexture.Height / 2),
1.0f,
SpriteEffects.None,
0.8f);
view raw Bullet.cs hosted with ❤ by GitHub
Then go to the Game1 draw method and modify the spritebatch.begin method to look like the following.
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
view raw game1.cs hosted with ❤ by GitHub
Now run the game and it should work perfectly.

Now the code is set up in such a way as to allow us to add enemies at some stage in the future. If you see any typos or mistakes please let me know.

Here is the source for the finished project.