Good day, I'm new to StackOverflow and Java programming. I currently have a school project that needs multi threading and I just need your advice on how to fix my code. I have spent too much time looking for answers on how to create a moving multiple images using a thread. I knew I'm almost near to find the solution but I'm running out of time as the submission is fast approaching. I believed I'll be more efficient if I seek help from somehow who knows better in Java.
Many thanks in advance.
Below is my current code, and it seems that image is flickering while moving.
// Bounce.java
import javax.swing.JFrame;
public class Bounce {
public static void main(String args[]) {
myBall s = new myBall(10, 20, 2, 2);
myBall s1 = new myBall(100, 10, 2, 2);
myBall s2 = new myBall(40, 10, 2, 2);
JFrame f = new JFrame();
f.add(s);
f.add(s1);
f.add(s2);
f.setVisible(true);
f.setSize(600, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Moving Ball");
}
}
The next code is in separate file.
// myBall.java
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class myBall extends JPanel implements Runnable {
private Thread animator;
int x = 0, y = 0, velX = 2, velY = 2;
Timer t;
public myBall(int x, int y, int velX, int velY) {
JFrame jf = new JFrame();
jf.setSize(600,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(this);
jf.setVisible(true);
this.x = (int )(Math.random() * 560);
this.y = (int )(Math.random() * 360);
this.velX = velX;
this.velY = velY;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(ellipse);
}
public void cycle() {
if(x < 0 || x > 560) {
velX = -velX;
}
if(y < 0 || y > 360) {
velY = -velY;
}
x += velX;
y += velY;
System.out.println(x);
}
#Override
public void run() {
while(true) {
for (int i = 0; i < 600; i++) {
cycle();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
}
}
Here you go. I normally don't do this, but you asked nicely and your code was pretty clean, so I assumed you been working a lot on it.
public class Start {
public static void main(String args[]) {
JFrame f = new JFrame();
Gui gui = new Gui();
gui.addBalls();
f.add(gui);
f.setSize(600, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Moving Ball");
f.setVisible(true);
}
}
Class GUI:
public class Gui extends JPanel implements Runnable {
private Thread animator;
int x = 0, y = 0, velX = 2, velY = 2;
Timer t;
ArrayList<myBall> myBalls = new ArrayList<>();
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (myBall ball: myBalls) {
int x = ball.getX();
int y = ball.getY();
Ellipse2D ellipse = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(ellipse);
}
}
public void cycle() {
for (myBall ball: myBalls) {
int x = ball.getX();
int y = ball.getY();
if(x < 0 || x > 560) {
ball.reverseX();
}
if(y < 0 || y > 360) {
ball.reverseY();
}
ball.move();
System.out.println(x);
}
}
#Override
public void run() {
while(true) {
for (int i = 0; i < 600; i++) {
cycle();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
}
public void addBalls() {
for (int i = 0; i < 4; i++) {
int x = (int )(Math.random() * 560);
int y = (int )(Math.random() * 360);
int velX = -5;
int velY = 5;
myBalls.add(new myBall(x, y, velX, velY));
}
}
}
Class Ball:
public class myBall {
int x;
int y;
int velX;
int velY;
public myBall(int x, int y, int velX, int velY) {
this.x = (int )(Math.random() * 560);
this.y = (int )(Math.random() * 360);
this.velX = velX;
this.velY = velY;
}
public void move() {
x+=velX;
y+=velY;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void reverseX() {
velX = -velX;
}
public void reverseY() {
velY = -velY;
}
}
Related
I have obtained from somewhere else a Java Swing code for a bouncing Ball. The code uses a class "Ball" which extends a JPanel.
Can Anyone help me converting this code to extends JFrame instead.
I want to do that so I could be able to call it from another frame class.
Here is the code:
public class Ball extends JPanel{
int x=0, y=0;
int angleX = 1, angleY = 1;
public void move(){
if (x + angleX <0) {
angleX =1;
} else if (x + angleX >getWidth()-50){
angleX =-1;
} else if (y + angleY <0) {
angleY =1;
} else if (y + angleY >getHeight()-50){
angleY =-1;
}
x = x + angleX;
y = y + angleY;
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 50, 50);
}
public static void main(String[] args){
JFrame jfrm= new JFrame("BounceBall");
jfrm.setSize(400,400);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrm.setVisible(true);
Ball bl = new Ball();
Component add = jfrm.add(bl);
while (true){
bl.move();
bl.repaint();
try{
Thread.sleep(10);
}catch(InterruptedException e){
}
}
}
}
Just extend JFrame and make some constructor for Ball class.
You can make an instance from Ball class from any other JFrame classes.
Ball bl = new Ball();/*then call methods*/
Or just call Balls main method in two ways:
Ball.main(null);
String args[]={/*some arguments*/}; Ball.main(args);
Here is your Ball class which now extends JFrame
import java.awt.Graphics;
import javax.swing.JFrame;
public class Ball extends JFrame {
public Ball() {
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
int x = 0, y = 0;
int angleX = 1, angleY = 1;
public void move() {
if (x + angleX < 0) {
angleX = 1;
} else if (x + angleX > getWidth() - 50) {
angleX = -1;
} else if (y + angleY < 0) {
angleY = 1;
} else if (y + angleY > getHeight() - 50) {
angleY = -1;
}
x = x + angleX;
y = y + angleY;
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 50, 50);
}
public static void main(String[] args) {
Ball bl = new Ball();
while (true) {
bl.move();
bl.repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}
}
I am new to Java and I'm creating a basic 'mini tennis game' I would like for the score to increase by one point each time the ball makes contact with the racket. I already have the score displayed on the screen at 0 but I don't know how to make it increase. I would greatly appreciate any help you could give me. Here is the code I have so far:
Game class
private int score = 0;
Ball ball = new Ball(this);
SecondBall ball2 = new SecondBall(this);
Racquet racquet = new Racquet(this);
public Game() {
addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
});
setFocusable(true);
}
private void move() {
ball.move();
ball2.move();
racquet.move();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
ball2.paint(g2d);
racquet.paint(g2d);
**//Show score on screen
String s = Integer.toString(score);
String sc = "Your score: ";
g.drawString(sc, getWidth()-150, 50);
g.drawString(s, getWidth()-50, 50);**
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "You Suck!!", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Mini Tennis");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
}
Ball Class
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
private int score = 0;
private String yourScoreName;
public Ball(Game game) {
this.game = game;
}
public void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > game.getWidth() - DIAMETER)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > game.getHeight() - DIAMETER)
game.gameOver();
if (collision()) {
ya = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x + xa;
y = y + ya;
}
private boolean collision() {
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
public Rectangle getBounds() {
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
You already have a collision method which returns true if the ball collides with your racquet. So you can easily increment your score:
if (collision()) {
ya = -1;
y = game.racquet.getTopY() - DIAMETER;
score++; //// like this
}
Just an advice, by copy pasting a tutorial you wont learn it. Start at the beggining.
JavaGame.java
public class JavaGame extends JFrame implements Runnable {
static Rectangle object = new Rectangle(60, 60, 50, 50);
static Rectangle object1 = new Rectangle(60, 60, 50, 50);
int x, y, xDirection, yDirection;
static AI AI = new AI(object);
static BI BI = new BI(object1);
private Image dbImage;
private Graphics dbg;
Image face;
public void run(){
try{
while(true){
move();
Thread.sleep(2);
}
}catch(Exception e){
System.out.println("ERROR");
}
}
public void move(){
x += xDirection;
y += yDirection;
if(y<=25)
y = 25;
if(y>=350)
y = 350;
if(x<=5)
x = 5;
if(x>=520)
x = 520;
}
public void setXDirection(int xdir){
xDirection = xdir;
}
public void setYDirection(int ydir){
yDirection = ydir;
}
public class AL extends KeyAdapter{
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_W){
setYDirection(-1);
}
if(keyCode == e.VK_S){
setYDirection(+1);
}
if(keyCode == e.VK_A){
setXDirection(-1);
}
if(keyCode == e.VK_D){
setXDirection(+1);
}
}
public void keyReleased(KeyEvent f){
int keyCode = f.getKeyCode();
if(keyCode == f.VK_W){
setYDirection(0);
}
if(keyCode == f.VK_S){
setYDirection(0);
}
if(keyCode == f.VK_A){
setXDirection(0);
}
if(keyCode == f.VK_D){
setXDirection(0);
}
}
}
public static final int WIDTH = 640, HEIGHT = 480;
public JavaGame(){
ImageIcon i = new ImageIcon("C:/Users/admin/workspace/Project/src/ProjectGame/Player.gif");
face = i.getImage();
addKeyListener(new AL());
setTitle("Java Game");
setSize(WIDTH, HEIGHT);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x=WIDTH/2;
y=HEIGHT/2;
}
public void paint(Graphics g){
dbImage = createImage(getWidth(),getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage,0,0,this);
}
public void paintComponent(Graphics g){
g.setColor(Color.RED);
g.fillOval(x, y, 50, 50);
g.drawImage(face, x, y, this);
AI.paint(g);
BI.paint(g);
repaint();
}
public static void main(String[] arg){
JavaGame jg = new JavaGame();
Thread t = new Thread(jg);
t.start();
Thread t1 = new Thread(AI);
t1.start();
Thread t2 = new Thread(BI);
t2.start();
}
}
AI.java
public class AI implements Runnable {
Rectangle AI;
int xDirection, yDirection;
boolean resting;
Image face1;
public AI(Rectangle r){
AI = r;
}
public void paint(Graphics g){
ImageIcon j = new ImageIcon("C:/Users/admin/workspace/Project/src/ProjectGame/Enemy.gif");
face1 = j.getImage();
g.setColor(Color.BLUE);
if(AI != null)
g.fillRect(AI.x, AI.y, AI.width, AI.height);
**g.drawImage(face, x, y, this);**
}
public int chooseRandomDirection(){
Random r = new Random();
int[] randDirection = new int[2];
randDirection[0] = 1;
randDirection[1] = -1;
int randChoise = r.nextInt(2);
return randDirection[randChoise];
}
public void setXDirection(int dir){
xDirection = dir;
}
public void setYDirection(int dir){
yDirection = dir;
}
public void move(){
int widthLimit = JavaGame.WIDTH - AI.width;
int heightLimit = JavaGame.HEIGHT - AI.height;
AI.x += xDirection;
if (AI.x > widthLimit) {
AI.x = widthLimit;
}
if (AI.x < 0) {
AI.x = 0;
}
AI.y += yDirection;
if (AI.y > heightLimit) {
AI.y = heightLimit;
}
if (AI.y < AI.height) {
AI.y = AI.height;
}
}
public void run(){
try{
while(true){
if(resting = true){
setXDirection(chooseRandomDirection());
setYDirection(chooseRandomDirection());
long start = System.currentTimeMillis();
long end = start + 1 * 1000;
while(System.currentTimeMillis() < end){
move();
Thread.sleep(5);
}
}else{
Thread.sleep(3000);
}
}
}catch(Exception ex){
System.err.println(ex.getMessage());
}
}
}
The g.drawImage(face, x, y, this); on AI.java isn't working. Saying
The method drawImage(Image, int, int, ImageObserver) in the type Graphics is not applicable for the arguments (Image, int, int, AI)
How to fix this ?
Im trying to add an object of the RedSquare class in to the JFrame in CatchMeV2 class. What is the problem?
public class CatchMeV2 implements ActionListener{
int width = 400;
int height = 450;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(400, 400);
frame.setTitle("CatchMe.V2");
RedSquare r = new RedSquare();
frame.add(r);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
public class RedSquare extends JPanel implements ActionListener {
int x = 20; int y = 20;
int velX = 4; int velY = 4;
public RedSquare(){
addActionListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.green);
g.fillRect(x, y, 50, 50);
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
x += velX;
y += velY;
if (x < 0) {
velX = 0;
x = 0;
}
if (x > 400 - 50) {
velX = 0;
x = 400 - 50;
}
if (y < 0) {
velY = 0;
y = 0;
}
if (y > 400 - 40) {
velY = 0;
y = 400 - 40;
}
repaint();
}
}
The actionPerformed method doesn't do anything. Can anyone help? Or is there an easy way to do this?
Background: I was trying to make a game by using one class. I did it but the problem was i could only take 1 key input at a time and it was lagging. And my teacher said that if I divided it into different classes it wouldn't lag. Is it true?
You cannot add non visual component to JPanel so you need to extend RedSquare class from component, for example JPanel and override paintComponent() method.
public class CatchMeV2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setTitle("CatchMe.V2");
RedSquare r = new RedSquare();
frame.setContentPane(r);
frame.setVisible(true);
}
}
class RedSquare extends JPanel implements ActionListener {
public RedSquare() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // don't forget to call super method
g.setColor(Color.green);
g.fillRect(20, 20, 50, 50);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
update>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
you can't use action performed for panel it's only for buttons or like that.if you want to do something with click on panel then you need to use implement mouselistner .and put action code inside mouseclick method .run this example
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
public class CatchMeV2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(400, 400);
frame.setTitle("CatchMe.V2");
RedSquare r = new RedSquare();
frame.add(r);
}
}
class RedSquare extends JPanel implements MouseListener {
int x = 20;
int y = 20;
int velX = 4;
int velY = 4;
public RedSquare() {
addMouseListener(this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(x, y, 50, 50);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("hi");
x += velX;
y += velY;
if (x < 0) {
velX = 0;
x = 0;
}
if (x > 400 - 50) {
velX = 0;
x = 400 - 50;
}
if (y < 0) {
velY = 0;
y = 0;
}
if (y > 400 - 40) {
velY = 0;
y = 400 - 40;
}
this.repaint();
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
at that time you only want to move square with mouse click so u can still use awt mouse event but when you use keys you have to use key binding
EDIT: This is an SSCCE to demonstrate my problem.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Main {
public static BufferedImage map, tileSand, tileSea;
public static void main(String[] args) {
map = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < 50 ; x++){
for(int y = 0; y < 50 ; y++){
boolean colour = Math.random() < 0.5;
if (colour){
map.setRGB(x, y, -256);
} else {
map.setRGB(x, y, -16776961);
}
}
}
tileSand = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
Graphics g = tileSand.getGraphics();
g.setColor(Color.YELLOW);
g.fillRect(0, 0, 32, 32);
tileSea = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
g.setColor(Color.BLUE);
g = tileSea.getGraphics();
g.fillRect(0, 0, 32, 32);
Island test = new Main.Island();
test.start();
long start, sleep;
while(true) {
start = System.currentTimeMillis();
test.getCanvas().requestFocus();
test.getCanvas().repaint();
sleep = 15-(System.currentTimeMillis()-start);
try {
Thread.sleep(sleep > 0 ? sleep : 0);
} catch (InterruptedException e) {
}
}
}
static class Island implements Runnable {
private Tile[][] tiles;
private JFrame frame;
private JPanel panel;
private Thread logicThread;
private boolean running = false;
private boolean paused = false;
private Image image;
private Player player;
public Island() {
image = new BufferedImage(1027, 768, BufferedImage.TYPE_INT_ARGB);
player = new Player();
tiles = new Tile[map.getWidth()][map.getHeight()];
int rgb;
for(int x = 0; x < map.getWidth(); x++) {
for(int y = 0; y < map.getHeight(); y++) {
rgb = map.getRGB(x, y);
switch (rgb) {
case -16776961: tiles[x][y] = new Tile("sea");
break;
case -256: tiles[x][y] = new Tile("sand");
break;
}
}
}
makeMap();
makeFrame();
addBindings();
logicThread = new Thread(this);
}
public JPanel getCanvas() {
return panel;
}
public void start() {
running = true;
paused = false;
logicThread.start();
}
public void run() {
long sleep, before;
while(running){
before = System.currentTimeMillis();
player.move();
try {
sleep = 15-(System.currentTimeMillis()-before);
Thread.sleep(sleep > 0 ? sleep : 0);
} catch (InterruptedException ex) {
}
while(running && paused);
}
paused = false;
}
private void makeFrame() {
frame = new JFrame("Island");
panel = new JPanel(){
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, 1024, 768);
long xl, yl;
xl = player.getLocation().x-512;
yl = player.getLocation().y-384;
int x2, y2;
x2 = (int) Math.floor(xl / 32);
y2 = (int) Math.floor(yl / 32);
int xoffset, yoffset;
xoffset = (int) (xl % 32);
yoffset = (int) (yl % 32);
for(int x = x2; x < x2+40; x++) {
for(int y = y2; y < y2+40; y++) {
if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) {
g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null);
}
}
}
g.drawImage(image, 0, 0, null);
}
};
panel.setPreferredSize(new Dimension(1024, 768));
panel.setIgnoreRepaint(true);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
private void addBindings() {
InputMap inputMap = panel.getInputMap();
ActionMap actionMap = panel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke("Q"),"hold-sprint");
actionMap.put("hold-sprint", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.sprint(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released Q"),"release-sprint");
actionMap.put("release-sprint", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.sprint(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("RIGHT"),"hold-right");
actionMap.put("hold-right", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.right(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released RIGHT"),"release-right");
actionMap.put("release-right", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.right(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("DOWN"),"hold-down");
actionMap.put("hold-down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.down(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released DOWN"),"release-down");
actionMap.put("release-down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.down(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("LEFT"),"hold-left");
actionMap.put("hold-left", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.left(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released LEFT"),"release-left");
actionMap.put("release-left", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.left(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("UP"),"hold-up");
actionMap.put("hold-up", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.up(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released UP"),"release-up");
actionMap.put("release-up", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.up(false);
}
});
}
private void makeMap() {
for(int x = 0; x < tiles.length; x++) {
for(int y = 0; y < tiles[0].length; y++) {
switch (tiles[x][y].getType()) {
case "sea": tiles[x][y].setContent(tileSea);
break;
case "sand": tiles[x][y].setContent(tileSand);
break;
}
}
}
}
}
static class Player{
private Point location;
private int xspeed, yspeed;
private boolean left, up, right, down, sprint;
public Player() {
location = new Point(0, 0);
left = false;
up = false;
right = false;
down = false;
sprint = false;
xspeed = yspeed = 0;
}
public void left(boolean state){
left = state;
}
public void up(boolean state){
up = state;
}
public void right(boolean state){
right = state;
}
public void down(boolean state){
down = state;
}
public void sprint(boolean state) {
sprint = state;
}
public void move() {
if (sprint) {
if (left) {
if(xspeed>-10)
xspeed--;
} if (right) {
if(xspeed<10)
xspeed++;
} if (up) {
if(yspeed>-10)
yspeed--;
} if (down) {
if(yspeed<10)
yspeed++;
}
} else {
if (left) {
if(xspeed>-5)
xspeed--;
} if (right) {
if(xspeed<5)
xspeed++;
} if (up) {
if(yspeed>-5)
yspeed--;
} if (down) {
if(yspeed<5)
yspeed++;
}
}
if (!sprint) {
if (xspeed > 5) {
xspeed--;
} if (xspeed < -5) {
xspeed++;
} if (yspeed > 5) {
yspeed--;
} if (yspeed < -5) {
yspeed++;
}
}
if (!left && !right) {
if (xspeed > 0) {
xspeed--;
} if (xspeed < 0) {
xspeed++;
}
} if (!up && !down) {
if (yspeed > 0) {
yspeed--;
} if (yspeed < 0) {
yspeed++;
}
}
location.x = location.x + xspeed;
location.y = location.y + yspeed;
}
public Point getLocation() {
return location;
}
}
static class Tile {
private String type;
private BufferedImage tile;
public Tile(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setContent(BufferedImage newTile) {
tile = newTile;
}
public BufferedImage getContent() {
return tile;
}
}
}
I have a JPanel with a modified paintComponent method. In this method I draw the relevant tiles from a 2d array to the screen based on the player location. I draw all my tiles to a BufferedImage and then I apply it to the screen at the end of the paint method. In theory this should not create tearing as I am double buffering? Here is the appropriate code, image is just a BufferedImage with the dimensions of the screen:
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, 1024, 768);
long xl, yl;
xl = player.getLocation().x-512;
yl = player.getLocation().y-384;
int x2, y2;
x2 = (int) Math.floor(xl / 32);
y2 = (int) Math.floor(yl / 32);
int xoffset, yoffset;
xoffset = (int) (xl % 32);
yoffset = (int) (yl % 32);
for(int x = x2; x < x2+40; x++) {
for(int y = y2; y < y2+40; y++) {
if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) {
g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null);
}
}
}
g.drawImage(image, 0, 0, null);
}
I think the tearing could possibly be caused by the player's location changing over the duration of the paint method causing the tiles not to match up, the faster the player goes the more obvious the effect is. However I get the players location at the start and store it in two longs, I was under the impression that longs are passed by value not reference so the player location should be constant whilst the method runs.
I am happy to provide more code :), and thanks in advance.
Just so if people find my question and wonder what I ended up doing to "fix" it, switch over to c++ and SDL or some other image library before you are to far into your project, it's simply better for this kind of thing.