Sunday 8 July 2012

We Control the Horizontal and the Vertical….and that’s about it in 2D



I was looking in on Ziggyware and found this post by noobie01 and so decided to post my ideas on this. Now this is no big solution, it’s just a method to place “units” randomly on the screen and also how to “randomly” move them around.


Random Placement







Now the first part of the post was asking how to place a unit on the screen at a random location. In this sample this is how I am doing it. First thing I do is set up 4 floats to hold the minimum and maximum screen positions that are possible.

// Variables to hold the min and max positions that a "unit" can be placed in.
float minX, minY, maxX, maxY;

Then in the LoadContent method I set them.

// Set the min max values
minX = GraphicsDevice.Viewport.TitleSafeArea.Left + (obj.image.Width / 2);
minY = GraphicsDevice.Viewport.TitleSafeArea.Top + (obj.image.Height / 2);
maxX = GraphicsDevice.Viewport.TitleSafeArea.Right - (obj.image.Width / 2);
maxY = GraphicsDevice.Viewport.TitleSafeArea.Bottom - (obj.image.Height / 2);

I then randomly set the position of the unit.

// Randomly place the object.
obj.Position = GetRandomPosition();
obj.spriteBatch = spriteBatch;

GetRandomPosition() looks like this:

// Method to generate a random position on the screen.
private Vector2 GetRandomPosition()
{
return new Vector2((float)MathHelper.Lerp(minX, maxX, (float)rnd.NextDouble()),
(float)MathHelper.Lerp(minY, maxY, (float)rnd.NextDouble()));
\\par


Random Movement


The next thing in the post was random movement. As you might have read in the post, I don’t think that this is really what is wanted, but I have done it here any was as a matter of completeness.
In the Update method of the sample, depending on the movement type selected (Default is random movement) I move the unit. So when in random movement the position of the object is altered like this:

case MovementTypes.TotalyRandom:
// Randomly move the object..
obj.Position.X += (float)MathHelper.Lerp(-obj.image.Width, obj.image.Width, (float)rnd.NextDouble());
obj.Position.Y += (float)MathHelper.Lerp(-obj.image.Height, obj.image.Height, (float)rnd.NextDouble());
break;

This is a pretty clumsy movement method and was done out of haste really. A much better way to move any game avatar is by using a velocity which I will cover in a later related post. In fact the BaseDrawable2DObject that is used in this sample is a foundation of this up coming post.

Random Patrol Path







Now I think a much better and maybe useful method is for the unit to follow a patrol path. This is just a number of points on the screen that the unit will move to in turn. Now if you have any sense you will tie this in with your A.I. and depending on the various states you can send the unit to specified points. This is out of the scope of this simple sample, but I am sure you will get what I mean.

Anyway onto the patrol path stuff. We first need a list of patrol points as well as some way of marking what point we want to head for..

// Entities used to represent the patrol points.
List<BaseDrawable2DObject> patrolPoints = newList<BaseDrawable2DObject>();
// This is the next target destination in the patrol points.
int pathTarget = 0;

We now have a list of patrol points and a marker to denote the point we want to be moving to. So our movement code now looks like this:

case MovementTypes.PatrolListPath:
case MovementTypes.PatrolMap:
// Move towards current patrol point..
if (patrolPoints.Count > 0)
{
Vector2 dir = patrolPoints[pathTarget].Position - obj.Position;
dir.Normalize();
obj.Translate(dir * 4);
if(obj.collisionRect.Intersects(patrolPoints[pathTarget].collisionRect))
pathTarget++;
if (pathTarget >= patrolPoints.Count)
pathTarget = 0;
}
break;

I get the direction from the units position to the desired location, normalize it and then move in that direction (the * 4 is there to speed it up a bit). I then check if the unit has arrived at the required destination, if it has I move the pathTarget on one. I then see if my pathTarget is still in the range of the list of patrol points and if it is beyond that I set it back to 0.

To set the patrol path up I use the following method:

// Method to generate a random patrol path.
private void GenerateRandomPatrolPath()
{
ClearPatrolPoints();
for (int p = 0; p < rnd.Next(4, 8); p++)
{
BaseDrawable2DObject point = new BaseDrawable2DObject(this, "Textures/box");
point.ForeColor = Color.Gold;
point.Enabled = true;
point.Scale = .5f;
point.Position = GetRandomPosition();
point.spriteBatch = spriteBatch;
Components.Add(point);
patrolPoints.Add(point);
}
}

What this does is clear out the old list, then populate the list with between 4 to 8 patrol points, each point being randomly placed on the screen.


Here is the ClearPatrolPoints() method so you wont think I am over loading the Components collection :)

// Method to clear the patrol points out.
private void ClearPatrolPoints()
{
// Remove any old points
foreach (BaseDrawable2DObject o in patrolPoints)
if (Components.Contains(o))
Components.Remove(o);
patrolPoints.Clear();
}

That is pretty much it, do forgive the clumsy movement mechanism, this was written to show the random position generation and patrol paths. In the next related post I intend to cover simple physics and sprite animation, this may end up being spread over a number of posts.

You can find the solution for this post here

No comments:

Post a Comment