java space ship game - java

here is the entire code for the classes Ship,Asteroids,BaseShapeClass. Ship Class inherits from the BaseShapeClass for its shape. Asteroid class is the main source code which declares the Graphics2D object,AffineTransform(for identity creation),declares double image buffer...
Code for BaseShapeClass..
package baseshapeclass;
import java.awt.Shape;
public class BaseShapeClass {
private Shape shape;
private double x, y;
private double velX, velY;
private double moveAngle, faceAngle;
private boolean alive;
//accessors and mutators
public Shape getShape(){return shape;}
public void setShape(Shape shape){ this.shape = shape; }
public double getX() { return x; }
public void setX(double x) { this.x = x; }
public void incX(double ix) { this.x += ix; }
public double getY() { return y; }
public void setY(double y) { this.y = y; }
public void incY(double iy) { this.y += iy; }
public double getVelX() { return velX; }
public void setVelX(double velX) { this.velX = velX; }
public void incVelX(double ivX) { this.velX += ivX; }
public double getVelY() { return velY; }
public void setVelY(double velY) { this.velY = velY; }
public void incVelY(double ivY) { this.velY += ivY; }
//MoveAngle refers to the objects angular movement
public double getMoveAngle() { return moveAngle; }
public void setMoveAngle(double mAngle) { this.moveAngle = mAngle; }
public void incMoveAngle(double imAngle) { this.moveAngle += imAngle; }
//FaceAngle refers to the objects face/heads angular movement
public double getFaceAngle() { return faceAngle; }
public void setFaceAngle(double fAngle) { this.faceAngle = fAngle; }
public void incFaceAngle(double ifAngle) { this.faceAngle += ifAngle; }
public boolean isAlive() { return alive; }
public void setAlive(boolean alive) { this.alive = alive; }
//default constructor everything will be set to original state
//when update is called everything will start to move
BaseShapeClass(){
setShape(null);
setAlive(false);
//all of them are set to '0' representing their initial position,
//which will be called during the update() Event of the graphics objects
setX(0.0);
setY(0.0);
setVelX(0.0);
setVelY(0.0);
setMoveAngle(0.0);
setFaceAngle(0.0);
}
}
Code for Ship class...
package baseshapeclass;
import java.awt.Rectangle;
import java.awt.Polygon;
public class Ship extends BaseShapeClass {
//ships shape along the x and y cordinates
private final int[] shipx = {-6,3,0,3,6,0};
private final int[] shipy = {6,7,7,7,6,-7};
public Rectangle getBounds(){
Rectangle r = new Rectangle((int)getX()-6, (int)getY()-6, 12, 12);
return r;
}
Ship(){
setShape(new Polygon(shipx, shipy, shipx.length));
setAlive(true);
}
}
Code for Asteroid(Main source code)...
package baseshapeclass;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public abstract class Asteroid extends Applet implements Runnable, KeyListener {
BufferedImage backbuffer;
Graphics2D g2d;
Ship ship = new Ship();
boolean showBounds= true;
AffineTransform identity = new AffineTransform();
#Override public void init(){
backbuffer = new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
g2d = backbuffer.createGraphics();
ship.setX(320);
ship.setY(240);
addKeyListener(this);
}
#Override public void update(Graphics g){
g2d.setTransform(identity);
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getSize().width, getSize().height);
g2d.setColor(Color.WHITE);
g2d.drawString("Ship: "+Math.round(ship.getX())+" , "+Math.round(ship.getY()),2, 150);
g2d.drawString("Face Angle: "+Math.toRadians(ship.getFaceAngle()),5, 30);
g2d.drawString("Move Angle: "+Math.toRadians(ship.getMoveAngle())+90,5,50);
drawShip();
paint(g);
}
public void drawShip(){
g2d.setTransform(identity);
g2d.translate(ship.getX(),ship.getY());
g2d.rotate(Math.toRadians(ship.getFaceAngle()));
g2d.setColor(Color.ORANGE);
g2d.fill(ship.getShape());
}
}
I hope you guys get a better idea with all the code in place. Just wanted to know on the part of Ship class why are the ships x and y cordinates such as under:
public class ship extends BaseShapeClass{
private int[] shipx = {-6,3,0,3,6,0};
private int[] shipy = {6,7,7,7,6,-7};
}
I cant follow on how those values will make upto a Polygon??

Ship(){
setShape(new Polygon(shipx,shipy,shipx.length));
setAlive(true);
}
You can see that the two arrays you are confused about go into the initialization of a Polygon. These two arrays, taken as a pair, give the x and y coordinates of each point in the Polygon.

