Java Physics: Why isn't this working?!?!

Started by
6 comments, last by nuclearfission 13 years, 6 months ago
I'm working on a simple java applet/game. I'm trying to make this game have the atari missile command feel to it. So far I have somewhat of a player/ship firing red lines(missiles) onscreen everytime the mouse is clicked. However I'm having trouble sending the missiles to where the mouse is being clicked. I've tried using vectors(trigonometry) to set a missile X velocity, but it just isn't working. Everytime I click on the mouse the missile shoots either in 1)a fixed point
or 2)Not where the mouse is. Anothing thing is that java works in radians not degrees, and I have not a clue how to relate radians on a graph?(probebly could have googled: to lazy though)

please help me!

code:(mouse pressed funtion is near the bottom)

meteorD main java class
/** * @(#)meteorD.java * * meteorD Applet application * * @author * @version 1.00 2010/10/9 */import java.applet.*;import java.awt.*;import java.awt.event.*;public class meteorD  extends Applet implements Runnable, MouseListener, MouseMotionListener{	//declare some variables	private player gunShip;	private Thread game;	private projectile [] missile;	//make a constant projectileSpeed = -4	private final int projectileSpeed = -4;	//if game loop is running	boolean running = false;	//init	public void init() {		//new player object		gunShip = new player(235,285);		//10 new projectile objects		missile = new projectile[10];		//mouse listener		addMouseListener(this);	}	//create and start the thread and set running = true	public void start(){		//create the thread		game = new Thread(this);		game.start();		running = true;	}	//stop the thread	public void stop(){		game.stop();		if(game != null){			game = null;		}		running = false;	}	//this is supposedly called when the user exits the browser?	public void destroy(){		game.stop();		if(game != null){			game = null;		}		running = false;	}	//run	public void run(){		Thread.currentThread().setPriority(Thread.MIN_PRIORITY);		//while running = true		while(true){			for(int i=0; i < missile.length; i++){				if(missile != null){					missile.move();					if(missile.outOfBounds()){						missile = null;					}				}			}			//clear screen and call function paint?			repaint();			//try and let the thread sleep			try{				game.sleep(30);			}			catch (InterruptedException e){			}			Thread.currentThread().setPriority(Thread.MAX_PRIORITY);		}	}	//draw graphics to screen	public void paint(Graphics g) {		gunShip.draw(g);		for(int i=0; i < missile.length; i++){				if(missile != null){					missile.draw(g);				}			}	}	public void mousePressed(MouseEvent e)	{		//loop through the amount of missiles		for(int i=0; i < missile.length; i++){			//if one of the missiles is null			if(missile == null){				//set a missile object and break from the loop				missile = gunShip.fireMissile(e.getX(), e.getY());				break;			}		}	}	public void mouseClicked(MouseEvent e)	{	}	public void mouseEntered(MouseEvent e)	{	}	public void mouseExited(MouseEvent e)	{	}	public void mouseReleased(MouseEvent e)	{	}	public void mouseMoved(MouseEvent e)	{	}	public void mouseDragged(MouseEvent e)	{	}}


player class
public projectile fireMissile(int mouseXpos, int mouseYpos); is what you want to look at

import java.awt.*;import java.applet.*;import java.math.*;public class player {	//position variables	private int xPos;	private int yPos;	//constructer	public player(int x, int y){		xPos = x;		yPos = y;	}	//set X and Y	public void setX(int x){		xPos = x;	}	public void setY(int y){		yPos = y;	}	public projectile fireMissile(int mouseXpos, int mouseYpos){		projectile missile = new projectile(xPos,yPos-15);		//final vector x y		int Cx = xPos + mouseXpos;		int Cy = yPos + mouseYpos;		//final vector magnitude and angle		double Cmagnitude =  Math.sqrt((Cx)^2 + (Cy)^2);		double Cangle = Math.atan(Cy/Cx);		//send the vector angle to radians?		Cangle = Math.toRadians(Cangle);		//final equation for determining x velocity                //found this online		double CxFinal = -4*Math.cos(Cangle);		//set missile objects speed		missile.setX_speed( CxFinal );		missile.setY_speed( -4 );		return missile;	}	//drawing function	public void draw(Graphics g){		g.drawOval(xPos,yPos,15,15);		g.drawLine(xPos+7,yPos+7,xPos +7,yPos-5);	}}


and just to be thorough here is the last java class:
projectile
import java.awt.*;import java.applet.*;public class projectile {	//position variables	private int xPos;	private int yPos;	private double speedX;	private int speedY;	//constructer	public projectile(int x, int y){		xPos = x;		yPos = y;		speedX = 0;		speedY = -4;	}	//set X and Y	public void setX(int x){		xPos = x;	}	public void setY(int y){		yPos = y;	}	//set the X and Y speed of the projectile	public void setX_speed(double x){		speedX = x;	}	public void setY_speed(int y){		speedY = y;	}	//move the projectile	public void move(){		xPos += speedX;		yPos += speedY;	}	//check and see if prijectile is out of screens bounds	public boolean outOfBounds(){		if(yPos > 300){			return true;		}		if(yPos < 0){			return true;		}		if(xPos > 500){			return true;		}		if(xPos < 0){			return true;		}		return false;	}	//drawing function	public void draw(Graphics g){		g.setColor(Color.red);		g.drawLine(xPos+7,yPos+7,xPos +7,yPos-5);	}}
Advertisement
Quote:Original post by nuclearfission
...However I'm having trouble sending the missiles to where the mouse is being clicked. I've tried using vectors(trigonometry) to set a missile X velocity, but it just isn't working. Everytime I click on the mouse the missile shoots either in 1)a fixed point
or 2)Not where the mouse is. Anothing thing is that java works in radians not degrees, and I have not a clue how to relate radians on a graph?(probebly could have googled: to lazy though)


So yeah you need trigonometry, vectors, etc. First off you have trouble with the concept of radians. Here's a little history: some time a long time ago some bloke discovered that the ratio of a circle's circumference to its diameter is a constant. He called this pi. Then someone invented the radian. It is a way to measure an angle. Basically you take the length of the arc, cut out by an angle, like a piece of pie, in the circle and divide it by the circle's radius. This is how many radians the angle is. You can also convert this to degrees. Then since pi was on the scene and now radians blokes decided to get together and formalize. The rest is history.

180 degrees = pi radians (where pi = 3.14.........................).

So if you have theta degrees and wish to convert it to radians then
radians = theta * pi / 180(degrees).
If you wish to convert someRadians to degrees, just
degrees = someRadians * 180(degrees)/ pi.

I'm not going to look thru your code, but hopefully the following will be enough for you:

1) get mouse coordinates (where you are firing) -- call this
m = <mx, my>.
This is vector notation; if you do not get this ask.

2) get missile origination point. You should know this; it is where the missile tower sprite is --
o = <ox, oy>.

