i am making a game with cactus pictures but when i do my code if its trying to switch between pictures it will stops and will freeze on that point the else if it does not work i also use bufferedimage for the pictures
my code:
package objectgame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import util.Resource;
public class EnemiesManager {
private List<Enemy> enemies;
private Random random;
private BufferedImage imagecactus1, imagecactus2, imagecactus3 ;
public EnemiesManager() {
enemies = new ArrayList<Enemy>();
imagecactus1 = Resource.getResourceImage("data/cactus1.png");
imagecactus2 = Resource.getResourceImage("data/cactus2.png");
imagecactus3 = Resource.getResourceImage("data/cactus3.png");
random = new Random();
enemies.add(getRandomCactus());
random = new Random();
}
public void update() {
for(Enemy e: enemies) {
e.update();
}
Enemy firstEnemy = enemies.get(0);
if(firstEnemy.isOutOfScreen()) {
enemies.remove(firstEnemy);
enemies.add(getRandomCactus());
}
}
public void draw(Graphics g) {
for(Enemy e: enemies) {
e.draw(g);
}
}
private Cactus getRandomCactus() {
Cactus cactus;
cactus = new Cactus();
cactus.setX(600);
if(random.nextBoolean()) {
cactus.setImage(imagecactus1);
}
else{
cactus.setImage(imagecactus2);
}
return cactus;
}
}
new class
package objectgame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import util.Resource;
public class Cactus extends Enemy{
private BufferedImage image;
private int posX, posY;
private Rectangle rect;
public Cactus() {
image = Resource.getResourceImage("data/cactus1.png");
posX = 200;
posY = 83;
rect = new Rectangle();
}
public void update() {
posX -= 3;
rect.x = posX;
rect.y = posY;
rect.width = image.getWidth();
rect.height = image.getHeight();
}
#Override
public Rectangle getBound() {
return rect;
}
#Override
public void draw(Graphics g) {
g.drawImage(image, posX, posY, null);
}
public void setX(int x) {
posX = x;
}
public void setY(int y) {
posY = y;
}
public void setImage(BufferedImage images) {
this.image = images;
}
#Override
public boolean isOutOfScreen() {
return (posX + image.getWidth() < 0);
}
}
what is the problem this is the code from the anamation manager and the details from the picture. I have tried many tutorials but none where working correct always slightly off the purpose for the random bool. I use eclipse so I don't get any errors specific to the location where the error happens. I also did use debugger but non are working. So I really need your guys help.
A clean approach is as follows:
private Cactus getRandomCactus() {
Cactus cactus = new Cactus();
cactus.setX(600);
BufferedImage [] images = {imagecactus1, imagecactus2, imagecactus3};
cactus.setImage(images[random.nextInt(3)]);
return cactus;
}
Note: random.nextInt(3) returns an int from 0 to 2 i.e. either 0 or 1 or 2.
There are a couple reasons you could be running into issues, the main one being the fact that you're called Random.nextBoolean() multiple times. When you do that, it gives you a new value each time. You'd want to set a variable equal to Random.nextBoolean().
Also, since you appear to be choosing between three different images, rather than two. For this, I recommend you use Random.nextInt instead:
private Cactus getRandomCactus() {
Cactus cactus;
cactus = new Cactus();
int randomInt = random.nextInt(0, 3); // this only called random.nextInt once, and gives me a random number between 0 and 2
cactus.setX(600);
if(randomInt == 0) {
cactus.setImage(imagecactus1);
}
else if (randomInt == 1) {
cactus.setImage(imagecactus2);
}
else {
cactus.setImage(imagecactus3);
}
return cactus;
}
the problem what that there where 2 files called cactus3.png and also there was one space to much. thanks for thinking with me .
Related
I am trying to code a very simple Pong-game, I think that is the name of this old game where a ball bounces between the player and a bunch of bricks with the ball going up and down. The player can move horizontally at the bottom.
So basically just some moving rectangles, eventually they are supposed to collide and so on.
However, I can allow the player to move the Rectangle with the buttons, but I can't manage to make objects move with the help of the AnimationTimer. (javafx.animation.AnimationTimer)
I already searched a lot but only found examples with mistakes that I managed to avoid.
(eg. like this AnimationTimer & JavaFX: Rectangle won't move horizontally using the setTranslateX() method. How to move Rectangle?).
I tried debugging it to see where the unexpected happens, but I couldn't find it. here is my code:
package bounceBall;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.control.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class BounceBallApp extends Application {
private Pane root = new Pane();
private Sprite player = new Sprite(400, 500, 40, 4, "player", Color.BLUE);
private boolean play;
private Parent createContent() {
this.play = false;
root.setPrefSize(800, 600);
root.getChildren().add(player);
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
update();
}
};
timer.start();
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 40; x++) {
Sprite s = new Sprite(20*x, y*8, 18, 5, "brick", Color.AQUA);
root.getChildren().add(s);
}
}
return root;
}
private List<Sprite> getSprites(){
List<Sprite> list = new ArrayList<Sprite>();
for (Node n : root.getChildren()) {
if (n instanceof Sprite) {
Sprite s = (Sprite)n;
list.add(s);
}
}
return list;
}
private void update() {
getSprites().forEach(b -> {
if (b.type.equals("bullet")) {
b.moveRight(b.getXspeed());
b.moveDown(b.getYspeed());
}
});
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createContent());
scene.setOnKeyPressed(e -> {
//as soon as any key gets hit the game starts with the shoot method
if (play == false) {
shoot(player);
play = true;
}
switch (e.getCode()) {
case A:{
player.moveLeft(10);
break;
}
case D:{
player.moveRight(10);
break;
}
default:
break;
}
});
primaryStage.setScene(scene);
primaryStage.setTitle("Bounce Ball");
primaryStage.show();
}
/*this method should be called once at the beginning to initiate the ball
the ball appears but it doesn't move, instead remains still
if I try to make the player move with AnimationTimer it doesn't work either, it works just by pressing keys*/
private void shoot(Sprite who) {
Sprite s = new Sprite((int)who.getTranslateX(), (int)who.getTranslateY()-2, 4, 4, "bullet", Color.BLACK);
s.setYspeed(-10);
root.getChildren().add(s);
System.out.println(root.getChildren().size());
}
private static class Sprite extends Rectangle {
final String type;
private int Xspeed, Yspeed;
public Sprite(int x, int y, int w, int h, String type, Color color) {
super(w, h, color);
this.type = type;
setTranslateX(x);
setTranslateY(y);
Xspeed = 0;
Yspeed = 0;
}
public void moveLeft(int d) {
setTranslateX(getTranslateX() - d);
}
public void moveRight(int d) {
setTranslateX(getTranslateX() + d);
}
public void moveUp(int d) {
setTranslateX(getTranslateY() - d);
}
public void moveDown(int d) {
setTranslateX(getTranslateY() + d);
}
public int getXspeed() {
return Xspeed;
}
public int getYspeed() {
return Yspeed;
}
public void setXspeed(int xspeed) {
Xspeed = xspeed;
}
public void setYspeed(int yspeed) {
Yspeed = yspeed;
}
}
public static void main(String[] args) {
launch(args);
}
}
I expect the ball to go straight up at the beginning but it appears at the wrong position (ca. 50px right from where I expect).
Most importantly it doesn't move.
Thanks a lot in advance.
I'm trying to learn Graphics2D library while building small games such as 2D car games, platformer games and so on... Today I decided to make a space-based game and obvoiusly in space you need stars. So I decided to use fillOval() to draw small circles which would give the effect of night-sky. BUT, whenever I try to move the stars or any other object, the older frames just stay there and a bunch of layers are drawn one after another. I thought that dipose() method would be enough... but it seems like it aint.What options do I have to fix this problem?
Here's a preview of what it looks like when i run the code.
Main.java (irrelevant code filtered out)
package asteroids;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
public class Main extends Canvas implements KeyListener {
private boolean gameOver;
private BufferStrategy backBuffer;
private Dimension dimension = new Dimension(Config.WINDOW_WH[0], Config.WINDOW_WH[1]);
private List<Star> stars = new ArrayList<Star>();
private HashMap<Integer,Boolean> keyDownMap = new HashMap<Integer, Boolean>();
private Ship ship;
public Main() {
// Initialize Window
initWindow();
addKeyListener(this);
this.createBufferStrategy(2);
backBuffer = this.getBufferStrategy();
// init variables
gameOver = false;
// Generating stars
generateStars();
// Init spaceship
ship = new Ship(25,36,"ship.png");
// Init loop
gameLoop();
}
public void initWindow(){
JFrame window = new JFrame("Asteroids");
setPreferredSize(dimension);
window.add(this);
window.pack();
window.setResizable(false);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBackground(new Color(54, 71, 99));
window.requestFocus();
}
public void update() {
if(keyDownMap.containsKey(KeyEvent.VK_ESCAPE)){
gameOver = false;
System.exit(0);
}
/*for(Star s: stars) {
s.update(keyDownMap);
}*/
this.ship.update(keyDownMap);
}
public void render(){
Graphics2D g = (Graphics2D) backBuffer.getDrawGraphics();
// Stars
for(Star s: stars) {
g.fillOval(s.posx - (s.width/2), s.posy - (s.height/2), s.width, s.height);
}
// Spaceship
g.drawImage(
this.ship.getImage(),
this.ship.posx, this.ship.posy,
this.ship.width, this.ship.height, null);
g.dispose();
backBuffer.show();
}
public void generateStars() {
for(int i = 0;i < 20;i++) {
int starX = new Random().nextInt(Config.WINDOW_WH[0]-10)+5;
int starY = new Random().nextInt(Config.WINDOW_WH[1]-10)+5;
stars.add(new Star(starX, starY));
}
}
public void gameLoop(){
while(!gameOver){
update();
render();
try{ Thread.sleep(20);}catch(Exception e){};
}
}
public static void main(String[] args) {
new Main();
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
keyDownMap.put(e.getKeyCode(), true);
}
#Override
public void keyReleased(KeyEvent e) {
keyDownMap.remove(e.getKeyCode());
}
}
Star.java
package asteroids;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.HashMap;
import java.util.Random;
public class Star {
int width, height;
int posx, posy;
/** CONSTRUCTOR **/
public Star(int x, int y) {
int rand = new Random().nextInt(Config.STAR_SIZES.length);
width = Config.STAR_SIZES[rand];
height = Config.STAR_SIZES[rand];
posx = x;
posy = y;
}
public void update(HashMap keyDownMap) {
if(keyDownMap.containsKey(KeyEvent.VK_LEFT))
this.posx += 1;
if(keyDownMap.containsKey(KeyEvent.VK_RIGHT))
this.posx -= 1;
if(keyDownMap.containsKey(KeyEvent.VK_UP))
this.posy += 1;
if(keyDownMap.containsKey(KeyEvent.VK_DOWN))
this.posy -= 1;
}
}
Ship.java
package asteroids;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import javax.swing.ImageIcon;
public class Ship {
public int posx, posy;
public int width, height;
private Image image;
public Ship(int w, int h, String img) {
this.posx = Config.WINDOW_WH[0]/2;
this.posy = Config.WINDOW_WH[1]/2;
this.width = w;
this.height = h;
this.image = new ImageIcon(getClass().getResource("/"+img)).getImage();
}
public Image getImage() {
return this.image;
}
public void setPosx(int x) {posx = x;}
public void setPosy(int y) {posy = y;}
public void setImg(Image img) {
this.image = img;
}
public void update(HashMap keyDownMap) {
if(keyDownMap.containsKey(KeyEvent.VK_LEFT))
this.posx += 1;
if(keyDownMap.containsKey(KeyEvent.VK_RIGHT))
this.posx -= 1;
if(keyDownMap.containsKey(KeyEvent.VK_UP))
this.posy += 1;
if(keyDownMap.containsKey(KeyEvent.VK_DOWN))
this.posy -= 1;
}
}
Config.java
import java.awt.Color;
public class Config {
// MAIN CANVAS SETTINGS
public static int[] WINDOW_WH = {500, 500};
public static String WINDOW_BG_IMG = "";
public static Color WINDOW_BG_CLR = new Color(40, 42, 45);
// OBJECT SETTINGS
public static int[] STAR_SIZES = {10,5,8,3,7};
}
EDIT:
After I tried to add a background image g.drawImage(this.bg,0,0,Config.WINDOW_WH[0], Config.WINDOW_WH[1], null); before drawing stars and the ship, it doesn't happen anymore. But im wondering if this is a fix or just a bad practice for avoiding the un-cleared frames.
BUT, whenever I try to move the stars or any other object, the older frames just stay there and a bunch of layers are drawn one after another.
Yes, that's how painting works. Think of the Graphics context like a physical canvas. Each time you paint on it, you are adding more more content to it. The API won't clear it for you.
There advantages to this, if you're performing an additive painting process, you may not wish to refresh it on each pass, but in your case, you're going to have to clear it each time.
I thought that dipose() method would be enough... but it seems like it aint
No, dispose releases any internal resources the context might be holding, freeing up memory. Having said that, you shouldn't dispose of a context you did create, as it can prevent future operations from been applied.
If you take a look at the example from the tutorials it clear shows the Graphics context been clear/prepared for each frame...
Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
g.setColor(COLORS[i]);
g.fillRect(0,0,bounds.width, bounds.height);
bufferStrategy.show();
g.dispose();
}
I would also recommend having a look at the example in the JavaDocs which presents a basic loop operation
I am making a clone of Flappy Bird. I was doing just fine performance-wise: 60 fps. This was when it had 1 pillar/obstacle only. As soon as I added 3 of them my fps dropped to 30 and below. Then game is unplayable now. I get that this has something to do with doing repaint() all the time.
Here is the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
/**
* Created by Lazar on 25/05/15.
*/
public class Environment extends JComponent implements ActionListener {
public static final Dimension dimension = new Dimension(800,600);
BufferedImage img;
BufferedImage ptica1;
BufferedImage ptica2;
double skokbrojac = 0;
int brzina = 4; // speed // MUST Background % brzina = 0
int dx;
int dx2;
int pad = 0; //drop
Timer timer;
boolean parno;
boolean skok = false;
//Stubovi // Pillars
Stub stub1 = new Stub();
Stub stub2 = new Stub();
Stub stub3 = new Stub();
ArrayList<Stub>stubovi = new ArrayList<Stub>();
int razmakStub; // Space between pillars
public Environment() {
setPreferredSize(dimension);
img = Util.openImage("pozadina.png");
ptica1 = Util.openImage("ptica1.png");
ptica2 = Util.openImage("ptica2.png");
stubovi.add(stub1);
stubovi.add(stub2);
stubovi.add(stub3);
dx = img.getWidth()/2;
timer = new Timer(1000/60,this);
timer.start();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
skok = true; // start jump
skokbrojac = 0; //jump frame counter
}
});
}
protected void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D)g;
//g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
if(dx == img.getWidth()){ //image horizontal scroll
dx2 = 0;
}
if(dx2 == img.getWidth()/2){ //image horizontal scroll
dx = dimension.width;
}
g2d.drawImage(img,getWidth() - dx, 0, null); //draw background
if(dx >= img.getWidth()){
g2d.drawImage(img,getWidth() - dx2, 0, null);
}
if(parno){
g2d.drawImage(ptica1,dimension.width/2, 290 + pad, null); //draw bird
}
else{
g2d.drawImage(ptica2,dimension.width/2, 290 + pad, null); //draw bird
}
stub1.postoji = true; //pillar1 exists?
if(razmakStub > 240){
stub2.postoji = true;
}
if(razmakStub > 480){ //pillar1 exists?
stub3.postoji = true;
}
for(Stub i : stubovi){ //draw pillars if they exist
if(i.postoji)
i.crtaj(g2d);
}
}
#Override
public void actionPerformed(ActionEvent e) {
dx = dx + brzina;
dx2 = dx2 + brzina;
if(skokbrojac > 5) // jump frame lenght
skok = false;
if(skok){
pad -= 15; // jump height
}
else{
pad += 8; //rate of the fall
}
skokbrojac++;
parno ^= true; // for different bird images
if(290 + pad >= 536 || 290 + pad<= 3) //border hit detect
timer.stop();
razmakStub += brzina;
for(Stub i : stubovi){ //reset pillars and make them move
if(i.postoji){
if(i.getDx() < -50){
i.setDx(800);
i.randomDy();
}
i.setDx(i.getDx() - brzina);
}
}
repaint();
}
}
Complete project source
Also bear in mind this is really unpolished version so the code is ugly. I am looking for a solution to boost performance.
Main Class:
import javax.swing.*;
/**
* Created by Lazar on 25/05/15.
*/
public class Main {
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Frame(new Environment());
}
});
}
}
Frame class:
import javax.swing.*;
/**
* Created by Lazar on 25/05/15.
*/
public class Frame extends JFrame{
public Frame(JComponent content){
setContentPane(content);
setTitle("Flappy");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(getPreferredSize());
setResizable(false);
setVisible(true);
setLocationRelativeTo(null);
}
}
Stub/Pillar class:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* Created by Lazar on 26/05/15.
*/
public class Stub {
BufferedImage dole;
BufferedImage gore;
Random r = new Random();
int dx = 700;
int dy = r.nextInt(250) + 250;
boolean postoji = false;
public void crtaj(Graphics2D g2d){
dole = Util.openImage("stub_dole.png");
gore = Util.openImage("stub_gore.png");
g2d.drawImage(dole, dx, dy, null);
g2d.drawImage(gore, dx, -(560-dy), null);
}
public void setDx(int dx) {
this.dx = dx;
}
public void randomDy(){
this.dy = r.nextInt(250) + 250;
}
public int getDx() {
return dx;
}
}
Ptica/Brid class:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
/**
* Created by Lazar on 26/05/15.
*/
public class Ptica {
BufferedImage ptica1;
BufferedImage ptica2;
boolean ptica;
boolean skok = false;
int pad = 0;
double skokBrojac = 0;
public Ptica(){
ptica1 = Util.openImage("/slike/ptica1.png");
ptica2 = Util.openImage("/slike/ptica2.png");
}
public void crtajPticu(Graphics g2d){
ptica ^= true;
if(ptica){
g2d.drawImage(ptica1, Environment.dimension.width/2, Environment.dimension.height/2-110 + pad, null);
}
else{
g2d.drawImage(ptica2, Environment.dimension.width/2, Environment.dimension.height/2-110 + pad, null);
}
System.out.println(pad);
}
public void setSkok(boolean skok) {
this.skok = skok;
}
public void setSkokBrojac(double skokBrojac) {
this.skokBrojac = skokBrojac;
}
public double getSkokBrojac() {
return skokBrojac;
}
public boolean isSkok() {
return skok;
}
public void setPad(int pad) {
this.pad = pad;
}
public int getPad() {
return pad;
}
}
Util class:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* Created by Lazar on 25/05/15.
*/
public class Util {
public static BufferedImage openImage(String name){
try {
if(!name.startsWith("/slike/")){
name="/slike/"+name;
}
return ImageIO.read(Util.class.getResource(name));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Avoid adding all you classes to the default package, this could cause issues with class loading on some versions of Java
Painting should paint the state and should not be making decisions or changing the state
Don't, repeatedly, load resources
For example, from you Stub class, which Environment's paintComponent calls crtaj, you do the following...
public void crtaj(Graphics2D g2d){
dole = Util.openImage("stub_dole.png");
gore = Util.openImage("stub_gore.png");
g2d.drawImage(dole, dx, dy, null);
g2d.drawImage(gore, dx, -(560-dy), null);
}
Loading the images can take time. You should either have a "cache" class which managers them (loading them once) or load them when the Stub class is created (I'd prefer the cache class, as if you create and destroy many Stubs, loading the resources within the Stub class (constructor for example) could become a bottle neck
For example, which was able to go from 200-300 objects moving simultaneously, to over 4000 through the use of a re-usable object cache (rather the re-creating the objects and re-loading their resources)
Use a profiler to determine where you code is actually spending time (Note that YourKit has a 15 day free trial license available).
Once you know what your bottleneck is then determine if there's an easy fix, if not consider better algorithms and data-structures to reduce the algorithmic complexity of your code.
Profiling, as suggested by #alex-fitzpatrick, is always good. Also:
Is the type of images created by your Util.openImage call compliant with the graphics2D object you paint on? You may be spending some with the conversions (image types).
eliminate calls to getWidth() etc. You know these values after object initialization, cache them.
If possible, don't call repaint on the entire component. Use the overloaded version that specifies the area to repaint.
... and consider using JavaFX for games :-)
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/ ....
Alright, so I've been trying to move my polygon so it bounces around the screen. Right now it does so but leave a trail the entire way. I have a GUI class, extended by an Aquarium class, which fills the screen with the color blue, creates a "creature" object (from Creature class) and uses update to move it down the screen. When it updates however, a trail is left behind. I have tried many methods mentioned in similar cases on the site but nothing works. Can somebody please help me?
GUI class (that holds JPanel etc)
package artilife;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AquariumGUI {
private GooPanel gooPanel;
private boolean loop = true;
protected int width, height;
private int frameTimeInMillis = 300;
private RenderingHints renderingHints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
#SuppressWarnings("serial")
class GooPanel extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHints(renderingHints);
draw(g2d);
}
}
public AquariumGUI() {
this(800, 500);
}
public AquariumGUI(int w, int h) {
width = w;
height = h;
JFrame frame = new JFrame();
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gooPanel = new GooPanel();
gooPanel.setPreferredSize(new Dimension(w, h));
frame.getContentPane().add(gooPanel);
frame.pack();
frame.setVisible(true);
}
public void go() {
while (loop) {
gooPanel.repaint();
update();
try {
Thread.sleep(frameTimeInMillis);
} catch (InterruptedException e) {
}
}
}
public void draw(Graphics2D g) {
}
public void update(){
}
public void setFrameTime(int millis){
frameTimeInMillis = millis;
}
}
Aquarium class that extended this and attempts to color the screen and place a Polygon creature on it:
package artilife;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Random;
public class MyAquarium extends AquariumGUI {
Creature tester;
public MyAquarium()
{
tester = new Creature();
}
public void draw(Graphics2D g) {
// Fill background
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
tester.draw(g);
}
public void update(){
tester.move(width, height);
}
public static void main(String[] args) {
MyAquarium aquarium = new MyAquarium();
aquarium.go();
}
}
And the creature that is being drawn, and holds the move method:
package artilife;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Creature
{
// Position and radius of the drop
private double x, y, r, Vx, Vy;
Polygon p = new Polygon();
int numSides;
public Creature() {
x = 800 / 2;
r = 10;
y = 50;
Vx = 10;
Vy = 3;
numSides = 3;
//creatureShape(numSides);
}
public void creatureShape (int sides)
{
if (sides <= 10){
for (int i = 0; i < sides; i++){
p.addPoint((int) (x + 50 * Math.cos((i) * 2 * Math.PI / sides)),
(int) (y + 50 * Math.sin((i) * 2 * Math.PI / sides)));
}
}
else{
for (int i = 0; i < 360; i++) {
double value = i / 360.0;
p.addPoint((int) (90 + 50 * value * Math.cos(8 * value * Math.PI)),
(int) (50 + 50 * value * Math.sin(8 * value * Math.PI)));
}
}
}
public void draw(Graphics2D g) {
creatureShape(numSides);
g.setColor(Color.BLUE);
g.fillPolygon(p);
}
public void move(int width, int height){
// Move the drop
x = x + Vx;
y = y +Vy;
if (y >= height){
Vy = -Vy;
y = height;
}
else if(y <= 0){
Vy = -Vy;
y = 0;
}
if(x >= width){
Vx = -Vx;
x = width;
}
if(x <= 0){
Vx = -Vx;
x = 0;
}
}
/*
public void attraction ()
{
if (
}*/
/*
public boolean check4Creatures ()
{
boolean isThere = false;
//if there is an another create object within a 60 point radius
isThere = true;
return isThere;
}*/
}
SOLUTION:
So fiddle for what feels like forever and it works now.
When drawing polygons in motion, some java functions store bits of information regarding the vertices. The best way to move them cleanly is to use translate() instead of manipulating the vertices directly (by updating x and y values) when updating the information, and then draw the fresh polygon.
Thank everyone for taking the time to look at my problem though!
You need to clear the screen between two drawing operations. You can either leave it to the framework, by calling the super.paintComponent() method, or you can do it your way, by filling the screen with something, like a g.fillRect() call.
The first method will actually make a call the the fillRect function, using the panel background color.