This post is in answer to your comment in Kronion's answer; I was going to post it as a comment, but there is too much to say and I wanted to show you some code, which is not as legible in the comments.
As Kronion said, the Polygon class does indeed accept an array of X coordinates, and an array of Y coordinates. The reason for this is that the X and Y coordinate are stored at the same position in both arrays. So if int index = 0, then that X,Y coordinate pair would be xArray[index] and yArray[index].
If that doesn't make any sense, examine the Polygon class source code. For example, you'll see this happening in the contains method, here:
for (int i = 0; i < npoints; lastx = curx, lasty = cury, i++) {
curx = xpoints[i];
cury = ypoints[i];
// remainder of loop
}
So in short, they are assigned in this manner because the X and Y are paired by their index positions.
Hope that helps.

Related

My Java Bouncing Ball Bounces up with a larger velocity

I'm making a simple Java program to bounce a ball up and down. The problem is that the ball bounces up higher than its starting point with each bounce. I expect the ball to bounce back up exactly to the height that it started from.
The ball physics can be found in the circle class in the doPhysics() method where I suspect the problem can be found
import java.awt.*;
import java.util.*;
public class Main{
public static Frame frame = new Frame();
public static Physics physics = new Physics();
public static ArrayList<Circle> circles = new ArrayList<Circle>(); //array for the points
public static void main(String args[]) {
Circle circle = new Circle(100, 300, 50, Color.BLACK);
circles.add(circle);
run();
}
public static void run() {
physics.timer.start();
}
}
import java.awt.*;
public class Circle {
private int x;
private int y;
private double xAccel= 0;
private double yAccel = 0;
private double xVel= 0;
private double yVel = 0;
private Color colour;
private int radius;
public Circle(int x, int y, int radius, Color colour) {
setX(x);
setY(y);
setRadius(radius);
setColour(colour);
}
public void draw(Graphics2D g2d) {
g2d.setColor(colour);
g2d.fillOval(x, y, radius*2, radius*2);
}
public void doPhysics() {
hitGround();
System.out.println(yVel);
yVel += Physics.getGravity();
y -= yVel;
}
public void hitGround() {
if(y + radius*2 > Frame.panel.h ) {
yVel = -yVel;
}
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setColour(Color colour) {
this.colour = colour;
}
public void setRadius(int radius) {
this.radius = radius;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColour() {
return colour;
}
public int getRadius() {
return radius;
}
}
import java.awt.*;
import javax.swing.*;
class Frame extends JFrame {
public static Panel panel;
public Frame() {
panel = new Panel();
this.setTitle("Fun");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
class Panel extends JPanel {
public int w = 500;
public int h = 500;
public Panel() {
this.setPreferredSize(new Dimension(w, h));
this.setBackground(Color.red);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(Circle circle : Main.circles) {
circle.draw(g2d);
}
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Physics implements ActionListener {
private static double gravity = -.1;
public Timer timer;
public Physics() {
timer = new Timer(1, this);
}
public static double getGravity() {
return gravity;
}
#Override
public void actionPerformed(ActionEvent e) {
for(Circle circle : Main.circles) {
circle.doPhysics();
}
Main.frame.repaint();
}
}
The problem is mainly caused by using integer values for position (x and y). On each iteration the values are rounded and the errors get accumulated.
Solution: declare double x and double y and only use the rounded integer values for drawing.
Above should reduce the problem, but not completely solve it. The code is doing a rough integration over time¹ by using the velocity calculated after the time interval (see Numerical Integration). This can be improved by doing an average of the velocities before and after it was changed. Roughly:
double preVel = yVel;
yVel += Physics.getGravity();
y -= (preVel + yVel)/2;
which can be simplified (pure math) to:
yVel += Physics.getGravity();
y -= yVel - Physics.getGravity()/2;
This should work fine since the acceleration is constant. Not the case if the acceleration is also changing. And it is also susceptible to precision errors being accumulated over time.
1 - see Numerical integration and Temporal discretization

JPannel not having the size setted in the setSize method

In my program I'm adding a JPannel that I'm using as canvas to a JFrame. The problem is that the size of the JPannel#setSize() is not what it is displayed.
I first had a problem more or less like this one and I asked here
Java questions about coordinates with Graphics
They toldme to add the JPannel and use the pack() method and it worked but I can't get it to work now because the JFrame is larger than the JPannel where I am drawing.
I have look at some threads to see if I coud fiand an answer but I wasn't succesfull. Here are the threads I looked:
Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
Why the JProgressBar doesn't respect the setSize()?
Component setSize method in FlowLayout object
setSize() not working?
setSize not influencing size of button
Why does the JFrame setSize() method not set the size correctly?
java.AWT - setSize() method
Java JPannel not Visible
I create a JFrame with setSize(600, 400); and I add the pane. Here is the code
import java.awt.Dimension;
import javax.swing.JFrame;
import me.nemo_64.particlessimulation.util.Canvas;
public class Frame extends JFrame {
private Frame(String title) {
super(title);
setResizable(false);
setSize(600, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(null);
init();
}
private void init() {
canvas = new Canvas();
canvas.setSize(400, 400);
canvas.setLocation(0, 0);
canvas.setPreferredSize(new Dimension(400, 400));
canvas.startDrawing();
add(canvas);
}
private Canvas canvas;
public static Frame getInstance() {
if (instance == null)
throw new IllegalAccessError("instanceFrame must be callen at least ones before this method");
return instance;
}
public static Frame instanceFrame(String title) {
if (instance != null)
return getInstance();
instance = new Frame(title);
return getInstance();
}
private static Frame instance;
private static final long serialVersionUID = 1L;
}
And here is the canvas class
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
public class Canvas extends ACanvas {
Vector p, dir;
float v;
public Canvas() {
p = new Vector(0, getHeight() / 2);
dir = new Vector(50f, 50f);
v = 50;
}
#Override
public void update(float delta) {
if (p.x <= 0 && dir.x < 0)
dir.x *= -1;
if (p.y <= 0 && dir.y < 0)
dir.y *= -1;
if (p.x + 100 >= getWidth() && dir.x > 0)
dir.x *= -1;
if (p.y + 100 >= getWidth() && dir.y > 0)
dir.y *= -1;
Vector a = dir.clone().multiply(delta);
p.add(a);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(e.getX() + " " + e.getY());
}
#Override
public void draw(Graphics2D g) {
System.out.println(g);
fill(255, 0, 0);
fillRectangle(p.x, p.y, 100, 100);
}
}
And here is the ACanvas class
package me.nemo_64.particlessimulation.util;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;
public abstract class ACanvas extends JPanel
implements KeyListener, MouseInputListener, MouseWheelListener, Drawable, Updateable, FigureDrawer {
private Graphics2D g;
private Thread drawThread;
private Color backgroundColor;
private Color actualColor;
private long lastTime = 0;
private float delta = 0;
public ACanvas() {
setFocusable(true);
addKeyListener(this);
addMouseListener(this);
addMouseWheelListener(this);
lastTime = System.currentTimeMillis();
drawThread = new Thread(() -> {
while (true)
repaint();
}, "Drawing thread");
}
#Override
/**
* Used to update all the components to be drawn
*/
public abstract void update(float delta);
/**
* Draws all the comsponents
*/
public void draw(Graphics2D g) {}
#Override
public Graphics2D getGraphics2D() {
return this.g;
}
#Override
/**
* Draws all the comsponents
*/
public void draw(Graphics g) {
this.g = (Graphics2D) g;
draw(this.g);
}
#Override
public void paint(Graphics g) {
super.paint(g);
delta = (System.currentTimeMillis() - lastTime) * 0.001f;
lastTime = System.currentTimeMillis();
clearBackground(g);
update(delta);
g.setColor(actualColor);
draw(g);
}
public void clearBackground(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
}
public void startDrawing() {
if (!drawThread.isAlive())
drawThread.start();
}
public void stopDrawing() {
if (drawThread.isAlive())
drawThread.interrupt();
}
public void background(Color c) {
backgroundColor = c;
}
public void background(int c) {
backgroundColor = new Color(c);
}
public void background(int r, int g, int b) {
backgroundColor = new Color(r, g, b);
}
public void background(float r, float g, float b) {
backgroundColor = new Color(r, g, b);
}
public void fill(Color c) {
actualColor = c;
g.setColor(c);
}
public void fill(int c) {
fill(new Color(c));
}
public void fill(float r, float g, float b) {
fill(new Color(r, g, b));
}
public void fill(int r, int g, int b) {
fill(new Color(r, g, b));
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseDragged(MouseEvent e) {}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {}
#Override
public void keyPressed(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyTyped(KeyEvent e) {}
}
It doen't seem to work in the height. In the canvas class I have a mouse click event that displays the position of the click. The width I click and the output is a coordenade like (0, ?) for the left and (400, ?) for the right. The problem is the height, at the top I get (?, 0) but at the bottom the highest value I could get is (?, 370) and not (?, 400). My question is: why the bottom doesn't go to (?, 400)?
Thanks for the help, if something is not clear just ask it
EDIT:
Other clases of the program are:
A vector class:
public class Vector {
public float x, y, z;
public Vector(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector(float x, float y) {
this(x, y, 0);
}
public Vector() {
this(0f, 0f, 0f);
}
public Vector multiply(float... values) {
for (float f : values) {
x *= f;
y *= f;
z *= f;
}
return this;
}
public Vector divide(float... values) {
for (float f : values) {
x /= f;
y /= f;
z /= f;
}
return this;
}
public Vector add(Vector... vectors) {
for (Vector v : vectors)
add(v.x, v.y, v.z);
return this;
}
public Vector add(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public Vector add(float x, float y) {
return add(x, y, 0);
}
public Vector remove(Vector... vectors) {
for (Vector v : vectors)
remove(v.x, v.y, v.z);
return this;
}
public Vector remove(float x, float y, float z) {
this.x -= x;
this.y -= y;
this.z -= z;
return this;
}
public Vector remove(float x, float y) {
return remove(x, y, 0);
}
public Vector normalize() {
double mod = module();
this.x /= mod;
this.y /= mod;
this.z /= mod;
return this;
}
public double module() {
return Math.sqrt(moduleSquared());
}
public double moduleSquared() {
return (double) (x * x + y * y + z * z);
}
public Vector clone() {
return new Vector(x, y, z);
}
#Override
public String toString() {
return "[ " + x + ", " + y + ", " + z + "]";
}
}
A drawing interface:
package me.nemo_64.particlessimulation.util;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
public interface FigureDrawer {
default public void fillRectangle(float x, float y, float width, float height) {
getGraphics2D().fill(new Rectangle2D.Float(x, y, width, height));
}
default public void drawRectangle(float x, float y, float width, float height) {
getGraphics2D().draw(new Rectangle2D.Float(x, y, width, height));
}
default public void fillCircle(float x, float y, float r) {
fillCircle(x, y, r, r);
}
default public void drawCircle(float x, float y, float r) {
drawCircle(x, y, r, r);
}
default public void fillCircle(float x, float y, float r1, float r2) {
getGraphics2D().fill(new Ellipse2D.Float(x, y, r1, r2));
}
default public void drawCircle(float x, float y, float r1, float r2) {
getGraphics2D().draw(new Ellipse2D.Float(x, y, r1, r2));
}
public Graphics2D getGraphics2D();
}
And the Drawable and Updateable interfaces:
package me.nemo_64.particlessimulation.util;
public interface Updateable {
/**
* Called when the component must be updated
* #param delta The seconds that past between calls
*/
public void update(float delta);
}
package me.nemo_64.particlessimulation.util;
import java.awt.Graphics;
public interface Drawable {
/**
* Called when the component must be drawn
*/
public void draw(Graphics g);
}
I see a lot of comments here (all valid) but the question you're asking is why the canvas is showing something like ~ 370 instead of 400 on the right hand side (if I read this correctly).
Your canvas is probably x,y(400,400) but the parent container is only 400px wide based on your initial call. There's a good chance your window border and other operating system specific elements are adding quite a few pixels (on Windows Vista/7 I seem to remember this was ~30px) so there's a really good chance that's the problem.
As a side note (having written some particle simulations in Java/Processing) I can say you might want to look at the OpenGL style of positioning using floats from -1.0f/1.0f representing your canvas rather than trying to do everything in integers. First, you're going to have a lot of choppy "bounces" working with integers as you're going to want to represent values between pixels. Secondly, this makes resizing your simulation to an arbitrary x/y width very easy.
https://learnopengl.com/Getting-started/Coordinate-Systems
Good luck with it, I stopped writing GUIs in Java five or six years ago so I'm a bit rusty. Null layouts can be problematic, I would recommend picking a layout manager and using setPreferredSize (GridBag was my favorite).

Failed to implement object rotation towards mouse JAVA [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
As title say, just can't do it. Attempted for long time and still fail. (I'm new to java)
My Image or fillRect rotate a little bit but not as it should rotate
Whole code +imgs
*MAIN game class*
package game.main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
public class game extends Canvas implements Runnable{
private static final long serialVersionUID = -392333887196083915L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Handler handler;
public game(){
handler = new Handler();
new window(WIDTH, HEIGHT,"Game",this);
handler.addObject(new Player(WIDTH/2-32, HEIGHT/2-32, ID.Player, handler));
}
public synchronized void start(){
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop(){
try{
thread.join();
running = false;
}catch(Exception e){
e.printStackTrace();
}
}
// ↓ game loop for update
public void run(){
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.print("FPS:" + frames);
frames = 0;
}
}
stop();
}
private void tick(){
handler.tick();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
public static void main(String args[]) {
new game();
}
}
<br>
package game.main;
import java.awt.Graphics;
public abstract class GameObject {
protected float x, y;
protected ID id;
protected float velX, velY;
public GameObject(float x, float y, ID id){
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick();
public abstract void render(Graphics g);
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public float getX(){
return x;
}
public float getY(){
return y;
}
public void setId(ID id){
this.id = id;
}
public ID getId(){
return id;
}
public void setVelX(int velX){
this.velX = velX;
}
public void setVelY(int velY){
this.velY = velY;
}
public float getVelX(){
return velX;
}
public float getVelY(){
return velY;
}
}
*GameObject class*
package game.main;
import java.awt.Graphics;
public abstract class GameObject {
protected float x, y;
protected ID id;
protected float velX, velY;
public GameObject(float x, float y, ID id){
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick();
public abstract void render(Graphics g);
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public float getX(){
return x;
}
public float getY(){
return y;
}
public void setId(ID id){
this.id = id;
}
public ID getId(){
return id;
}
public void setVelX(int velX){
this.velX = velX;
}
public void setVelY(int velY){
this.velY = velY;
}
public float getVelX(){
return velX;
}
public float getVelY(){
return velY;
}
}
*Handler class*
package game.main;
import java.awt.Graphics;
import java.util.LinkedList;
// render all objects
public class Handler {
LinkedList<GameObject> object = new LinkedList<GameObject>();
public void tick(){
for(int i = 0; i < object.size(); i++){
GameObject tempObject = object.get(i);
tempObject.tick();
}
}
public void render(Graphics g){
for(int i = 0; i <object.size();i++){
GameObject tempObject = object.get(i);
tempObject.render(g);
}
}// handling adding objects
public void addObject(GameObject object){
this.object.add(object);
}
}
*window class*
package game.main;
import java.awt.Canvas;
import java.awt.Dimension;
import javax.swing.JFrame;
public class window extends Canvas{
private static final long serialVersionUID = 3010486623466540351L;
public window(int width, int height, String title, game game){
JFrame frame = new JFrame(title);
frame.setPreferredSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
// X button
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// ¤ button maximize
frame.setResizable(false);
// window appear in middle of screen instead of top left corner
frame.setLocationRelativeTo(null);
// add game to window
frame.add(game);
frame.setVisible(true);
game.start();
}
}
* ID class*
package game.main;
public enum ID {
Player();
}
ADDED code only to this class
*Player class*
package game.main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
public class Player extends GameObject{
Handler handler;
public Player(int x, int y, ID id, Handler handler) {
super(x, y, id);
this.handler = handler;
}
public void tick() {
}
public void render(Graphics g) {
///////////ADDED//////////////////
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
int mouseX = (int) b.getX();
int mouseY = (int) b.getY();
int centerX = game.WIDTH / 2;
int centerY = game.HEIGHT / 2;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
((Graphics2D)g).rotate(angle, centerX, centerY);
//////////////////////////////
g.setColor(Color.white);
g.fillRect((int)x, (int)y, 32, 32);
}
}
How it now works and how I want it. WHITE COLOR - original/ GREEN - I want it like that
Example 1
Example 2
I looked in this sources:
Get mouse possition (stackoverflow)
Java 2d rotation in direction mouse point (stackoverflow)
Rotating an object to point towards the mouse
The problem is that MouseInfo.getPointerInfo().getLocation(); returns the absolute mouse location. You need the mouse location relative to your game canvas. You can modify the render method in your game class as follows:
Point mouseLocation = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(mouseLocation, this);
handler.render(g, mouseLocation);
This requires you to modify the method signatures of your rendering methods accordingly. This is only one way to pass the mouseLocation from your game canvas to your Player's rendering method.
Use the mouseLocation instead of MouseInfo.getPointerInfo().getLocation(); in your Player's render method.
There are a few more things you have to change to place the player in the center of the canvas and make him rotate around his center:
You should set the size of the game canvas instead of the size of the window(JFrame). Do this by calling setPreferredSize(new Dimension(width, height)); on the game canvas and by calling frame.pack() before frame.setVisible(true). This will ensure that your game canvas has exactly the size specified by WIDTH and HEIGHT.
You could add two fields refx and refy to your GameObject class which describe the reference point of your GameObject (e.g. its center). You could then construct a new Player by calling new Player(WIDTH/2-16, HEIGHT/2-16, 16, 16, ID.Player, handler) where the player's initial position is at (WIDTH/2-16, HEIGHT/2-16) and its reference point is (16,16) - the center of the player when the player is represented by a 32x32 rectangle.
In the Player's render method initialize the center you want to rotate around with int centerX = Math.round(x + refx); int centerY = Math.round(y + refy); where (x,y) is the position of the object you want to rotate and (refx, refy) the point you want to rotate around relative to the object's position (e.g. x = WIDTH/2-16, y = HEIGTH/2-16, refx = 16, refy = 16).

Java 2d space gravity not working

I am trying to make a 2d game in java with realistic physics. The game is supposed to be set in space from a top down view. The best way I can explain the view is to use this link: 3d graph found one gooogle images with search "3d graph xyz". The view is supposed to be set so that you are looking from the top of the +y towards the -y.
In the game I currently only have it showing one sun and one planet to test the gravity. However, when I run the game the planet only moves away from the sun in a towards the bottom right. I believe this to be due to me misusing the equation when moving it to java. For reference the equations I used were Newton's Law of Universal Gravitation (F=(G*M1*M2)/D^2) and Newton's Second Law of Motion (F=MA, but used as A=F/M).
In short, My question is what did I do wrong with my equations? I will post all my code below, but fair warning it is designed to be expanded upon so there is a lot of excess currently.
Thanks for any help in advance.
Core class:
package src.main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import src.main.input.Input;
import src.main.input.InputHandler;
import src.main.map.Map;
public class Core extends JPanel
{
private static InputHandler iHandler = new InputHandler();
private static Input input = new Input(iHandler);
private long ticks;
private Map map;
public static Dimension SIZE;
public static Random rand = new Random();
public Core(Dimension d)
{
setPreferredSize(d);
SIZE = d;
ticks = 0;
map = new Map(SIZE.width, SIZE.height);
start();
}
public synchronized void update()
{
ticks++;
iHandler.update(ticks);
/*if (iHandler.getWheelRotation() != 0)
{
int i = iHandler.getWheelRotation();
map.changeMagnification(i > 0);
if (i > 0)
i--;
else
i++;
iHandler.setWheelRotation(i);
if (i < 0 && map.getMagnification() == 0)
iHandler.setWheelRotation(0);
if (i > 0 && map.getMagnification() == Map.MAX_MAGNIFY)
iHandler.setWheelRotation(0);
}*/
map.update(ticks);
}
public synchronized void paintComponent(Graphics g2)
{
Graphics2D g = (Graphics2D) g2;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, SIZE.width, SIZE.height);
map.draw(g);
}
public void start()
{
Thread thread = new Thread()
{
public void run()
{
while (true)
{
long time = System.currentTimeMillis();
update();
repaint();
time = (1000 / 128) - (System.currentTimeMillis() - time);
if (time > 0)
{
try
{
Thread.sleep(time);
} catch (Exception ex)
{
ex.printStackTrace();
}
}
}
}
};
thread.start();
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getDefaultConfiguration().getBounds();
public void run()
{
JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new Core(new Dimension(r.width, r.height)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.addKeyListener(input);
frame.addMouseListener(input);
frame.addMouseMotionListener(input);
frame.addMouseWheelListener(input);
}
});
}
}
Map Class:
package src.main.map;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import src.main.Core;
import src.main.celestials.SolarSystem;
public class Map
{
private int magnification;
public static final int MAX_MAGNIFY = 15;
private ArrayList<SolarSystem> systems = new ArrayList<SolarSystem>();
public Map(int x, int y)
{
SolarSystem s=new SolarSystem(new Point(500,500), "sun", (int) (1.9891 * Math.pow(10, 30)));
s.addPlanet(new Point(550, 550), "planet");
systems.add(s);
}
public void update(long ticks)
{
for(int i = 0; i < systems.size(); i++)
systems.get(i).update(ticks);
}
public void draw(Graphics2D g)
{
g.setColor(Color.DARK_GRAY);
magnification= 1;
for(int i=0; i<systems.size(); i++)
{
systems.get(i).draw(g, magnification);
}
}
public int getMagnification()
{
return magnification;
}
public void changeMagnification(boolean bigger)
{
if (bigger)
magnification++;
else
magnification--;
if (magnification > MAX_MAGNIFY)
magnification = MAX_MAGNIFY;
if (magnification < 1)
magnification = 1;
}
}
Body Class:
package src.main.celestials;
import java.awt.Point;
import src.main.Core;
import src.main.map.Map;
public abstract class Body
{
protected String name;
protected double x, y, mass;
public Body(Point t, String s, int m)
{
x = t.x;
y = t.y;
name = s;
mass = m;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getMass() {
return mass;
}
public void setMass(double mass) {
this.mass = mass;
}
public abstract void update(long ticks);
}
SolarSystem Class:
package src.main.celestials;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import src.main.celestials.Planet;
public class SolarSystem extends Body {
private ArrayList<Planet> planets = new ArrayList<Planet>();
private BufferedImage[] images = new BufferedImage[7];
private BufferedImage sun;
public SolarSystem(Point t, String s, int m) {
super(t, s, m);
try
{
String loc = System.getProperty("user.home") + "\\Desktop\\Proof of Concept Game\\Proof of Concept Game\\Gravity Test\\Suns\\";
images[0] = ImageIO.read(new File(loc + "Sun_Blue.png"));
images[1] = ImageIO.read(new File(loc + "Sun_BlueWhite.png"));
images[2] = ImageIO.read(new File(loc + "Sun_Orange.png"));
images[3] = ImageIO.read(new File(loc + "Sun_Red.png"));
images[4] = ImageIO.read(new File(loc + "Sun_White.png"));
images[5] = ImageIO.read(new File(loc + "Sun_Yellow.png"));
images[6] = ImageIO.read(new File(loc + "Sun_YellowWhite.png"));
} catch (Exception e)
{
e.printStackTrace();
}
sun = images[(int) (Math.random() * images.length)];
}
//earth mass:5.97219 × 10^24KG
//sun mass: 1.9891 × 10^30KG
//sun/earth ratio: 333060.4016
#Override
public void update(long ticks) {
// run interactions between planets and solar systems
for(int i=0; i<planets.size(); i++)
{
planets.get(i).setxAccel(genAccelX(i));
planets.get(i).setyAccel(genAccelY(i));
}
// update using acceleration and velocity
for(int i=0; i<planets.size(); i++)
{
planets.get(i).update(ticks);
}
}
public void addPlanet(Point point, String name)
{
planets.add(new Planet(point, name, (int) (5.97219*Math.pow(10, 24))));
}
/*public double genAccel(int i)
{
double G=6.67*Math.pow(10, -11);
double Dx=Math.pow(planets.get(i).getX()-getX(), 2);
double Dy=Math.pow(planets.get(i).getY()-getY(), 2);
double D=Math.sqrt(Dx+Dy);
return G*planets.get(i).getMass()/Math.pow(D, 2);
}
public double genAccelX(int i)
{
double Dx=Math.pow(planets.get(i).getX()-getX(), 2);
double Dy=Math.pow(planets.get(i).getY()-getY(), 2);
double D=Math.sqrt(Dx+Dy);
double A=genAccel(i);
return Dx*A/D;
}
public double genAccelY(int i)
{
double Dx=Math.pow(planets.get(i).getX()-getX(), 2);
double Dy=Math.pow(planets.get(i).getY()-getY(), 2);
double D=Math.sqrt(Dx+Dy);
double A=genAccel(i);
return Dy*A/D;
}*/
public double genAccelX(int i)
{
double x1=0;
double x2=0;
/*if(getX()>planets.get(i).getX())
{*/
x1=getX();
x2=planets.get(i).getX();
/*}
else
{
x1=planets.get(i).getX();
x2=getX();
}*/
double G=6.67e-11;
double d=x1-x2;
d*=d;
planets.get(i).setxForce((G*getMass()*planets.get(i).getMass())/d);
return planets.get(i).getxForce()/planets.get(i).getMass();
}
public double genAccelY(int i)
{
double y1=0;
double y2=0;
/*if(getY()<planets.get(i).getY())
{*/
y1=getY();
y2=planets.get(i).getY();
/*}
else
{
y1=planets.get(i).getY();
y2=getY();
}*/
double G=6.67e-11;
double d=y1-y2;
d*=d;
planets.get(i).setyForce((G*getMass()*planets.get(i).getMass())/d);
return planets.get(i).getyForce()/planets.get(i).getMass();
}
public void draw(Graphics2D g, int magnification) {
g.drawImage(sun, (int)(x) * magnification + 2, (int)(y) * magnification + 2, 50, 50, null);
for(int i=0; i<planets.size(); i++)
{
g.setColor(Color.PINK);
g.fillOval((int)planets.get(i).getX(), (int)planets.get(i).getY(), 20, 20);
}
}
}
Planet Class:
package src.main.celestials;
import java.awt.Point;
public class Planet extends Body {
double xForce, yForce, xAccel, yAccel, xVel, yVel;
public Planet(Point t, String s, int m) {
super(t, s, m);
}
public double getxForce() {
return xForce;
}
public void setxForce(double xForce) {
this.xForce = xForce;
}
public double getyForce() {
return yForce;
}
public void setyForce(double yForce) {
this.yForce = yForce;
}
public double getxAccel() {
return xAccel;
}
public void setxAccel(double xAccel) {
this.xAccel = xAccel;
}
public double getyAccel() {
return yAccel;
}
public void setyAccel(double yAccel) {
this.yAccel = yAccel;
}
public double getxVel() {
return xVel;
}
public void setxVel(double xVel) {
this.xVel = xVel;
}
public double getyVel() {
return yVel;
}
public void setyVel(double yVel) {
this.yVel = yVel;
}
#Override
public void update(long ticks) {
xVel+=xAccel;
yVel+=yAccel;
x+=xVel;
y+=yVel;
System.out.println("X: "+(int)x+"\t\t"+"Y: "+(int)y);
System.out.println("XVel: "+xVel+"\t\t"+"YVel: "+yVel);
System.out.println("XAccel: "+xAccel+"\t"+"YAccel: "+yAccel);
}
}
First of all, concerning your comment
I thought I was in the java forum?
(also #PM77-1 :) StackOverflow is not a forum at all! Also see https://meta.stackexchange.com/a/92110 . It is a "Question And Answer" site, and this imposes some constraints on how you should ask, and what to expect as a response. (Actually, the fact that I'm writing this here is already a "violation" of these rules, and I'm risking downvotes for that). The question in its current form is hardly suitable for any site of the StackExchange network. If you write a question here, then you should ...
Include a clear and focussed question (namely, one that goes beyond "What is wrong with my code?")
Provide Minimal, Complete, and Verifiable example (preferably, if possible and appropriate, as a single code block, with no dependencies to other, unrelated classes, and no dependencies to external resources etc.)
That said, regarding your actual "question": The formula that you are using is correct. But it is not properly implemented. The formula is
(according to Wikipedia)
The "r" refers to the distance between the centers of mass of the objects.
In your code, you tried to implement this in the SolarSystem#genAccelX and SolarSystem#genAccelY methods:
...
double x1=0;
double x2=0;
x1=getX();
x2=planets.get(i).getX();
double G=6.67e-11;
double d=x1-x2;
d*=d;
planets.get(i).setxForce((G*getMass()*planets.get(i).getMass())/d);
return planets.get(i).getxForce()/planets.get(i).getMass();
But the problem is that you are computing this separately for x and for y. Thus, the resulting force is losing its actual direction (and is "wrong" anyhow).
To put it simply: The d that you are computing there is negative, because the planet should move to the left. But by taking d*=d, it becomes positive (and this, the planet is moving to the right)
The solution:
You should describe all positions, velocities and forces as vectors instead of computing everything separately for x and y. Basically, it will boil down to a class like
class Vector {
private double x, y;
// Setters, getters...
....
double distanceSquared(Vector other) {
double dx = x - other.x;
double dy = y - other.y;
return Math.sqrt(dx*dx+dy*dy);
}
double distance(Vector other) {
return Math.sqrt(distanceSquared(other));
}
// Some other useful methods:
double length() { ... }
void normalize(double factor) { ... }
void scale(double factor) { ... }
void add(Vector other) { ... }
void addScaled(double factor, Vector other) { ... }
void sub(Vector other) { ... }
Vector difference(Vector other) { ... }
}
Given such a class, the method for computing the force and acceleration could roughly look like this:
// The bodies here may be the sun and a planet:
public double computeForceStrength(Body body0, Body body1)
{
double G=6.67e-11;
Vector position0 = body0.getPosition();
Vector position1 = body1.getPosition();
double distanceSquared = position0.distanceSquared(position1);
// The formula from wikipedia:
double f = G * body0.getMass() * body1.getMass() / distanceSquared;
return f;
}
void performSomeTimeStep(Body body0, Body body1)
{
Vector direction = position1.difference(position0);
direction.normalize();
double f = computeForceStrength(body0, body1);
body0.getVelocity().addScaled(direction, f / body0.getMass());
body1.getVelocity().addScaled(direction, -f / body1.getMass());
}
(just to show the basic idea - again: There are many degrees of freedom)
There are several other (stylistic) issues with the code, but ... when it is working, you may want to submit it to https://codereview.stackexchange.com/ ....

Call an method of a class in an array - Java

I am having a problem with a project.
So basically what I have is a class Shape with some sub-class ( ShapeRectangle, ShapeTriangle, etc ).
In each sub-class, I got an outputShape method:
g.fillRect(getX(), getY(), getWidth(), getHeight());
In another class, showShapes, I got an array that contains the sub-classes.
I would like to run the method via the array.
Is there any way to do it?
EDIT:
The array in showShapes is a Shape[] array.
Here are the code of ShapeRect ( sorry, bits are in french ):
import java.awt.Color;
import java.awt.Graphics;
public class FormeRectangulaire extends Forme {
public FormeRectangulaire(int x, int y, int width, int height){
setX(x);
setY(y);
setWidth(width);
setHeight(height);
setColor(Color.RED);
}
public void afficherForme(Graphics g){
g.setColor(getColor());
g.fillRect(getX(), getY(), getWidth(), getHeight());
}
}
Here is the shape:
import java.awt.Color;
import java.awt.Graphics;
public class Forme {
private int x;
private int y;
private int width;
private int height;
private Color color;
/*public void afficherForme(Graphics g){
afficherForme(g);
}*/
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Color getColor(){
return color;
}
public void setColor(Color color){
this.color = color;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
And here is how I put each class inside the array:
public void creerArrayFormes(){
String[][] donnes = getDatas();
if(donnes[getDatasElement()][0].equals("CARRE") || donnes[getDatasElement()][0].equals("RECTANGLE")){
FormeRectangulaire rect = new FormeRectangulaire(Integer.parseInt(donnes[getDatasElement()][1]),Integer.parseInt(donnes[getDatasElement()][2]),Integer.parseInt(donnes[getDatasElement()][3]),Integer.parseInt(donnes[getDatasElement()][4]));
setFormes(rect, getDatasElement());
}
}
You must create an array object or a List of SuperClass :
List<Form> shapes = new ArrayList<Form>();
//List<Form> shapes = new ArrayList<>(); in JDK 7
shapes.add(new ShapeRectangle());
shapes.add(new ShapeTriangle());
//....
Create a loop to get the objects :
for(int i = 0; i<shapes.size();i++){
Object obj = shapes.get(i);
if(objinstanceof ShapeRectangle){
((ShapeRectangle)obj).fillRect(....);
}
else if(list.get(i)
}
I strongly recommend adding outputShape to the Shape class. If Shape is naturally abstract (no expectation of actually creating a new Shape()) it can be abstract.
If you do that, you can just iterate over your Shape[] and call outputShape for an element. That will call the version of outputShape for the actual class of the element:
for(Shape s: shapes) {
s.outputShape();
}

Categories