Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Tuesday, December 22, 2009

A very small Chirstmas present from Botworks

Well seeming as I haven't finished any of the projects I am working on yet (more on what they are in the new year) so I can't offer discounts or bonus content. However, I can offer a little something for XNA developers. One of the things that I found most frustrating in XNA was drawing a line, so I created a little function to do just that. It isn't especially clever, but it gets the job done

void drawLine(Texture2D line,int lineWidth,Vector2 startPosition,Vector2 endPosition,SpriteBatch spriteBatch)
{
float length = Vector2.Distance(startPosition, endPosition);
float theta = (float)Math.Atan((double)((endPosition.X - startPosition.X) / (endPosition.Y - startPosition.Y)));
float alpha = (float)(2*Math.PI) - theta;
spriteBatch.Begin();
spriteBatch.Draw(line, new Rectangle((int)startPosition.X, (int)startPosition.Y, lineWidth, (int)length), null, Color.White, alpha, new Vector2(lineWidth/2,0), SpriteEffects.None, 0);
spriteBatch.End();
}
  • line - this a pre-loaded texture2D which is your basic line pixel. It needs to be 1 pixel high. It can be of any width (for example if you want a glowing line) but a standard line is 1 pixel wide
  • lineWidth - unsurprisingly this is the width of the texture loaded in the line property
  • startPosition, endPosition - these vectors are the start and end co-ordinates of the line
  • spriteBatch - this is just the instance of the spriteBatch which, unless you have specifically changed, is just called spriteBatch



And here is a quick demonstration. I am using a 21x1 image file which is just a red pixel in the middle with fading transparencies going out to create something of a laser effect.

Merry Christmas and a happy and productive new year to you all.

Monday, January 26, 2009

Moving in an RTS

In this post I will be discussing the theory behind the code in making a unit move from one location to another. This is not meant to be a complete tutorial, nor ground breaking. In fact, it won't even cover basic path finding. However, if you are having problems making a unit move between two points (namely, they move diagonally and then straight along) read on.

Such a seemingly simple thing, moving a unit between two points in a straight line (ignoring path finding as FK will not have path finding) However,I struggled with it for quite some time.

At first, I thought it would be really simple. See if the X co-ordinate of the object is bigger or smaller than the target X co-ordinate. Then, add/subtract the desired speed depending on whether the number is bigger or smaller (with bigger numbers being down and to the right). This works fine if the destination is as much above as it is to the right. However, if the target is not, the unit moves at 45 degrees toward the thing until either the X or Y co-ordinate are in line with the destrination (which ever is sooner) at which point, it moves horizontally/vertically. Apart from looking ridiculous, it is not the quickest way between the two points and so will be incredibly frustrating for the player. But then, if you are the target audience for this post, you knew this already.

