LibGDX - How to slow down update() method? - java

I'm trying to recreate Space Invaders in LibGDX to get grip on game-developing but when I try to set every enemy (for now they are just squares) to move in sequence the update() method makes them change their postitions way too fast. Is there some way to slow down this rendering on whole project or any other proper way to solve this? I also tried to handle movement in Timer class and scheulde it but it caused memory overload and threads weren't fired in the same time for every object.
package regularmikey.objects;
import java.util.Timer;
import java.util.TimerTask;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
public class Aliens {
public float x;
public float y;
public float fx;
public float fy;
public int step_count = 0;
public Aliens(float x, float y) {
this.fx = this.x = x;
this.fy = this.y = y;
};
public void update(float dt){
if(step_count == 10) {
step_count = 0;
y = y - 1;
x = fx;
}
x = x + 3;
step_count++;
};
PlayState class
package regularmikey.gamestates;
import java.util.ArrayList;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import regularmikey.managers.GameStateManager;
import regularmikey.objects.Aliens;
import regularmikey.objects.Bullet;
import regularmikey.objects.Player;
public class PlayState extends GameState {
private Player player;
private ArrayList<Bullet> bullets;
private ArrayList<Aliens> aliens;
private ShapeRenderer sr;
public PlayState(GameStateManager gsm) {
super(gsm);
}
#Override
public void init() {
sr = new ShapeRenderer();
bullets = new ArrayList<Bullet>();
aliens = new ArrayList<Aliens>();
player = new Player(bullets);
spawnAliens();
}
#Override
public void update(float dt) {
player.update(dt);
for(int i = 0; i < aliens.size(); i++) {
aliens.get(i).update(dt);
}
}
public void spawnAliens() {
aliens.clear();
float i, j;
for(j = 100; j <= 510; j = j + 45) {
for(i = 250; i <= 445; i = i + 45) {
aliens.add(new Aliens(j, i));
}
}
}
#Override
public void draw() {
player.draw(sr);
for(int i = 0; i < aliens.size(); i++) {
aliens.get(i).draw(sr);
}
}
#Override
public void handleinput() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
// TODO Auto-generated method stub
}
}
public void draw(ShapeRenderer sr) {
sr.setColor(1, 1, 1, 1);
sr.begin(ShapeType.Line);
sr.rect(x, y, 30, 30);
sr.end();
};
}

