Feeds:
Posts
Comments

Archive for March, 2009

Jussi writes,

Given the lengths of c1 and c2 and angle alpha, what’s the simplest and fastest way to calculate the length of d (see the attached image)?

vector1

Looks tricky at first, but trying to do it the boring way ended up giving me a nice answer.

What we want is to have the line with angle alpha intersect the hypotenuse of the triangle. So, let’s write down the equations of the two lines:

The hypotenuse can be written using the normal straight line formula:

y = c_1 - \frac{c_1}{c_2}x

While the other line is in polar co-ordinates because we only know the angle alpha:

\begin{array}{rcl} x &=& d \cos \alpha \\ y &=& d \sin \alpha \end{array}

Substitute those into the first equation:

d \sin \alpha = c_1 - \frac{c_1}{c_2}d \cos \alpha

We want to find d, so collect all the terms with d together:

d( \sin \alpha + \frac{c_1}{c_2}) = c_1

And finally divide by the stuff in the brackets:

d = \frac{c_1}{\sin \alpha + \frac{c_1}{c_2} \cos \alpha}

Now let’s check that it works with some bmax code:

Graphics 600,600,0

c1#=300
c2#=400

an#=0

While Not (KeyHit(KEY_ESCAPE) Or AppTerminate())
	x#=300-c2/2
	y#=300-c1/2
	DrawLine x,y,x+c2,y
	DrawLine x,y,x,y+c1
	DrawLine x+c2,y,x,y+c1

	an = (an+1) Mod 90

	t#=an/90
	r#=c1/(Sin(an)+(c1/c2)*Cos(an))
	DrawLine x,y,x+Cos(an)*r,y+Sin(an)*r

	Flip
	Cls
Wend

Yep!

Read Full Post »

In this post, SpaceTW asked:

Hi, I need help aiming at moving targets for a program. I have the variables for the speed and direction of the enemies, but the targeting is still not accurate enough.

There’s a very simple solution if you don’t mind the bullets travelling at different speeds, but that can lead to bullets travelling very fast or very slow, so let’s say that we want every bullet to go the same speed. Here’s the solution:

Suppose you have a tower at a fixed position (x_0,y_0), and an enemy at initial position (x_1,y_1) moving in the direction (v_x,v_y).

You want to shoot a bullet travelling at a certain velocity V so that it collides with the enemy.

Let the direction of the bullet be (d_x,d_y).

If d_x=v_x and d_y=v_y, then the bullet will move in parallel with the enemy, always staying the same distance from it.

You can now consider that the enemy is not moving at all, relative to the bullet, and the difference in position between them is (x_1-x_0, y_1-y_0). The bullet can move along this line to collide with the bullet.

If the bullet takes t frames to reach the bullet, we now get:

\begin{array}{rcl}d_x = (x_1-x_0)/t + v_x \\ d_y = (y_1-y_0)/t + v_y \end{array}

As we said that the bullet’s velocity is V, we get

d_x^2 + d_y^2 = V^2

Which expands out to:

\begin{array}{rcl} \left(\frac{1}{t}\right)^2 \left[ (x_1 - x_0)^2 + (y_1 - y_0)^2 \right] && \\ + \frac{1}{t} \left[ v_x (x_1 - x_0) + v_y ( y_1 - y_0) \right] &&\\ + v_x^2 + v_y^2 - V^2 &=& 0 \end{array}

(I had to split that over a few lines so it would fit in the post column, sorry!)

Which is a quadratic equation! So set:

\begin{array}{rcl} a &=& (x_1-x_0)^2 + (y_1-y_0)^2 \\ b &=&  2[ v_x(x_1-x_0) + v_y(y_1-y_0) ] \\ c &=&  v_x^2 + v_y^2 - V^2 \end{array}

Then, using the quadratic formula:

\frac{1}{t} = \frac{-b + \sqrt{ b^2 - 4ac}}{2a}

You can now put that back into the equations for d_x and d_y, and you’re done!

Here’s the result, written in BlitzMax:

diffx:double=x2-x1
diffy:double=y2-y1
v:Double=3                'desired speed of bullet

a:Double=diffx*diffx+diffy*diffy
b:Double=2*(vx*diffx+vy*diffy)
c:Double=vx*vx+vy*vy-v*v

