Feeds:
Posts
Comments

Posts Tagged ‘example’

Stevie G asks on the blitzbasic forums:

My mind’s gone a blank so I’m looking for some help here. What I need is the angle of elevation a weapon needs to be at to launch a projectile and hit a target. The target can be higher or lower than the weapon. I’m working in 2d so have the following information available:

X0 = X coord of weapon
Y0 = Y coord of weapon
X1 = X coord of target
Y1 = Y coord of target
Speed = Launch Speed of projectile
Gravity = -9.8

I’m not interested in including wind resistence etc..

A Level maths to the rescue! Use one of the equations of motion:

s = ut + \frac{1}{2}at^2

Where s is the distance travelled, u is the initial velocity, a is the acceleration, and t is time elapsed. We want to find an angle \phi to shoot the projectile at which will satisfy this equation.

Deal with the x- and y-components of motion separately. There’s no acceleration in the x-axis, so that equation will be easy to rearrange to get an expression for t:

\begin{array}{rcl}s_x &=& x_1-x_0 \\ u_x &=& V \cos(\phi) \\ a_x &=& 0 \\ \\ s_x &=& (V \cos(\phi))t \\ t &=& \frac{s_x}{V \cos(\phi)} \end{array}

Now we can put that into the equation for the y-axis:

\begin{array}{rcl}s_y &=& y_1-y_0 \\ u_y &=& V \sin(\phi) \\ a_y &=& g \\ \\ s_y &=& V \sin(\phi) (\frac{s_x}{V \cos(\phi)}) + \frac{1}{2}g(\frac{s_x^2}{V^2\cos^2(\phi)}) \end{array}

Now some clever cancelling and use of trig identities:

\begin{array}{rcl} s_x \tan(\phi) + \frac{gs_x^2}{2V^2}\sec^2(\phi) - s_y &=& 0 \\ \frac{gs_x^2}{2V^2}\tan^2(\phi) + s_x\tan(\phi) + (\frac{gs_x^2}{2V^2} - s_y) &=& 0 \end{array}

which, if you’re willing to believe it, is a quadratic equation in \tan(\phi). Use the quadratic formula to find \tan(\phi) and hence \phi. Simples!

… that’s a lie, so here’s some bmax code:

Graphics 600,600,0Graphics 600,600,0
Global bullets:TList=New TList
Type bullet
	Field x#,y#
	Field vx#,vy#
	Field path#[]

	Function Create:bullet(x#,y#,vx#,vy#)
		b:bullet=New bullet
		bullets.addlast b
		b.x=x
		b.y=y
		b.vx=vx
		b.vy=vy
		Return b
	End Function

	Method update()
		path:+[x,y]

		x:+vx
		y:+vy
		vy:+g
		DrawRect x-5,y-5,10,10

		For i=0 To Len(path)-1 Step 2
			DrawRect path[i],path[i+1],1,1
		Next

		If x>600 Or y>600
			bullets.remove Self
		EndIf
	End Method
End Type

'the setup is that you've got a cannon at (0,300), trying to fire at the mouse cursor.
'gravity is directed down the screen and the velocity of the projectiles is fixed at 20 px per frame.
'there will be some inaccuracy in the projectiles drawn on the screen because I'm using a discrete timestep model, due to I'm lazy.

Const g#=1,v#=20

While Not (KeyHit(KEY_ESCAPE) Or AppTerminate())
	sx#=MouseX()
	sy#=MouseY()-300

	a#=g*sx*sx/(2*v*v)	'coefficients of the quadratic equation
	b#=sx
	c#=a-sy

	If b*b>4*a*c	'if solution exists

		t#=(-b+Sqr(b*b-4*a*c))/(2*a)		'this is tan(phi)

		an#=ATan(t)
		DrawLine 0,300,sx,sy+300

		If MouseHit(1)
			bullet.Create 0,300,v*Cos(an),v*Sin(an)
		EndIf

	Else
		DrawText "no solution!",0,0
	EndIf

	For bu:bullet=EachIn bullets
		bu.update
	Next

	Flip
	Cls
Wend

Hope that’s useful!

Read Full Post »

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 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 »