The key here is the dt variable that is passed along with the update() method, which is short for Delta Time.
Delta time is a commonly used factor in game development that represents the time that has passed since the last frame.
I can't exactly make out the way you are making your aliens move about, but the usual way to make entities in your game move smoothly (regardless of the frame rate):
void update(float deltaTime){
this.position = currentPosition + (this.movementSpeed × deltaTime);
}
This doesn't take into consideration the direction in which the entity is moving, amongst others. But that is besides the point of this example.
So, in your case, you could so something like this:
package regularmikey.objects;
import java.util.Timer;
import java.util.TimerTask;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
public class Aliens {
public float x;
public float y;
public float fx;
public float fy;
public int step_count = 0;
private float moveTimer;
private float moveTreshold;
public Aliens(float x, float y) {
this.fx = this.x = x;
this.fy = this.y = y;
moveTimer = 0; // This will act as a stopwatch
moveTreshold = 3000; // Alien will move once it passes this treshold
};
public void update(float dt){
// check whether we passed the treshold for moving or not
if(moveTimer += dt; > moveTreshold){
if(step_count == 10) {
step_count = 0;
y = y - 1;
x = fx;
}
x = x + 3;
step_count++;
moveTimer = 0; // reset the timer
}
};

Related

Particles not rendering

I put in a particle system but when i run the program, when I spawn some particles, they don't render. I looked at the ArrayList and its value would always be 0 even when i added a particle to it.
heres the code for main class:
package Main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import me.mango.rendering.Particle;
//do double buffering
public class Game extends JPanel {
private static final long serialVersionUID = 1L;
public static final int height = 400;
public static final int width = height * 16 / 9;
JPanel p;
Game game;
Graphics g;
JFrame frame;
KeyListener kl;
MouseListener ml;
public boolean running = true;
private ArrayList<Particle> particles = new ArrayList<Particle>(500);
public Game(){
kl = new KeyListener(){
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
};
ml = new MouseListener(){
public void mousePressed(MouseEvent e) {
addParticle(true);addParticle(false);addParticle(true);
addParticle(false);addParticle(true);addParticle(false);
}
public void mouseReleased(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
};
}
public void addParticle(boolean b){
int dx,dy;
int x = 100;
int y = 100;
if(b){
dx = (int) (Math.random()*5);
dy = (int) (Math.random()*5);
}else{
dx = (int) (Math.random()*-5);
dy = (int) (Math.random()*-5);
}
int size = (int) (Math.random()*12);
int life = (int) Math.random()*(120)+380;
particles.add(new Particle(x,y,dx,dy,size,life,Color.blue));
}
public void update(double delta){
for(int i = 0; i<= particles.size() - 1;i++){
if(particles.get(i).update()) particles.remove(i);
}
System.out.println(particles.size());
}
#Override
public void paint(Graphics g){
g.clearRect(0, 0, getWidth(), getHeight());
//render here
renderParticles(g);
g.dispose();
}
public void renderParticles(Graphics g){
for(int i =0;i <= particles.size() - 1;i++){
particles.get(i).render(g);
System.out.println("spawned");
}
}
public void run(){
//initialize time loop variables
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
double lastFpsTime = 0;
//Main game loop
while(running)
{
//Calculate since last update
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double)OPTIMAL_TIME);
//update frame counter
lastFpsTime += updateLength;
//update FPS counter
if(lastFpsTime >= 1000000000)
{
lastFpsTime = 0;
}
//game updates
game.update(delta);
//graphics (gameState)
game.repaint();
try{
Thread.sleep((Math.abs(lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000));
}catch(Exception e){
System.out.println("Error in sleep");
}
}
}
public void start(){
frame = new JFrame("Game");
game = new Game();
frame.add(game);
frame.pack();
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.addKeyListener(kl);
frame.addMouseListener(ml);
frame.setVisible(true);
run();
}
public static void main(String[] args){
new Game().start();
}
}
and for the particle class:
package me.mango.rendering;
import java.awt.Color;
import java.awt.Graphics;
public class Particle {
private int x;
private int y;
private int dx;
private int dy;
private int size;
private int life;
private Color color;
public Particle(int x, int y, int dx, int dy, int size, int life, Color c){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.size = size;
this.life = life;
this.color = c;
}
public boolean update(){
x += dx;
y += dy;
life--;
if(life <= 0){
return true;
}
return false;
}
public void render(Graphics g){
g.setColor(color);
g.fillRect(x-(size/2), y-(size/2), size, size);
g.dispose();
}
}
Thanks!
You have a thing called game inside the class Game: that's not good design at all. Apparently you dont understand the meaning of creating an object.
In main() you created an object game: that should be enough. That thing you have to manipulate.
Therefore calling game.something() inside the class game is a convolution. Get rid of it.
game = new Game();
Game game;
These things must go.
And any reference to game.someMethod()
should be replaced with just someMethod(), if you are inside Game.
Plus you have things like run() and start() etc: do you think you are creating some threads?? by just using those names for your methods?
No.

How do I embed this into my website?

I am attempting to embed a game into my website that I programmed in java. I have no idea how to take my code from eclipse(which is what my JDE is) and put it into my website. I am using a weebly.com website. I do have several unfinished classes, I want to upload my incomplete games as well as complete just to show progress. so I ask you, how do I get this code from eclipse, to my website. Thanks for the help and the following is my code.
This is my Main class:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
public class Main extends Applet implements Runnable {
private static final long serialVersionUID = 1L;
Thread th = new Thread(this);
boolean running = true;
public int Jweidth = 400, Jheight = 400;
Image dbImage;
Graphics dbGraphics;
Bullet b;
Player p;
Enemy e, e2, e3, e4, e5, e6, e7, e8;
HealthBar hb;
NameSign ns;
Restart r;
private boolean BFire;
public void init() {
//set window size
setSize(Jweidth, Jheight);
//calls player class
p = new Player(this);
//calls healthBar
hb = new HealthBar(this, p);
//calls enemy class
e = new Enemy(this);
e2 = new Enemy(42, 0, this);
e3 = new Enemy(84, 0, this);
e4 = new Enemy(126, 0, this);
e5 = new Enemy(0, 42, this);
e6 = new Enemy(42, 42, this);
e7 = new Enemy(84, 42, this);
e8 = new Enemy(126, 42, this);
//calls bullet class
b = new Bullet(this);
//calls nameSign class
ns = new NameSign(this);
//calls Restart class
r = new Restart(this);
}
public void start() {
//starts a new thread
th.start();
}
public void stop() {
running = false;
}
public void destroy() {
running = false;
}
public void run() {
while (running) {
setBFire(b.getFire());
//calls update method from player class
p.update(this);
//calls update method from enemy class
e.update(this, p);
e2.update(this, p);
e3.update(this, p);
e4.update(this, p);
e5.update(this, p);
e6.update(this, p);
e7.update(this, p);
e8.update(this, p);
//calls update method from fire class if BFire is true
if (setBFire(true)) {
b.update(this, p);
}
//calls update method from HealthBar class
hb.update(this, p);
//calls update method from NameSign class
ns.update(this);
//calls update method from Restart class
r.update(this, p);
repaint();
//sets Thread to repeat every 17 milliseconds
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//doublebuffer
public void update(Graphics g) {
dbImage = createImage(Jweidth, Jheight);
dbGraphics = dbImage.getGraphics();
paint(dbGraphics);
g.drawImage(dbImage, 0, 0, this);
}
//paint class
public void paint(Graphics g) {
//calls paint method from player class
p.paint(g, this);
//calls paint method from enemy class
e.paint(g, this);
e2.paint(g, this);
e3.paint(g, this);
e4.paint(g, this);
e5.paint(g, this);
e6.paint(g, this);
e7.paint(g, this);
e8.paint(g, this);
//calls paint method from bullet class
b.paint(g, this);
//calls paint method from healthBar class
hb.paint(g, this);
//calls paint method from nameSign class
ns.paint(g, this);
//calls paint method from Restart class
r.paint(g);
}
public int getJweidth() {
return Jweidth;
}
public int getJheight() {
return Jheight;
}
//ignore all boolean Bfire methods
public boolean isBFire() {
return BFire;
}
public boolean setBFire(boolean bFire) {
BFire = bFire;
return bFire;
}
}
This is my Enemy class:
import java.awt.*;
import java.net.URL;
public class Enemy {
//Enemy ints
private int x = 0, y = 0, speed = 2;
private URL url;
private Image Enemy;
//adds image
public Enemy(Main m){
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
}
public Enemy(int i, int j, Main m) {
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
x = i;
y = j;
}
//same as run method but just for the enemy
public void update(Main m, Player p){
x += speed;
if(x <= 0){
speed = 2;
y += 32;
}
else if(x > m.getJweidth() - 32){
speed = -2;
y += 32;
}
//calls collision method
collision(p);
}
//enemy player hitbox
private void collision(Player p) {
int Px = p.getX();
int Py = p.getY();
int Pr = p.getRadious();
if(Px - Pr <= x && Px + Pr >= x && Py - Pr <= y && Py + Pr >= y){
p.hit();
}
}
//Graphics for enemy
public void paint(Graphics g, Main m){
g.drawImage(Enemy, x, y, m);
}
}
This is my Bullet class (this game is a work in progress and this class isn't working, but that is just unfinished work that I will do soon)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
public class Enemy {
//Enemy ints
private int x = 0, y = 0, speed = 2;
private URL url;
private Image Enemy;
//adds image
public Enemy(Main m) {
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
}
public Enemy(int i, int j, Main m) {
url = m.getDocumentBase();
Enemy = m.getImage(url, "Enemy.png");
x = i;
y = j;
}
//same as run method but just for the enemy
public void update(Main m, Player p) {
x += speed;
if (x <= 0) {
speed = 2;
y += 32;
} else if (x > m.getJweidth() - 32) {
speed = -2;
y += 32;
}
//calls collision method
collision(p);
}
//enemy player hitbox
private void collision(Player p) {
int Px = p.getX();
int Py = p.getY();
int Pr = p.getRadious();
if (Px - Pr <= x && Px + Pr >= x && Py - Pr <= y && Py + Pr >= y) {
p.hit();
}
}
//Graphics for enemy
public void paint(Graphics g, Main m) {
g.drawImage(Enemy, x, y, m);
}
}
This is my Restart class(once again unfinished but on the way)
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Restart implements KeyListener {
private int x, y;
private int pHealth;
private String string = "Would you like to play again?";
private boolean restart = false;
public Restart(Main m) {
x = 600;
y = 600;
}
public void update(Main m, Player p) {
//checks if players health = 0 and if restart is true
pHealth = p.getpHealth();
if (setRestart(true && pHealth <= 0)) {
System.out.println("Restart");
x = m.Jweidth / 2 - 75;
y = m.Jheight / 2;
}
//reset ints for player
//TODO
//reset ints for enemy
//TODO
//reset ints for bullet
//TODO
//reset ints for healthbar
//TODO
}
public void paint(Graphics g) {
g.drawString(string, x, y);
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_F1: {
setRestart(true);
break;
}
}
}
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_F1: {
setRestart(false);
break;
}
}
}
public void keyTyped(KeyEvent arg0) {
}
//ignore all boolean methods
public boolean isRestart() {
return restart;
}
public boolean setRestart(boolean restart) {
this.restart = restart;
return restart;
}
}
You will have to use Applets to embed your Java program in a browser, or Java Web Start if you just want to start it from the web in a new window.
Some security issues may apply depending on the Java version you are using.
Here are some examples on how to do it:
https://docs.oracle.com/javase/tutorial/deployment/applet/
http://www.javatpoint.com/java-applet
And here for the Java Web Start:
https://docs.oracle.com/javase/tutorial/deployment/webstart/
You're gonna need to make a .jar file and a compiled .class file, no .java file. To implement Java code in HTML, you can use the deprecated <applet> tag, or the new <object> tag.
<object codetype="application/java" classid="java:yourclass.class" archive="yourjar.jar" width="1000" height="1000"></object>
codetype="application/java" - The type of code, use application/java.
classid="?" - Java class to run, eg. java:MyApplet.class
archive="url" - Address or filename of the Java archive file (.jar) containing the class files.
width="?" - The width of the window, in pixels.
height="?" - The height of the window, in pixels.
Just telling you, I'm not sure that it'll work.

n-body simulation - IndexOutOfBoundsException occurring randomly

Let me be brief. I am creating a n-body simulation for a school-project. I've encountered a problem: I get the error IndexOutOfBoundsException only sometimes when I run the simulation. There does not seem to be any correlation between when I get the error. I am assuming I am destroying the bodies (via the collision detection method) too quickly for it to register, and it tries to access an index that no longer exists. I thought
if(bodies.get(i)!=null&&bodies.get(n)!= null)
in the update method would fix it, but it did not. Could someone take a look at the code and tell me what might be causing the error? To recreate the error: Simply press 'o' in the simulation, or randomly spawn massive bodies with 'm' until it occurs. Please keep in mind that I am only in high school, and I have not got a lot of programming experience.
MAIN:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main extends JPanel implements Runnable, KeyListener{
public static int width = 1400;
public static int height = (width/16) * 9;
public String title = "Orbital Mechanics Simulator -";
public Dimension dim = new Dimension(width, height);
public boolean running;
Color bgColor = new Color(0x000000);
public static long timeScale = (long) Math.pow(10,7.5); //how many simulation-seconds one IRL-second represents.
public static long distanceScale = ((Physics.astUnit*10L) / width); //how many meters does one pixel represent
ArrayList<Body> bodies = new ArrayList<Body>();
long initFpsTime;
long secondFpsTime;
long nowTime;
long lastTime;
long timeElapsed;
float deltaTime;
int fps = 200;
public Main(){
this.setPreferredSize(dim);
this.setBackground(bgColor);
this.start();
}
public void start(){
running = true;
Thread program = new Thread(this, "update");
program.start();
}
public void run(){
lastTime = System.nanoTime();
while(running){
nowTime = System.nanoTime();
deltaTime = nowTime - lastTime;
update(deltaTime);
initFpsTime = System.currentTimeMillis();
if((initFpsTime - secondFpsTime) > Math.pow(10,3) / fps){
render();
secondFpsTime = System.currentTimeMillis();
}
}
}
public void update(float deltaTime){
for(int i=0; i<bodies.size();i++){
resetForces();
bodies.get(i).update((float)(deltaTime / Math.pow(10,9))*timeScale);
lastTime = System.nanoTime();
//sets the forces for all bodies
for(int n=0; n<bodies.size();n++){
if(bodies.get(i)!=bodies.get(n)){
if(bodies.get(i)!=null&&bodies.get(n)!= null)
bodies.get(i).setForce(Physics.getFx(bodies.get(i), bodies.get(n)), Physics.getFy(bodies.get(i), bodies.get(n)));
//collision detection
if(Physics.getDistanceBetween(bodies.get(i), bodies.get(n)) < (bodies.get(i).radius + bodies.get(n).radius)*distanceScale){
collision(bodies.get(i),bodies.get(n));
}
}
}
}
}
//DIFFERENT SYSTEMS
public void solarSystem(){
Body sun;
Body earth;
Body mars;
sun = new Body("Sun", Physics.massSun, 20, 0,0, new Color(0xffff00), (float)0, (float)0);
earth = new Body("earth", Physics.massEarth, 10, Physics.astUnit/distanceScale,0, new Color(0x0000ff), (float)0, (float)0);
mars = new Body("Mars", Physics.massEarth, 10, (long)(1.5*Physics.astUnit/distanceScale) ,0, new Color(0x00ff00), (float)0, (float)0);
earth.setVelocity(0,(float)Physics.getInitVy((long)Physics.getDistanceBetween(earth, sun), sun));
mars.setVelocity(0,(float)Physics.getInitVy((long)Physics.getDistanceBetween(mars, sun), sun));
bodies.add(sun);
bodies.add(earth);
bodies.add(mars);
}
public void twoBodies(){
bodies.add(new Body("Sun", Physics.massSun, 20, 0,0, new Color(0xffff00), (float)0, (float)0));
bodies.add(new Body("earth", Physics.massEarth, 10, Physics.astUnit/distanceScale,0, new Color(0x0000ff), (float)0, (float)0));
bodies.add(new Body("Mars", Physics.massMars, 10, (long)(1.5*Physics.astUnit/(distanceScale)),0 ,new Color(0x00ff00), (float)0, (float)0));
//earth.setVelocity(0,(float)Physics.getInitVy((long)Physics.getDistanceBetween(earth, sun), sun));
//mars.setVelocity(0,(float)Physics.getInitVy((long)Physics.getDistanceBetween(mars, sun), sun));
}
public void createRandomBody(){
bodies.add(new Body("randomBody",Physics.massSun,10, Physics.randomXPos(), Physics.randomYPos(), Physics.randomColor(),(float)0,(float)0));
}
public void createMassiveBody(){
bodies.add(new Body("Sun",Physics.massSun,10, Physics.randomXPos(), Physics.randomYPos(), Physics.randomColor(),(float)0,(float)0));
}
public void createSmallBody(){
bodies.add(new Body("Earth",Physics.massEarth,10, 0, 0, Physics.randomColor(), (float)0, (float)0));
}
public void createSystem(){
for(int i=0; i<20;i++){
for(int n=0; n<20;n++){
bodies.add(new Body("Random", Physics.massSun, 4, -width/2 + n*20 , height/2 - i*20 , Color.WHITE, (float)0, (float)0 ));
}
}
}
public void resetForces(){
if(bodies.get(0) != null);
for(int i=0;i<bodies.size();i++){
if(i<=0 && i < bodies.size()){
bodies.get(i).resetForce();
}
}
}
public void collision(Body a, Body b){
Body newBody = new Body("newBody", a.mass+b.mass, 20, (a.xPos+b.xPos)/2, (a.yPos+b.yPos)/2, Physics.randomColor(), (a.mass*a.vx + b.mass*b.vx)/(a.mass+b.mass), (a.mass*a.vy+b.mass*b.vy)/(a.mass+b.mass));
bodies.remove(a);
bodies.remove(b);
bodies.add(newBody);
}
public void render(){
repaint();
}
public void keyPressed(KeyEvent event) {
switch(event.getKeyChar()){
case 'r': createRandomBody();
break;
case 'f': twoBodies();
break;
case 'm':
createMassiveBody();
break;
case 'z':
createSmallBody();
break;
case 'o':
createSystem();
break;
case 's':
solarSystem();
break;
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //quick vs quality - preferring quality
for(int i=0;i<bodies.size();i++){
bodies.get(i).displayPlanet(g2d);
}
}
public static void gui(){
Main main = new Main();
JFrame frame = new JFrame();
frame.setResizable(false);
frame.setTitle(main.title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(main);
frame.addKeyListener(main);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){ //Event dispatching thread
public void run(){
gui();
}
});
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
BODY
import java.awt.Color;
import java.awt.Graphics;
public class Body {
public static int xOrigo = Main.width / 2;
public static int yOrigo = ((Main.width * 9) / 16) / 2;
public static int numOfBodies; // how many bodies the program contains.
public static float distanceScale = Main.distanceScale;
public String name;
public float mass, fx, fy, accX, accY, vx, vy, initVx, initVy, deltaX, deltaY;
public long xDisplay, yDisplay;
public long xPos, yPos;
public int radius;
public Color color;
public Body(String name, float mass, int radius, long xPos, long yPos, Color color, float initVx, float initVy){
this.name = name;
this.mass = mass;
this.radius = radius;
this.color = color;
numOfBodies++;
setX(xPos);
setY(yPos);
setVelocity(initVx, initVy);
}
public void update(float deltaTime){
this.deltaX += this.vx * deltaTime;
if(this.deltaX >= distanceScale){
this.incX();
deltaX = 0;
}else if(this.deltaX <= -distanceScale){
this.decX();
deltaX = 0;
}
this.deltaY += this.vy * deltaTime;
if(this.deltaY >= distanceScale){
this.incY();
deltaY = 0;
}else if(this.deltaY <= -distanceScale){
this.decY();
deltaY = 0;
}
this.vx += (this.accX * deltaTime);
this.vy += (this.accY * deltaTime);
}
public void setX(long xPos){
this.xPos = xPos;
this.xDisplay = xOrigo + xPos - radius;
}
public void setY(long yPos){
this.yPos = yPos;
this.yDisplay = yOrigo - yPos - radius;
}
public void incX(){
this.xPos++;
this.xDisplay = xOrigo + xPos - radius;
}
public void decX(){
this.xPos--;
this.xDisplay = xOrigo + xPos - radius;
}
public void incY(){
this.yPos++;
this.yDisplay = yOrigo - yPos - radius;
}
public void decY(){
this.yPos--;
this.yDisplay = yOrigo - yPos - radius;
}
public void setForce(float fx, float fy){
this.fx += fx;
this.accX = fx / this.mass;
this.fy += fy;
this.accY = fy / this.mass;
}
public void setVelocity(float vx, float vy){
this.vx += vx;
this.vy += vy;
}
public void displayPlanet(Graphics g){
g.setColor(this.color);
g.fillOval((int )this.xDisplay, (int)this.yDisplay, this.radius*2, this.radius*2); //temporary fix
}
public long getXPos(){
return this.xPos;
}
public long getYPos(){
return this.yPos;
}
public void resetForce(){
this.fx = 0;
this.fy = 0;
}
}
PHYSICS:
import java.awt.Color;
import java.util.Random;
public class Physics {
public static Random rand = new Random();
public static final double G = 6.67384*(Math.pow(10, -11));
public static long astUnit = 149597871000L; //L IS TO INDICATE IT'S A LONG VALUE, otherwise neg value
public static float massEarth = (float)(5.97219*Math.pow(10,24));
public static float massSun = (float)(1.9891*Math.pow(10,30));
public static float massMars = (float) (6.41693*(Math.pow(10,23)));
public static float randomMass(){
return (float) Math.pow(((rand.nextDouble()*(massSun-massEarth))),rand.nextDouble())+massEarth;
}
public static double randInitV(){
return (double) rand.nextDouble()*Math.pow(10,4);
}
public static int randomXPos(){
return rand.nextInt(Main.width)-Main.width/2;
}
public static int randomYPos(){
return rand.nextInt(Main.height)-Main.height/2;
}
public static Color randomColor(){
return new Color(rand.nextInt(0xffffff));
}
public static int randomRadius(){
return rand.nextInt(50)+5;
}
public Physics(){
}
/*
public static Vector getVectorBetween(Body a, Body b){
float force = (float)((G*a.mass*b.mass) / Math.pow(getDistanceBetween(a,b),2));
double angle = Math.atan2(Math.abs(a.y - b.y),Math.abs(a.x - b.x));
Vector vector = new Vector(force,angle);
return vector;
}
*/
public static double getInitVy(long d, Body a){
return Math.sqrt((G*a.mass) / d);
}
public static float getFx(Body a, Body b){
float force = getForceBetween(a,b);
double angle = getAngleBetween(a,b);
float fx = (float)(force*Math.cos(angle));
if(a.xPos > b.xPos){
return -fx;
}else{
return fx;
}
}
public static float getFy(Body a, Body b){
float force = getForceBetween(a,b);
double angle = getAngleBetween(a,b);
float fy = (float)(force*Math.sin(angle));
if(a.yPos > b.yPos){
return -fy;
}else{
return fy;
}
}
public static float getForceBetween(Body a, Body b){
float force = (float)((G*a.mass*b.mass) / Math.pow(getDistanceBetween(a,b),2));
return force;
}
public static double getDistanceBetween(Body a, Body b){
double xKatet = Math.abs(a.getXPos()*Main.distanceScale - b.getXPos()*Main.distanceScale);
double yKatet = Math.abs(a.getYPos()*Main.distanceScale - b.getYPos()*Main.distanceScale);
double distance = Math.hypot(xKatet, yKatet);
return distance;
}
public static double getAngleBetween(Body a, Body b){
long deltaX = Math.abs(a.xPos-b.xPos);
long deltaY = Math.abs(a.yPos-b.yPos);
double angle = Math.atan2(deltaY, deltaX);
return angle;
}
}
(Given the few information and the wall of code, I may be going too far out on a limb, but in doubt, I can delete the answer)
You are accessing the same list with different threads. The collision handling method
public void collision(Body a, Body b) {
...
bodies.remove(a);
bodies.remove(b);
bodies.add(newBody);
}
is executed by the main physics thread that is started in the Main#start() method. This thread is modifying the list. And this may happen while the Swing Event Dispatch Thread (that is also reponsible for painting) is iterating over the bodies in the paintComponent method:
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
...
for(int i=0;i<bodies.size();i++){
bodies.get(i).displayPlanet(g2d);
}
}
Adding additional checks will not solve this issue. You'll need some form of synchronization. The brute-force-hammer would be to just synchronize on the bodies list:
public void collision(Body a, Body b) {
...
synchronized (bodies)
{
bodies.remove(a);
bodies.remove(b);
bodies.add(newBody);
}
}
and
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
...
synchronized (bodies)
{
for(int i=0;i<bodies.size();i++){
bodies.get(i).displayPlanet(g2d);
}
}
}
(basically, something like this would have to be done in all places where one thread might read the list while another thread is writing to the list).
But again: This is rather pragmatic. You could consider one of the thread-safe data structures from the java.util.concurrent package, or some manual, more fine-grained locking solution, probably with some ReadWriteLock.
It's far too much code to give a more focussed answer here (but at least, I wanted to point out what is (almost certainly) the reason for your problem)
You have a problem in your method Main.update(), the essentials of which are:
public void update(float deltaTime){
for(int i=0; i<bodies.size();i++){
// ...
//sets the forces for all bodies
for(int n=0; n<bodies.size();n++){
// ...
//collision detection
if(Physics.getDistanceBetween(bodies.get(i), bodies.get(n)) < (bodies.get(i).radius + bodies.get(n).radius)*distanceScale){
collision(bodies.get(i),bodies.get(n));
}
}
}
}
In the event that i is bodies.size() - 1 and there is a collision with another body, the two colliding bodies are replaced with a single body, reducing the total number of bodies by 1. At that point i is bodies.size(), which is not a valid index into bodies. You nevertheless continue the inner loop, during which you perform bodies.get(i) again, generating an IndexOutOfBoundsException.

How can I make each block move in the opposite direction once they reach a certain point on the side of the screen?

I am trying to get three different blocks to move back and forth from one side of the screen to the other. If the block on the far right reaches the game frame's width, it's velocity is reversed and it starts moving to the left side. However, my problem exists with the other two blocks. I put in my code a method that states once the second block reaches the (game width - 100), with 100 just being the width of each blocks, it's velocity should be reversed. The third block is suppose to work the same except once it reaches the x point (game width - 200). My attempt to change the velocity of the second and third blocks can be seen under the UpdateBlocks method in the PlayState class posted below.
Another thing I want to point out is that in update method in the block class, the x value is being reversed too. I tried at first to make it read the blocks from the PlayState then change the corresponding velocities but I got a thread error. That's why I am bringing my current predicament to you.
Here is the block class:
package com.jamescho.game.model;
import java.awt.Rectangle;
import com.jamescho.framework.util.RandomNumberGenerator;
import com.jamescho.game.main.GameMain;
import com.jamescho.game.state.PlayState;
public class Block {
private float x, y;
private int width, height, velX = 700;
private Rectangle rect;
private PlayState play;
private boolean visible;
private static final int UPPER_Y = 275;
private static final int LOWER_Y = 355;
public Block(float x, float y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
rect = new Rectangle((int) x, (int) y, width, height);
visible = false;
}
// Note: Velocity value will be passed in from PlayState!
public void update(float delta) {
x += velX * delta;
if (x <= 0 || x >= GameMain.GAME_WIDTH - 100) {
velX = -velX;
}
updateRect();
}
public void updateRect() {
rect.setBounds((int) x, (int) y, width, height);
}
public void invisible() {
visible = false;
}
public void visible() {
visible = true;
}
public void stop() {
velX = 0;
}
public void reverse() {
velX = -velX;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public Rectangle getRect() {
return rect;
}
}
Here is the PlayState where everything is going on:
package com.jamescho.game.state;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import com.jamescho.game.main.GameMain;
import com.jamescho.game.main.Resources;
import com.jamescho.game.model.Block;
public class PlayState extends State {
private ArrayList<Block> row1;
private ArrayList<Block> row2;
private ArrayList<Block> row3;
private Block block;
private Font scoreFont;
private int playerScore = 0;
private static final int BLOCK_HEIGHT = 100;
private static final int BLOCK_WIDTH = 100;
private int blockSpeed = -200;
private static final int PLAYER_WIDTH = 66;
private static final int PLAYER_HEIGHT = 92;
#Override
public void init() {
row1 = new ArrayList<Block>();
row2 = new ArrayList<Block>();
scoreFont = new Font("SansSerif", Font.BOLD, 25);
for (int i = 0; i < 3; i++) {
Block b = new Block(i * 105, GameMain.GAME_HEIGHT - 101,
BLOCK_WIDTH, BLOCK_HEIGHT);
row1.add(b);
b.visible();
for (int h = 0; h < 3; h++) {
Block b2 = new Block(h * 105, b.getY() - 208,
BLOCK_WIDTH, BLOCK_HEIGHT);
row2.add(b2);
b2.invisible();
}
}
}
#Override
public void update(float delta) {
playerScore += 1;
if (playerScore % 500 == 0 && blockSpeed > -280) {
blockSpeed -= 10;
}
Resources.runAnim.update(delta);// starts iterating through its frames
updateBlocks(delta);
}
private void updateBlocks(float delta) { // time from last update
for (Block b : row1) { //foreach statement; for each iteration of "b" the code is executed, one "b" at a time
if(row1.get(1).getX() == GameMain.GAME_WIDTH - BLOCK_WIDTH - 5) {
row1.get(1).reverse();
}
else if(row1.get(2).getX() == GameMain.GAME_WIDTH - 2 * BLOCK_WIDTH - 5) {
row1.get(2).reverse();
}
b.update(delta);
}
for (Block c : row2) { //foreach statement; for each iteration of "b" the code is executed, one "b" at a time
// used with objects; can't use primitive
c.update(delta);
if (c.isVisible()) {
}
}
}
#Override
public void render(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, GameMain.GAME_WIDTH, GameMain.GAME_HEIGHT);
renderPlayer(g);
renderBlocks(g);
renderScore(g);
}
private void renderScore(Graphics g) {
g.setFont(scoreFont);
g.setColor(Color.GRAY);
g.drawString("" + playerScore / 100, 20, 30);
}
private void renderPlayer(Graphics g) {
}
private void renderBlocks(Graphics g) {
for (Block b : row1) {
if (b.isVisible()) {
g.drawImage(Resources.blue_panel, (int) b.getX(), (int) b.getY(),
BLOCK_WIDTH, BLOCK_HEIGHT, null); // change null if you want the object to know about object
}
}
for (Block c : row2) {
if (c.isVisible()) {
g.drawImage(Resources.blue_panel, (int) c.getX(), (int) c.getY()+105,
BLOCK_WIDTH, BLOCK_HEIGHT, null); // change null if you want the object to know about object
}
}
}
#Override
public void onClick(MouseEvent e) {
}
#Override
public void onKeyPress(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
for (Block b : row1) {
b.stop();
for (Block c : row2) {
if (c.isVisible() == true) {
c.stop();
}
}
}
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
}
}
#Override
public void onKeyRelease(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
for (Block c: row2) {
c.visible();
}
}
}
public float getb1X() {
return row1.get(1).getX();
}
}
Sorry I haven't gone through your entire code. But this is how I would do it:
int x , int y -- are the coordinates of each block on the screen.
a block can move on the screen in 4 ways / directions / quadrants:
1) x = x + deltaX, y = y + deltaY
2) x = x - deltaX, y = y + deltaY
3) x = x + deltaX, y = y - deltaY
4) x = x - deltaX, y = y - deltaY
Thus in order to change the direction when a block hits any side you should multiply deltaX with -1 if it hits left or right side and deltaY with -1 if it hits the bottom or top. this will reverse its direction.