NOTE: (1) and (2) should be both described using coordinates from the same coordinate system. If you do not get this ask. It's important.

Then form a vector,
p = <mx - ox, my - oy>.

Then form a vector called
u = norm( <px, py> ),
where norm ( * ) is the vector normalization operation. Again ask or google if you're not familiar.

Then each frame the fired missiles position vector, f, can be updated like
f += speed * u,
where speed is the speed of the missile, and speed * u is the velocity of the missile.

Obviously, this last part, you can adjust to your taste, like if you need to do frame independent movement....

Hope this helps a bit (hopefully I didn't type in any mistakes).
Okay sorry for the long wait, I had some priorities to attend. After trying your solutions(thanks btw), the missiles are still not moving towards the mouse. I might not understand the normalizing of the vectors?

Quote:Then form a vector,
p = <mx - ox, my - oy>.


okay I was adding mx to ox, and my to oy. I fixed that, thank you.


Quote:Then form a vector called
u = norm( <px, py> )


Is normalizing a vector the same as:

x = px/magnitude
y = py/magnitude

this is what I was understanding from the website: http://www.fundza.com/vectors/normalize/index.html

Quote:Then each frame the fired missiles position vector, f, can be updated like
f += speed * u


I beleive I now have something simuliar to this in my program. Except f is the xPosition of the missile.
I wrote a quick example in c#/xna. I think it will break everything down for you:

Code:
            Vector2 target;            Vector2 gun;            Vector2 missile;            Console.WriteLine("Welcome to missile/vector sim.");            //            Console.WriteLine("The origin is at the bottom left (0,0).");            Console.WriteLine("The game area is 100x100.");            Console.WriteLine("Positive x is to the right; positive y is up.");            Console.WriteLine("Missile tower is located at (50,0).");            Console.WriteLine("\nFire missile to (0 to 100) => (x):");                       string str = Console.ReadLine();            int x = int.Parse(str);            Console.WriteLine("Fire missile to (0 to 100) => (y):");            str = Console.ReadLine();            int y = int.Parse(str);            Console.WriteLine("\nYou're firing the missile to location: (" + x + "," + y + ").");            target = new Vector2(x, y);            gun = new Vector2(50, 0);            missile = new Vector2(50, 0);                        Vector2 direction = new Vector2(0, 0);            direction = Vector2.Subtract(target, gun);            direction.Normalize();            Console.WriteLine("\n\nThe missile's direction vector is: <" + direction.X + "," + direction.Y + ">.");            float missileSpeed = 1.0f;            while (Vector2.Subtract(missile, target).Length() > 0.5)            {                Console.WriteLine("The missile's position is: (" + missile.X + "," + missile.Y + ").");                missile += missileSpeed*direction;            }            //             Console.Read();


Output:
Welcome to missile/vector sim.The origin is at the bottom left (0,0).The game area is 100x100.Positive x is to the right; positive y is up.Missile tower is located at (50,0).Fire missile to (0 to 100) => (x):87Fire missile to (0 to 100) => (y):37You're firing the missile to location: (87,37).The missile's direction vector is: <0.7071068,0.7071068>.The missile's position is: (50,0).The missile's position is: (50.70711,0.7071068).The missile's position is: (51.41422,1.414214).The missile's position is: (52.12132,2.12132).The missile's position is: (52.82843,2.828427).The missile's position is: (53.53554,3.535534).The missile's position is: (54.24265,4.24264).The missile's position is: (54.94975,4.949747).The missile's position is: (55.65686,5.656854).The missile's position is: (56.36397,6.36396).The missile's position is: (57.07108,7.071067).The missile's position is: (57.77818,7.778173).The missile's position is: (58.48529,8.48528).The missile's position is: (59.1924,9.192387).The missile's position is: (59.89951,9.899493).The missile's position is: (60.60661,10.6066).The missile's position is: (61.31372,11.31371).The missile's position is: (62.02083,12.02081).The missile's position is: (62.72794,12.72792).The missile's position is: (63.43504,13.43503).The missile's position is: (64.14215,14.14213).The missile's position is: (64.84926,14.84924).The missile's position is: (65.55637,15.55635).The missile's position is: (66.26347,16.26345).The missile's position is: (66.97058,16.97056).The missile's position is: (67.67769,17.67767).The missile's position is: (68.3848,18.38478).The missile's position is: (69.0919,19.09188).The missile's position is: (69.79901,19.79899).The missile's position is: (70.50612,20.5061).The missile's position is: (71.21323,21.21321).The missile's position is: (71.92033,21.92031).The missile's position is: (72.62744,22.62742).The missile's position is: (73.33455,23.33453).The missile's position is: (74.04166,24.04164).The missile's position is: (74.74876,24.74874).The missile's position is: (75.45587,25.45585).The missile's position is: (76.16298,26.16296).The missile's position is: (76.87009,26.87007).The missile's position is: (77.57719,27.57717).The missile's position is: (78.2843,28.28428).The missile's position is: (78.99141,28.99139).The missile's position is: (79.69852,29.6985).The missile's position is: (80.40562,30.4056).The missile's position is: (81.11273,31.11271).The missile's position is: (81.81984,31.81982).The missile's position is: (82.52695,32.52692).The missile's position is: (83.23405,33.23403).The missile's position is: (83.94116,33.94114).The missile's position is: (84.64827,34.64825).The missile's position is: (85.35538,35.35535).The missile's position is: (86.06248,36.06246).


To understand about vector normalization, this this wiki article section.

Also note I used XNA's Vector2 class for the vector op's to implement the thing I talked about in the last post. You can prolly just follow the code and implement something similar in yr program. Also, note how all physical objects in my simulation have a consistent coordinate system; if this requirement is not met, results may suck.

So basically my output has me firing the missile from position (50,0) -- the gun's position, to the user chosen target-- in this case, I chose target = (87,37); in your situation this would just be the target position chosen by the user's mouse.
You should change the position and speed variables of the projectile to float or double. Here is a changed version of of the player.fireMissile function.

    public projectile fireMissile(int mouseXpos, int mouseYpos){        float startX = xPos;        float startY = yPos-15;                projectile missile = new projectile(startX, startY);        float angle = Math.atan2(mouseYpos - startY, mouseXpos - startX);                missile.setX_speed( Math.cos(angle) );        missile.setY_speed( Math.sin(angle) );        return missile;    }
zoto, I can't compile because the java compiler says that it might be a possible loss of precision. I changed startX and startY to int and it works, but the missile is a little off target.

Thanks for the revised code example[smile]
Sorry about that, the Math functions return a double so you need to typecast them to a float or change the variables to doubles.
Some angles will be impossible if you use an integer instead of a type with a decimal point for your position and speed.
HaHa! Sure it may not exactly go to the very point/tip of the mouse but it at least hits the mouse. For now it's good enough for me [grin]
public projectile fireMissile(int mouseXpos, int mouseYpos){        int startX = xPos;        int startY = yPos-15;        float mouseX = mouseXpos;        float mouseY = mouseYpos;        float finalX = startX;        float finalY = startY;        projectile missile = new projectile(startX, startY);        double angle = Math.atan2(mouseY - finalY, mouseX - finalX);        missile.setX_speed( Math.round(4*Math.cos(angle)) );        missile.setY_speed(  Math.round(4*Math.sin(angle)) );        return missile;    }


Thank you signal_ and zoto for your time and help. I believe I'm going to now work on adding a meteor class. Hopefully I won't run into another issue again.[headshake]

This topic is closed to new replies.

Advertisement