[Note: Another problem that you may encounter is that as the unit reaches it's destination, it jumps around it. This is because it is unlikely the player will click on a pixel that your units movement speed goes in to exactly. As a result, you unit will switch between being to the left and to the right of the target. I will explain my solution to this at the end of the post]

I tried a couple of other things that, in hind sight, are long winded amd complicated; I won't bore you with the the details. They ended up working to a point, except when the unit had to move either vertically or horizontally, it would accelerate to near infinite speeds.

The solution I finally settled on, at first seemed too complicated (and for all I know, there might be a better one) It relies on creating a right angled triangle with the destination point, finding the accute angle and creating proportional x/y speeds that add up to make a total (limiting the maximum speed) (See diagram)



Using trigonometry (Soh Cah Toa!) we can find the angle using xDist and yDist (which can be calculated by subtracting the larger x/y co-ordinate from the smaller of the unit and it's destination)

Tan(Angle) = yDist/xDist

Or...

Angle = atan(yDist/xDist) //atan is the inverse of tan, called atan in most programming langauges.

In most programming languages, this will actually give you the answer in radians (a way of numbering angles where pi represents 180 degrees). However, for the sake of simplicity (no PI key on my keyboard!) I will use degrees. You can either convert Angle in to degrees (*180 and then divide by PI) or when I say 90, use PI/2.

Next, we work out how steep the hypotenuse (longest side of the trianlge) needs to be. By doing the angle/90 we can work out what proportions the 2 speeds need to be. If the angle is 90, then we know we want the whole speed to be vertical, whereas 0 needs to give the whole speed as horizontal.

The way I did this was first calculate the Y speed.

ySpeed = (Angle/90)*Speed //where speed is the distance in pixels that you want your unit to cover in one frame.

In this, if the angle is 45, (ie. as far up as it is across) then you get (1/2)*speed resulting in half of your total speed to vertical.

The xSpeed is then calculated by taking the angle from 90 and putting that over 90. In the end, you will get two angles that add up to 90. Therefore, when you put them over 90 as two seperate fractions, they will add up to 1. So, when the two fractions are times by the speed, the two fractions of speed will add up to speed.

The problem with this is it will only work when both values are increasing (ie, the unit is moving right and down) To get around this (and deal with a second problem which I mentioned earlier) when the destination is selected, define two boolean variables to store whether the target is left/right and up/down. Then, when your regular function to move the unit is called, if movingRight == true, if != true, then subtract the number and so on.

I realise that this is a little confusing, so here is a quick summary of what I mean

Summary: By finding out the angle that the destination is from the current position, you can find the preportion that the two speeds need to be.

The final issue is checking when a unit is arriving. By using your movingRight boolean variable, you can simply see whether the unit has passed the X co-ordinate. If movingRight==true then if curX >= targetX then it has arrived. Likewise, if movingRight != true, then curX <= targetX for it to have arrived. And you do not need to check y, as they should happen at the same time.

Here is my C#/XNA code if it is any help: (distASec is a Vector2 which stores the speed, curPosition is a Vector2 which has the units location and currentTarget is a Vector2 which is where the unit is heading. Vector2 is a XNA data type which stores X and Y co-ordinates(as floating point numbers, if your in to that sort of thing!).

if (currentPosition != newTarget)
{
Vector2 totDist;
float refAngle;
currentTarget = newTarget;

//Calcuates total distance and direction
if (currentPosition.position.X < movingright =" true;" x =" currentTarget.position.X">


}
else
{
movingRight = false;
totDist.X = currentPosition.position.X - currentTarget.position.X;


}

if (currentPosition.position.Y < movingdown =" true;" y =" currentTarget.position.Y">


}
else
{
movingDown = false;
totDist.Y = currentPosition.position.Y - currentTarget.position.Y;
}
refAngle = (((float)(Math.Atan((totDist.Y / totDist.X))))*180)/(float)Math.PI;


distASec.Y = (refAngle / 90)*speed;
distASec.X = ((90 - refAngle)/90)*speed;

}

Finally, to check if the unit has arrived.

if((movingRight && currentPosition.position.X >= currentTarget.position.X)(!movingRight && currentPosition.position.X <= currentTarget.position.X))
{

//Code to be excuted upon arrival

}

Thursday, September 25, 2008

Boids Motion

Warning the post contains programming!

Ok, so the other day I stumbled across this website and decided to implement a basic boid flock in Flash. For those who don't know, Boid Flocking is a mathmatical way (ie. no random) way of moving a number (more than 3) objects that represents a flock. In this example, they move in 2D space, but it could easily to be expanded to 3D (or indeed simplified to 1D...). This theory was developed by Craig Reynolds. After creating a basic model, I created a simple game which I submitted to Newgrounds. From a game designers point of view, and clearly the reviews point of view, it is horrible, however, I built it mainly for demonstration purposes of boid stuff.

Boids run on 3 main rules. The first, and most important rule, is that they head towards the average mass of the boids.

_root.toalPosX = 0;
_root.toalPosY = 0;
for(i = 1; i<11;>
{
var numx:Number = _root["boid"+i+"_mc"]._x;
toalPosX = toalPosX + numx;
var numy:Number = _root["boid"+i+"_mc"]._y;
toalPosY = toalPosY + numy;
}
var averagePosX:Number = _root.toalPosX/10;
_root.averagePosY = _root.toalPosY/10;

This only works with 11 Boids, and I would like to, at some point, change to that to a foreach statement, however, as I have mainly been using C# recently, and I wasn't sure how you did it in Flash. So, as you can see, it defines two variables, one for X and one for Y (That is another thing you will miss going in to Flash from C#, things like Vector2s) Then, by cycling through each boid, and adding their x and y's to their respective variables, I was able to deduce the average location. This is placed within onEnterFrame, so the center of mass is always moving.

The thing that I think I did wrong was with how their velocities are handeled. As you can see from the NG movie, they tend to shoot off and the second their mass moves in one direction, it keeps moving, much like if you are swinging a bucket of water, the second the mass goes past the mid point you will suddenly lurch in that direction.

However, I actually added a 4th rule (I will come back to the other 2) that means the mass moves towards the red dot in the game (normally I would have it roughtly tracking the mouse) However, it keeps shooting past at increasing velocity.

for(i = 1; i<11;>
{
if(_root["boid"+i+"_mc"]._x <>
{
_root["bVolX"+i]+=1;
}
else if(_root["boid"+i+"_mc"]._x >averagePosX)
{
_root["bVolX"+i]-=1;
}

if(_root["boid"+i+"_mc"]._y <>
{
_root["bVolY"+i]+=1;
}
else if(_root["boid"+i+"_mc"]._y >averagePosY)
{
_root["bVolY"+i]-=1;
}

}

As you can see the numbers just keep getting bigger. I am trying to think of a way to stop them growing so huge, I am sure there must be something I missed in the implementation, because they are meant to basically stay within the bounds of the screen.

Anyway, back to my implentation. The next rule, which deffenitley has a noticable effect is a little bit of repulsion. I used twin for loops to check boid i against boid j where i != j. When I first did this, for reasons best known only to me, I put the signs as the same, so although they were repelling, they were both going the same way, so they just got a little bit faster. Better now.

for(i = 1; i <11; j =" 1;" distancex =" _root[" distancey =" _root["> -150)
{
_root["bVolX"+i] -= 1;
_root["bVolX"+j] += 1;
}
else if (distanceX > 0 && distanceX <> -150)
{
_root["bVolY"+i] -= 1;
_root["bVolY"+j] += 1;
}
else if (distanceY > 0 && distanceY <>

Fairly self explanatory. The effect looks a little bit like opposite magnets. One thing to note is this does not prohibit collisions, if they are travelling fast enough this will merely slow them down. What I would be interested in seeing done is where the two boids involved in the collision spin off in a random direction. To do this, I would hitTest within these for loops. What might make more sense if if you times the bVolX by -0.8 to flip it, and bVolY to add a bit of variation so it doesn't go straight back, by -1.2. Then the other boid would be times by these two values switched for X and Y. Maybe I will try this, points to anyone who beats me.

The final rule, and probably the least important, is a speed checker. Boids will try to mimick other Boids average speed. If most boids are going faster, it will speed up and vice versa. The idea behind this is they should meet somewhere in the middle and not go to fast. Well, thats the idea anyway.

I did this simply by checking the boids velocity against the average velocity and adding or subtracting depending on this.

avgVelX =0 ;
totVelX = 0
for(i = 1; i<11;>
{
totVelX += _root["bVolX"+i]
}
avgVelX = totVelX/10;
for(i = 1; i<11;>
{
if(avgVelX >= 0)
{
if(_root["bVolX"+i] <>
{
bVolX += 2;
}
else if (_root["bVolX"+i] > avgVelX)
{
bVolX -= 2;
}
} else
{
if(_root["bVolX"+i] <>
{
bVolX -= 2;
}
else if (_root["bVolX"+i] > avgVelX)
{
bVolX += 2;
}
}
}

avgVelY =0 ;
totVelY = 0
for(i = 1; i<11;>
{
totVelY += _root["bVolY"+i]
}
avgVelY = totVelY/10;
for(i = 1; i<11;>
{
if(avgVelY >= 0)
{
if(_root["bVolY"+i] <>
{
bVolX += 2;
}
else if (_root["bVolY"+i] > avgVelY)
{
bVolY -= 2;
}
} else
{
if(_root["bVolY"+i] <>
{
bVolY -= 2;
}
else if (_root["bVolY"+i] > avgVelY)
{
bVolY += 2;
}
}
}

The only thing missing is the red dot you control in the game. I was trying to make something that followed the mouse, except just a bit slower, but ended up with a Boid you controlled. It works exactly the same as all the other boids, except the centre of mass is always the mouse and it does not copy speed, nor is it repelled by other boids.

I hope this has helped anyone trying to implement a Boid thing. It is a really nice programming challenge, trying to interpret the rules in to your programming lanaguage. The website I listed at the top was a great resource. Any questions, please leave a comment or email me @ thekileyenator@gmail.com

Thanks for reading!