Loop in a JApplet animation Java

import java.awt.Graphics;
import javax.swing.JApplet;
import javax.swing.JPanel;
public class Circle extends JPanel {
int x = 75;
int y = 100;
int diameter = 50;
public void setAnimationY(int y) {
this.y = y;
}
public int getAnimationY() {
return y;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int startDiameter) {
diameter = startDiameter;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, diameter, diameter);
}
}
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BouncingBall extends JApplet {
private int speed = 5;
private Timer timer;
private Circle draw;
#Override
public void init() {
super.init();
setLayout(new BorderLayout());
draw = new Circle();
add(draw);
timer = new Timer(30, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int y = draw.getAnimationY();
int diameter = draw.getDiameter();
int roof = getHeight();
y += speed;
if (y < 0) {
y = 0;
speed *= -1;
} else if (y + diameter > roof) {
y = roof - diameter;
speed *= -1;
}
draw.setAnimationY(y);
repaint();
}
});
}
#Override
public void start() {
super.start();
timer.start();
}
#Override
public void stop() {
timer.stop();
super.stop();
}
}
I am trying to create a JApplet that contains a ball that is bouncing up and down. So far I have been able to get the ball to go up and down but now I am trying to make the ball more "life-like" so I want the height of the ball to decrease each time the ball bounces until eventually it stops.
I have attempted to do a while loop using the roof variable that I created for the getHeight() method but for some reason when I tried to use it either the ball didn't move at all or the loop had no affect on the ball.
I have also tried a for loop but I ran into the same problem that I got into with the while loop. I believe the problem is that I am not placing this for loop in the correct spot for it to work correctly.
thanks in advance.
Little modifications to your code that can give you some trails:
#Override
public void actionPerformed(ActionEvent e) {
int y = draw.getAnimationY();
int diameter = draw.getDiameter();
int roof = getHeight();
y += speed;
//
// Reduce the ball size at the bottom of the screen
//
if(y + diameter > roof) {
if(diameter > minDiameter) {
diameter -= (roof - y);
} else {
diameter = minDiameter;
}
} else if (diameter < maxDiameter) {
diameter++;
}
draw.setDiameter(diameter);
if (y < 0) {
y = 0;
speed *= -1;
} else if (y + diameter > roof) {
y = roof - diameter;
speed *= -1;
}
// Simulates a little gravity
speed += 0.5;
draw.setAnimationY(y);
repaint();
}
For more realism, the best way would to find an equation that is function of the ball position and a coefficient of hardness for the ball and would give you the ball size.
Well let use continue with #MadProgrammer's solution from your other related question:
In your class of DrawPane we can easily define the height, getAnimationHeight() and setAnimationHeight(int) to control the height decrease as soon as it touches the ground. Please remember that in java left-top co-ordinate is (0, 0) and right-bottom co-ordinate is (getWidth(), getHeight()). Suppose that it starts from height = 0(top). Then it will start from y = height(top) and eventually move to the getHeight()(bottom) of your container. We will increase the height(top y) using setAnimationHeight() by adding an amount(say 30) to current height(which getAnimationHeight() will return) .
So, this little tweak made to #MadeProgrammer's solution in your other question will be the following demo.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
public class Circle extends JApplet {
private int delta = 8;
private Timer timer;
private DrawPane drawPane;
#Override
public void init() {
super.init();
setLayout(new BorderLayout());
drawPane = new DrawPane();
add(drawPane);
timer = new Timer(100, new ActionListener() {
int frameCount = 0;
#Override
public void actionPerformed(ActionEvent e) {
int y = drawPane.getAnimationY();
int diameter = drawPane.getDiameter();
y += delta;
if (y < drawPane.getAnimationHeight()) {
y = drawPane.getAnimationHeight();
delta *= -1;
} else if (y + diameter > getHeight()) {
y = getHeight()- diameter;
delta *= -1;
int animationHeight = drawPane.getAnimationHeight();
animationHeight = animationHeight + (getHeight() - diameter - animationHeight)/2;
drawPane.setAnimationHeight(animationHeight);
if(animationHeight + diameter + 2 >= getHeight())
{
System.out.println("true");
drawPane.setAnimationY(getHeight() - diameter);
repaint();
timer.stop();
return;
}
}
drawPane.setAnimationY(y);
repaint();
}
});
}
#Override
public void start() {
super.start();
timer.start();
}
#Override
public void stop() {
timer.stop();
super.stop();
}
public class DrawPane extends JPanel {
int x = 100;
int y = 0;
int diameter = 50;
int height = 0;
public void setAnimationX(int x) {
this.x = x;
}
public void setAnimationY(int y) {
this.y = y;
}
public void setAnimationHeight(int h)
{
height = h;
}
public int getAnimationHeight()
{
return height;
}
public int getAnimationX() {
return x;
}
public int getAnimationY() {
return y;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int startDiameter) {
diameter = startDiameter;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, diameter, diameter);
}
}
}
NOTE: As soon as it touches the bottom finally, you should stop the Timer to get rid of the flickering of the ball. This task is left as an exercise for you.

Categories