tInv#=(-b+Sqr(b*b-4*a*c))/(2*a)   ' solve 1/t
dx=diffx*tInv+vx
dy=diffy*tInv+vy

That’s it!

Read Full Post »

In this post Ryan Burnside asked how to find the exact place where a line intersects the outline of a box.

Here’s my solution:

Function boxintersect(last_x#, last_y#, x#, y#, bx1#, by1#, bx2#, by2#, ix# Var, iy# Var)
	'finds point of intersection of line from (last_x,last_y) to (x,y)
	'with the box (bx1,by1,bx2,by2). the ix and iy parameters are var pointers, which means
	'the function fills in the values of the point of intersection in the variables that you give.
	'the function also returns true if there is an intersection, and false if there is none.

	If Not (x>=bx1 And x=by1 And y<=by2) Return False

	If last_x = bx1 		'does it cross left edge?
		iy# = last_y + (y - last_y) * (bx1-last_x)/(x-last_x)
		If iy>=by1 And iy bx2 And x =by1 And iy<=by2			'is intersection point on right edge?
			ix# = bx2
			Return True
		EndIf
	EndIf

	If last_y = by1 		'does it cross top edge?
		ix# = last_x + (x - last_x) * (by1 - last_y)/(y - last_y)
		If ix>=bx1 And ix by2 And y =bx1 And ix<=bx2			'is intersection point on bottom edge?
			iy# = by2
			Return True
		EndIf
	EndIf
End Function

'example
Graphics 800,600,0

Global box1#,boy1#,box2#,boy2#
Global ox#,oy#,nx#,ny#

Function maketest()
	box1=Rnd(200,300)
	boy1=Rnd(100,200)
	box2=Rnd(500,600)
	boy2=Rnd(400,500)

	nx=Rnd(box1,box2)
	ny=Rnd(boy1,boy2)
	an#=Rnd(360)
	ox=300*Cos(an)+400
	oy=300*Sin(an)+300

End Function

maketest

While Not (KeyHit(KEY_ESCAPE) Or AppTerminate())

	If KeyHit(KEY_SPACE)
		'make a new box and line
		maketest
	EndIf

	DrawLine box1,boy1,box2,boy1
	DrawLine box1,boy1,box1,boy2
	DrawLine box1,boy2,box2,boy2
	DrawLine box2,boy1,box2,boy2

	DrawLine ox,oy,nx,ny

	Local ix#,iy#	'variables to store point of intersection in
	boxintersect( ox,oy,nx,ny, box1,boy1,box2,boy2, ix,iy )

	DrawOval ix-3,iy-3,6,6

	Flip
	Cls
Wend

The way it works is to notice that one line crosses another if it starts on one side of the crossed line, and ends on the other. That’s what the first check is about, checking the infinite line which the side of the box is part of. The second check finds the intersection point and checks if it is actually within the line segment which makes up the box.

Read Full Post »

Matrix maths

Matrices are pretty confusing things, so here’s a quick summary of what they are, where they come from, and how you use them. Beware that matrices are very tricky, and require a lot of background knowledge before you can understand them in any depth.

Scalars are individual numbers – your age is a scalar, the length of an object is a scalar, and so on.

Some scalars: 1,\; -653.3,\; x,\; y,\; z.

Vectors are like lists of scalars, so a position in space is a vector – it consists of one scalar for each co-ordinate.

Some vectors: \begin{pmatrix}1\\2\\3\end{pmatrix},\; \begin{pmatrix}x\\y\\z\end{pmatrix},\; \vec{x},\; \vec{v}

You can do algebra with vectors like you can with scalars. Addition is done by reading across the rows. For example:

\begin{pmatrix}1\\2\\3\end{pmatrix} + \begin{pmatrix}4\\5\\6\end{pmatrix} = \begin{pmatrix}1 + 4 \\ 2 + 5 \\ 3 + 6\end{pmatrix} = \begin{pmatrix} 5\\7\\9\end{pmatrix}.

And you can multiply a vector by a scalar:

2\begin{pmatrix}x\\y\\z\end{pmatrix} = \begin{pmatrix}2x\\2y\\2z\end{pmatrix}.

You can even multiply two vectors together (their ‘dot product’) but you have to cheat a bit with the notation and write the firstone sideways, for reasons which will become clear when we look at matrices:

\begin{pmatrix}x&y&z\end{pmatrix}\begin{pmatrix}1\\2\\3\end{pmatrix} = 1 \times x + 2 \times y + 3 \times z = x + 2y + 3z.

As vectors are made up of several scalars, you can think of matrices as being made up of several vectors. Consider a system of simultaneous equations:

\begin{array}{rcl} x + y + z &=& 6 \\ 3x + 2y + z &=& 10 \\ 2x+y-z &=& 1 \end{array}

Without explanation, here’s how you write that in matrix form:

\begin{pmatrix}1&1&1\\3&2&1\\2&1&-1\end{pmatrix} \begin{pmatrix}x\\y\\z\end{pmatrix} = \begin{pmatrix}6\\10\\1\end{pmatrix}.

What I’ve noticed is that every equation in the system had some number of x, some number of y, and some number of z. So, all you really need to describe the whole system is state what each of those coefficients is, and what each line was equal to. To understand what the matrix form means, look at the 3 \times 3 matrix a row at a time, as if it was a series of vector multiplications:

\begin{pmatrix}1&1&1\end{pmatrix}\begin{pmatrix}x\\y\\z\end{pmatrix} = 6.

x + y + z = 6.

Which is the first equation of our system! Matrices aren’t just a quick way of writing down equations though – once you’ve got something into matrix form, there are a set of general operations you can perform on them to make finding a solution a lot less fiddly.

A matrix is like a 2D array of numbers. A matrix with m rows and n columns is called a m \times n matrix. This is the other way round to the way you normally give co-ordinates, where the horizontal one is first and the vertical second. I think that’s just because you saw “rows and columns”, not “columns and rows”, and mathematicians wrote down the definition in words before drawing it out on paper.

If you want to give a matrix a name, the convention is to use a capital letter so you know it isn’t a scalar, which are always represented by lower-case letters.

You can add two matrices of the same size by adding the corresponding entries:

\begin{pmatrix}1&2\\3&4\end{pmatrix} + \begin{pmatrix}5&6\\7&8\end{pmatrix} = \begin{pmatrix}6&8\\10&12\end{pmatrix}.

The same goes for subtracting matrices.

Multiplying matrices is a bit more involved. To multiply two matrices, first of all the second matrix has to have the same number of rows as the first matrix has columns. Multiplying an $m \times n$ matrix by an $n \times p$ matrix results in an $m \times p$ matrix.

To do the actual multiplication, start at the top-left entry of each matrix, and read right in the first matrix and down in the second matrix, summing up the products of each pair of entries as you go. That result is the value of the top-left entry of the result matrix.

\begin{pmatrix}a&b&c\\d&e&f\\g&h&i\end{pmatrix}\begin{pmatrix}j&k&l\\m&n&p\\q&r&s\end{pmatrix} = \begin{pmatrix}aj + bm + cq&\ldots&\ldots\\\vdots&\ddots&\\\vdots&&\ddots\end{pmatrix}.

Now go back and start again at the top-left of the first matrix, and the second entry in the top row of the second matrix, and proceed as before, to get the second entry of the top row. Once you’ve finished the top row, move down to the second row, of the first matrix, getting you the second row of the result, and so on and so forth. Very tedious work, but as long as you remember the order to do things in you can do it almost mechanically – read along the first matrix and down the second, then change row or column to get each entry in the result.

I don’t think anyone can get this right first time. If you ever really need to multiply two matrices, refer back here until you get a sensible answer. Unfortunately, matrix multiplication isn’t commutative, which means it matters which way round you do it. While $3 \times 7 = 7 \times 3 = 21$, the same isn’t always true for matrices:

\begin{pmatrix}1&2\\3&4\end{pmatrix} \begin{pmatrix}5&6\\7&8\end{pmatrix} = \begin{pmatrix}19&22\\43&50\end{pmatrix}

but

\begin{pmatrix}5&6\\7&8\end{pmatrix}\begin{pmatrix}1&2\\3&4\end{pmatrix} = \begin{pmatrix}23&34\\31&46\end{pmatrix}

That’s not even upside-down or reflected, it’s completely different numbers!

Though you can’t divide two matrices, so that’s one less thing to learn.

There are a few special matrices. First, the zero matrix:

\begin{pmatrix} 0 & 0 & \ldots \\ 0 & 0 & \ldots \\ \vdots & \vdots & \ddots \end{pmatrix}.

is like the number zero – adding zero matrix to any other matrix leaves it as it is, and multiplying any matrix by the zero matrix results in the zero matrix. There’s a different zero matrix for every size, but you can always write it as just 0 without leading to any ambiguity.

Secondly, the identity matrix:

\begin{pmatrix}1 & 0 & 0 & \ldots \\ 0 & 1 & 0 & \ldots \\ 0 & 0 & 1 & \ldots \\ \vdots & \vdots & \vdots & \ddots \end{pmatrix}

is like the number 1, with respect to multiplication. The identity matrix of any size is written as simply I Multiplying any matrix by an identity matrix (of the correct dimensions) leaves it as it is. You can also define the inverse of a square matrix A as the matrix A^{-1} which, when multiplied by A on either side, results in the identity matrix.

So, back to our system of simultaneous equations. If we find the inverse of the 3 \times 3 matrix on the left hand side of our equation, and multiply both sides by that, we are left with just \begin{pmatrix}x\\y\\z\end{pmatrix}, so we can read off their values from the result of the right-hand side:

\begin{array}{rcl} A \begin{pmatrix} x \\ y \\ z \end{pmatrix} &=& B \\ A^{-1}A \begin{pmatrix} x \\ y \\ z \end{pmatrix} &=& A^{-1}B \\ I \begin{pmatrix} x \\ y \\ z \end{pmatrix} &=& A^{-1}B \\ \begin{pmatrix} x \\ y \\ z \end{pmatrix} &=& A^{-1}B \end{array}

Nifty!

But this is deceptively simple, because finding the inverse of a matrix involves quite a bit of work. We’ll come back to this, after the last couple of matrix operations.

The transpose of a matrix is just the same matrix, written ‘sideways’ – rows become columns, and columns become rows. The transpose of a matrix A is written A^T. So, reading down the first row of A gives you the first column of A^T, the second row gives the second column, and so on. Easy.

The determinant of a matrix is a bit like its size, but not really. It’s a scalar, but it can be negative or positive or even zero. What it really does is exactly what it says on the tin – it determine some of the characteristics of the matrix.

Now the determinant gets very complicated very quickly, so I’ll only go as far as telling you what it is for a 3 \times 3 matrix. First of all, the determinant of a 2 \times 2 matrix is

\begin{vmatrix}a&b \\ c&d \end{vmatrix} = ac - bd.

(to show you’re working out the determinant of a matrix, write it in between straight lines instead of parentheses)

There are a few ways to work out the determinant of a 3 \times 3 matrix, but of course they all work out to the same number. The way I was taught was:

  • Read along the top row.
  • For each entry, cover up the row and column it belongs to, and work out the determinant of the 2 \times 2 matrix that is still visible, and multiply that number by the entry on the top row .
  • Add the first and third results together and subtract the second one.

\begin{array}{rcl} \begin{vmatrix} x_{00}&x_{01}&x_{02} \\ x_{10}&x_{11}&x_{12} \\ x_{20}&x_{21}&x_{22} \end{vmatrix} &=& x_{00}(x_{11}x_{22} - x_{12}x_{21}) + x_{02}(x_{10}x_{21} - x_{11}x_{20}) \\ && - x_{01}(x_{10}x_{21} - x_{12}x_{20}) \end{array}

You can just remember that formula if you want, but I find it makes much more sense following the method.

Another way I’ve been taught is to start with x_{00}(x_{11}x_{22} - x_{12}x_{21}, and then “cycle round” the letters of each row, so  you next add x_{01}(x_{12}x_{20} - x_{10}x_{22}), and then x_{02}(x_{10}x_{21} - x_{11}x_{20}). It’s horses for courses, really.

We’re almost there!

For each entry in a matrix, its minor is the determinant of the matrix made by deleting the row and column the original entry is in. The entry x_{ij} of a matrix is even if i+j is even, and odd if it is not. The cofactor of a matrix entry is the same as its minor in an even entry, or the opposite sign in an odd entry. You can form the matrix of cofactors for a matrix by setting each entry of the new matrix to be the cofactor of the entry in the old matrix.

Finally, the inverse of a matrix is the transpose of its matrix of cofactors, all divided by the determinant of the original matrix. Phew! Don’t worry, I have never succesfully remembered this. Look it up when you need it.

A^{-1} = \frac{1}{|A|} C^T

Clearly, if a matrix’s determinant is zero, you can’t divide by it, so it has no inverse. These matrices are called non-invertible matrices. Mathematicians do have a way with words!

So we can finally solve that system of equations! First, find the determinant:

\begin{array}{rcl} \begin{vmatrix}1&1&1\\3&2&1\\2&1&-1\end{vmatrix} &=& 1(2 \times (-1) - 1 \times 1) - 1(3 \times (-1) - 1 \times 2) \\&& + 1(3 \times 1 - 2 \times 2) \\ &=& -3 +5 -1 \\ &=& 1.\end{array}

That’s handy!

So, the matrix’s inverse is:

\begin{pmatrix}1&1&1\\3&2&1\\2&1&-1\end{pmatrix}^{-1} = \frac{1}{1} \begin{pmatrix}-3&2&-1\\5&-3&2\\-1&1&-1 \end{pmatrix}

All that’s left to do is multiply both sides of the equation by this inverse (on the left, remember matrices aren’t commutative!)

\begin{array}{rcl} \begin{pmatrix} x\\y\\z \end{pmatrix} &=& \begin{pmatrix}-3&2&-1\\5&-3&2\\-1&1&-1 \end{pmatrix} \begin{pmatrix}6\\10\\1\end{pmatrix} \\ &=& \begin{pmatrix}1\\2\\3\end{pmatrix} \end{array}

We’re done! We can read off that x=1,\; y=2\; z=3.

Now that was a huge amount of faff for something that you probably knew how to do when it was written as a set of simultaneous equations, but think about how you’d get a computer to do it that way. It would get very complicated, especially if you added more variables in. The matrix method, on the other hand, is very easy for a computer to do – it was just a series of well-defined mathematical operations, with no decisions to be made at any step.

But you almost never need to solve simultaneous equations in a game! What are some useful applications of matrices? Consider 2d transformations – moving, rotating and scaling. Moving and scaling are easy to do just with vectors, but what about rotation? Here’s how you do it with a set of scalar equations:

\begin{array}{rcl} x_1 &=& x_0 \cos \theta - y_0 \sin \theta \\ y_1 &=& y_0 \cos \theta + x_0 \sin \theta \end{array}

You can use the same trick as with the simultaneous equations before to write this in terms of matrices:

\begin{pmatrix}x_1\\y_1\end{pmatrix} = \begin{pmatrix}\cos \theta & - \sin \theta \\ \sin \theta & \cos \theta \end{pmatrix} \begin{pmatrix}x_0 \\y_0 \end{pmatrix}

(I worked that matrix out by drawing a pair of axes and the graphs of sin and cos on paper, by the way. It’s another little thing it’s not worth trying to remember, but much more useful to work out each time you need it)

What this means is, you can work out the matrix for rotation by a particular angle once, and repeatedly apply that to a vector to rotate multiple times. It’s not obvious you can do that with the pair of equations above.If you find the inverse of a rotation matrix, you can also ‘undo’ a rotation very easily.

The matrix method gets vastly more useful when you move to 3d, and you end up with lots of equations and variables to keep track of.

So, that’s a brief summary of matrices. It’s a lot to learn in one go, and not at all intuitive. I think it’s best just to be aware of what they are, and refer back to this or somewhere like mathworld. Unless you’re doing a lot of 3d maths, I think you can get away with not knowing too much about them, as a games developer. Matrices also have all sorts of other applications, for example in graph theory and group theory, but I won’t bother covering those unless someone asks for it.

If you have any questions or don’t understand something, add a comment and I’ll endeavour to give satisfaction.

Read Full Post »

Yo

I’ve set up this blog as a place to answer questions about maths programming problems. If you’ve never understood trigonometry, or how to work out a percentage, or need some help with more involved topics, send me an email and I’ll write up a nice explanation.

Read Full Post »