JFrame repainting image blinking - java

I am having an issue with the command super.paintComponents(g); when updating a JFrame. The issue I am having is that the image I am loading is blinking while the code is running. I am pretty sure that the code is double buffering and have not found any helpful resource online to solve this issue. This is my first question so please tolerate any formatting errors.
Here is my entire code (snippets below):
public class GAME extends JFrame implements KeyListener, MouseMotionListener {
int mouseX, mouseY;
public static ArrayList<Images> images = new ArrayList<Images>();
public static String lastKeyPressed = null;
public GAME() {
this.addMouseMotionListener(this);
this.addKeyListener(this);
}
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
}
public void mouseMoved(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_LEFT) {
lastKeyPressed = "LEFT";
} else if (e.getKeyCode() == e.VK_RIGHT) {
lastKeyPressed = "RIGHT";
} else if (e.getKeyCode() == e.VK_UP) {
lastKeyPressed = "UP";
} else if (e.getKeyCode() == e.VK_DOWN) {
lastKeyPressed = "DOWN";
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
#Override
public void paint(Graphics g) {
super.paintComponents(g);
for (int i = 0; i < images.size(); i++) {
g.drawImage(images.get(i).img, images.get(i).xpos, images.get(i).ypos, null);
}
}
public static void main(String[] args) throws IOException, InterruptedException {
GAME frame = new GAME();
Dimension dim = new Dimension(800, 600);
frame.setPreferredSize(dim);
frame.setSize(dim);
frame.setResizable(false);
frame.setTitle("GAME");
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Images test = new Images("unnamed.png");
images.add(test);
while (true) {
if (lastKeyPressed == "LEFT") {
test.xpos -= 5;
lastKeyPressed = null;
} else if (lastKeyPressed == "RIGHT") {
test.xpos += 5;
lastKeyPressed = null;
} else if (lastKeyPressed == "UP") {
test.ypos -= 5;
lastKeyPressed = null;
} else if (lastKeyPressed == "DOWN") {
test.ypos += 5;
lastKeyPressed = null;
}
frame.repaint();
Thread.sleep(100);
}
}
}
Here is the images class:
public class Images {
String name;
BufferedImage img;
int xpos;
int ypos;
public Images (String Name) throws IOException{
name = Name;
xpos = 40;
ypos = 90;
System.out.println(name);
System.out.println("PATH: " + GAME.class.getResource(name));
URL file = getClass().getClassLoader().getResource(name);
img = ImageIO.read(file);
}
}
What you probably only want to see is the following:
My paint method:
#Override
public void paint(Graphics g) {
super.paintComponents(g);
for (int i = 0; i < images.size(); i++) {
g.drawImage(images.get(i).img, images.get(i).xpos, images.get(i).ypos, null);
}
}
And the block of code in the main class that is running the game:
Images test = new Images("unnamed.png");
images.add(test);
while (true) {
if (lastKeyPressed == "LEFT") {
test.xpos -= 5;
lastKeyPressed = null;
} else if (lastKeyPressed == "RIGHT") {
test.xpos += 5;
lastKeyPressed = null;
} else if (lastKeyPressed == "UP") {
test.ypos -= 5;
lastKeyPressed = null;
} else if (lastKeyPressed == "DOWN") {
test.ypos += 5;
lastKeyPressed = null;
}
frame.repaint();
Thread.sleep(100);
}
(I added the Thread.sleep because it seemed to decrease the rate at which the blinking occurred)
Here is a gif of what is happening (I just used the first Google result for 'test' for the image):
http://i.imgur.com/WjLCSvu.gif?1
I appreciate any help and general suggestions to better my code. Thank you.

Don't override paint of top level containers like JFrame there aren't double buffered, instead, use a JPanel and override its paintComponent method. JPanel is double buffered by default.
Then, add the panel to what ever container you want
Don't forget to call it's super method (super.paintComponent) before you do any custom painting.
Take a closer look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
This is just one reason why you shouldn't (extend from JFrame and) override paint of top level containers, take a look at
How can I set in the midst?
Graphics rendering in title bar
Java JFrame .setSize(x, y) not working?
How to get the EXACT middle of a screen, even when re-sized
for some more

Related

How to make the sprite move once when arrow key is pressed?

I am trying to make the sprite stop continuously moving. Right now, the code makes the sprite move in the direction indicated by the user through arrow keys without stopping. I want to press an arrow key and make the sprite move once (ex. 10 steps only) in that direction.
public class Contents extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(100, this);
private Image man;
int x=0, y=0;
public Contents() {
super.setDoubleBuffered(true);
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
#Override
public void paintComponent (Graphics g) {
super.paintComponent(g);
super.setBackground(Color.white);
ImageIcon ii = new ImageIcon("guy.png");
man = ii.getImage();
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(man, x, y, this);
}
double xv = 0;
double yv = 0;
public void move() {
x += xv;
y += yv;
}
public void up() {
yv = -1;
xv = 0;
}
public void down() {
yv = 1;
xv = 0;
}
public void left () {
xv = -1;
yv = 0;
}
public void right () {
xv = 1;
yv = 0;
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
//Collision for left and right walls
if (x==0) {
xv = 1;
}
else if (x==900-240) {
xv = -1;
}
// Collision for top and bottom walls
if (y==0) {
yv = 1;
}
else if (y==600-320) {
yv = -1;
}
move();
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
up();
}
if (code == KeyEvent.VK_DOWN) {
down();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
It works when I delete the boundaries under ActionEvent. The boundaries prevent the sprite from going off screen. But I want to keep the boundaries and control the sprite too.
I figured it out. Under keyReleased, set xv=0. Then when you release the arrow key, the sprite will stop moving.

Java Graphics Rectangle Size Changing

I have just started to learn Java, so excuse my messy code. Looking all over the internet, I have not found a solution to this question yet. This is the game pong. I have to padels that I am controlling ith the keys, 'w', 's', up, and down. When I draw the panels in my graphics section, I use the padelY for Y1 and use padelY + padelLength(A constant) for Y2. I cannot seem to understand why when I rut the program the padels change size as I move them up and down. Also, the padel on the right is named panel1, when I draw the padel I use the screen size - the padel spacing for X1 yet the padel appears to be stuck on the side.
I would really appreciate any advice that anyone could give on those issues or how to clean up my code in general!
Thanks!
package Pong;
//Import Libraries
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
#SuppressWarnings("serial")
public class Pong extends JPanel implements KeyListener{
int padel1y = 150;
int padel2y = 150;
static final int padelLength = 100;
int padelWidth = 10;
int padelSpeed = 2;
int padel2Speed = 0;
int padel1Speed = 0;
int ballX = BOX_WIDTH/2;
int ballY= BOX_HEIGHT/2;
int ballXSpeed = 2;
int ballYSpeed = 1;
int ballRadius = 10;
int ballCount = 0;
public final static int ballSpeedIncrease = 500;
public final static int BOX_WIDTH = 600;
public final static int BOX_HEIGHT = 600;
public final static int UPDATE_RATE = 100;
public final static int padelSpace = 10;
public Pong() {
setPreferredSize(new Dimension(BOX_WIDTH,BOX_HEIGHT));
Thread gameThread = new Thread() {
public void run(){
while(true){
ballCount = ballCount + 1;
if(ballCount%ballSpeedIncrease == 0){
if(ballXSpeed < 0){
ballXSpeed = ballXSpeed - 1;
}
if(ballYSpeed < 0){
ballYSpeed = ballYSpeed - 1;
}
if(ballXSpeed > 0){
ballXSpeed++;
}
if(ballYSpeed > 0){
ballYSpeed++;
}
}
if(ballX-ballRadius <= 10+padelWidth){
if(ballY<padel2y || ballY>padel2y+padelLength){
System.exit(0);
}
else{
ballXSpeed = -ballXSpeed;
}
}
else if(ballX+ballRadius >= 590-padelWidth){
if(ballY<padel1y || ballY>padel1y+padelLength){
System.exit(0);
}
else{
ballXSpeed = -ballXSpeed;
}
}
if(ballY-ballRadius <= 0){
ballYSpeed = -ballYSpeed;
}
else if(ballY+ballRadius >= BOX_HEIGHT){
ballYSpeed = -ballYSpeed;
}
padel1y = padel1y +padel1Speed;
padel2y = padel2y +padel2Speed;
ballX = ballX + ballXSpeed;
ballY = ballY+ ballYSpeed;
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
}
catch (InterruptedException ex) {}
}
}
};
gameThread.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0,0,BOX_WIDTH,BOX_HEIGHT);
g.setColor(Color.blue);
g.fillRect(padelSpace,padel2y,padelSpace + padelWidth,padel2y+padelLength);
g.fillRect(BOX_WIDTH-padelSpace,padel1y,BOX_WIDTH-padelSpace-padelWidth,padel1y+padelLength);
g.setColor(Color.green);
g.fillOval(ballX, ballY, ballRadius*2, ballRadius*2);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Create Frame
JFrame frame = new JFrame("PONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONG");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Pong pong = new Pong();
frame.setContentPane(pong);
frame.setSize(BOX_WIDTH,BOX_HEIGHT);
frame.pack();
frame.addKeyListener(pong);
frame.setVisible(true);
}
});
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP){
padel1Speed = -padelSpeed;
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
padel1Speed = padelSpeed;
}
else if(e.getKeyCode() == KeyEvent.VK_W){
padel2Speed = -padelSpeed;
}
else if(e.getKeyCode() == KeyEvent.VK_S){
padel2Speed = padelSpeed;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
padel1Speed = 0;
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
padel1Speed = 0;
}
else if(e.getKeyCode() == KeyEvent.VK_W){
padel2Speed = 0;
}
else if(e.getKeyCode() == KeyEvent.VK_S){
padel2Speed = 0;
}
}
#Override
public void keyTyped(KeyEvent e) {}
}
See this for documentation on how to use the fillRect() method: https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html#fillRect(int,%20int,%20int,%20int)
The arguments are: x position, y position, width and height.
You use it like this: g.fillRect(padelSpace,padel2y,padelSpace + padelWidth,padel2y+padelLength);
The second and third arguments are wrong. You should only be passing the width and height. Like this: g.fillRect(padelSpace, padel2y, padelWidth, padelLength);
More generally, when something is going wrong (drawing the paddle) read the documentation on the methods you use to do that.

Screen Keeps Flickering when Drawing Graphics on Canvas (Java)

I am a complete noob to Java Graphics.
I wrote a simple "game" in which you control a box with the arrow keys
Here is the source code:
package com.thundercrust.graphics;
public class Drawings extends Canvas implements KeyListener, Runnable {
public static Thread thread;
public static Drawings draw;
private static final long serialVersionUID = 1L;
public static boolean running = false;
public static int x = 640;
public static int y = 320;
public static int bulletX = 0;
public static int bulletY = 0;
public static int direction = 2;
public static boolean fired = false;
public static boolean show = false;
public static String colorCode;
public static final int WIDTH = 1366;
public static final int HEIGHT = WIDTH / 16 * 9;
public static final String title = "A Moving Box!";
JFrame frame = new JFrame();
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setColor(Color.black);
g2D.fillRect(0, 0, 1366, 768);
g2D.setColor(Color.pink);
g2D.fillRect(50, 50, 1266, 668);
if (colorCode.equals("red")) g2D.setColor(Color.red);
if (colorCode.equals("orange")) g2D.setColor(Color.orange);
if (colorCode.equals("yellow")) g2D.setColor(Color.yellow);
if (colorCode.equals("green")) g2D.setColor(Color.green);
if (colorCode.equals("blue")) g2D.setColor(Color.blue);
if (colorCode.equals("cyan")) g2D.setColor(Color.cyan);
if (colorCode.equals("gray")) g2D.setColor(Color.gray);
g2D.fillRect(x, y, 50, 50);
}
public Drawings() {
frame.addKeyListener(this);
frame.setTitle(title);
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.add(this);
}
public void display() {
while (running = true) {
repaint();
try {
Thread.sleep(30);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
colorCode = JOptionPane.showInputDialog("Enter the color of the box: ");
running = true;
draw = new Drawings();
draw.start();
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) { y-= 5; direction = 0; }
if (keyCode == KeyEvent.VK_DOWN) { y+= 5; direction = 2; }
if (keyCode == KeyEvent.VK_LEFT) {x-= 5; direction = 3;}
if (keyCode == KeyEvent.VK_RIGHT) {x+= 5; direction = 1;}
if (keyCode == KeyEvent.VK_Z) System.out.println("You pressed z");
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (running = true) {
System.out.println("The Game is Running!");
repaint();
try {
Thread.sleep(60);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
The reason why I am asking for help is because the application always flickers and it gets really annoying.
Is there any way to fix this?
Any help would be appreciated.
Canvas is not double buffered and I'd recommend not using it this way. Instead, consider using a JPanel and overriding it's paintComponent method, this will give you double buffering for free.
See Painting in AWT and Swing and Performing Custom Painting for some deatils
Alternatively, you could use BufferStrategy, which would allow you to define you own double buffering strategy as well as take complete control over the painting process, letting you control when the canvas was painted (AKA active painting)

Making a program exit during a loop

I recently was playing around with Java, and I made a program that runs in a loop. When I tried hitting the X in the corner to close it, nothing happened. I tried adding standard mouselistener code to make it exit, but it won't come through the loop. The program is simply a small square bouncing around the screen:
package mainPackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class MainClass extends JApplet{
public static boolean isRunning = true;
public static void startStop(){
if(isRunning){
isRunning = false;
} else {
isRunning = true;
}
}
/**
* Eclipse kept yelling at me.
*/
private static final long serialVersionUID = -3997547128895841169L;
final static Color bg = Color.white;
final static Color fg = Color.black;
/*
* The direction of the box; 1 is up-right, 2 is down-right, etc.
*/
public static byte direction = 1;
/*
*The X and Y values start somewhat randomly.
*/
public static short x = (short) (Math.random() * 150);
public static short y = (short) (Math.random() * 150);
public void init() {
}
public static void moveBall(){
if(x >= 585){
if(direction == 1){
direction = 4;
} else {
direction = 3;
}
} else if(x <= 0){
if(direction == 3){
direction = 2;
} else {
direction = 1;
}
} else if(y <= 0){
if(direction == 1){
direction = 2;
} else {
direction = 3;
}
} else if(y >= 365){
if(direction == 3){
direction = 4;
} else {
direction = 1;
}
}
if(direction == 1){
x++; y--;
} else if(direction == 2){ x++; y++;
} else if(direction == 3){ x--; y++;
} else if(direction == 4){ x--; y--;
} else { System.out.println(direction); System.exit(5);}
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Color color = Color.black;
Rectangle2D.Double a = new Rectangle2D.Double(250, 250, 10, 10);
Rectangle2D.Double fill = new Rectangle2D.Double(0, 0, 600, 400);
g2.setPaint(color);
g2.fill(fill);
while(isRunning){
g2.setPaint(Color.blue);
g2.fill(a);
try {
Thread.sleep(15L);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
e.printStackTrace();
}
g2.setPaint(Color.black);
g2.fill(a);
a.setRect(x, y, 10, 10);
}
}
/**
* #param args
*/
public static void main(String[] args) {
JFrame jframe = new JFrame("Test");
jframe.setVisible(true);
jframe.setBounds(250, 250, 600, 400);
jframe.setResizable(false);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new MainClass();
jframe.getContentPane().add("Center", applet);
while(isRunning){
moveBall();
try {
Thread.sleep(15L);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("Interrupted.");
}
}
}
}
[Edit]I forgot to mention that when I exported it into an executable JAR file and then ran it, I had to open Task Manager, which then told me it was not responding, in order to close it.
Is there anyway to re-write this so that it can close?
I think you're not listening the close event. Try with this:
class WindowEventHandler extends WindowAdapter {
public void windowClosing(WindowEvent evt) {
isRunnig = false;
}
}
and
jframe.addWindowListener(new WindowEventHandler());
Thread.sleep and main loop in Swing EDT are bad idea.
Use javax.swing.Timer.

trouble running smooth animation in thread only when using key listener

first time using a forum for coding help so sorry if i post this all wrong. i have more than a few classes i don't think screenManger or core holds the problem but i included them just incase. i got most of this code working through a set of tutorials. but a certain point started trying to do more on my own.
i want to play the animation only when i'm moving my sprite.
in my KeyTest class i am using threads to run the animation it used to work (poorly) but now not at all pluss it really gunks up my computer. i think it's because of the thread. im new to threads so i'm not to sure if i should even be using one in this situation or if its dangerous for my computer.
the animation worked smoothly when i had the sprite bouce around the screen forever. the animation loop played with out stopping.
i think the main problem is between the animationThread, Sprite, and keyTest classes, but itcould be more indepth.
if someone could point me in the right direction for making the animation run smoothly when i push down a key and stop runing when i let off it would be greatly apriciated.
i already looked at this Java a moving animation (sprite) obviously we were doing the same tutorial. but i feel my problem is slightly different.
p.s. sorry for the typos.
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
public class KeyTest extends Core implements KeyListener {
public static void main(String[] args){
new KeyTest().run();
}
Sprite player1;
Image hobo;
Image background;
animation hoboRun;
animationThread t1;
//init also calls init form superclass
public void init(){
super.init();
loadImages();
Window w = s.getFullScreenWindow();
w.setFocusTraversalKeysEnabled(false);
w.addKeyListener(this);
}
//load method will go here.
//load all pics need for animation and sprite
public void loadImages(){
background = new ImageIcon("\\\\STUART-PC\\Users\\Stuart\\workspace\\Gaming\\yellow square.jpg").getImage();
Image face1 = new ImageIcon("\\\\STUART-PC\\Users\\Stuart\\workspace\\Gaming\\circle.png").getImage();
Image face2 = new ImageIcon("\\\\STUART-PC\\Users\\Stuart\\workspace\\Gaming\\one eye.png").getImage();
hoboRun = new animation();
hoboRun.addScene(face1, 250);
hoboRun.addScene(face2, 250);
player1 = new Sprite(hoboRun);
t1 = new animationThread();
t1.setAnimation(player1);
}
//key pressed
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_ESCAPE){
stop();
}
if(keyCode == KeyEvent.VK_RIGHT){
player1.setVelocityX(0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}
if(keyCode == KeyEvent.VK_LEFT){
player1.setVelocityX(-0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}
if(keyCode == KeyEvent.VK_DOWN){
player1.setVelocityY(0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}
if(keyCode == KeyEvent.VK_UP){
player1.setVelocityY(-0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);;
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}else{
e.consume();
}
}
//keyReleased
#SuppressWarnings("static-access")
public void keyReleased(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_LEFT){
player1.setVelocityX(0);
try{
this.t1.setRunning(false);
}catch(Exception ex){}
}
if(keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN){
player1.setVelocityY(0);
try{
this.t1.setRunning(false);
}catch(Exception ex){}
}else{
e.consume();
}
}
//last method from interface
public void keyTyped(KeyEvent e){
e.consume();
}
//draw
public void draw(Graphics2D g){
Window w = s.getFullScreenWindow();
g.setColor(w.getBackground());
g.fillRect(0, 0, s.getWidth(), s.getHieght());
g.setColor(w.getForeground());
g.drawImage(player1.getImage(), Math.round(player1.getX()), Math.round(player1.getY()), null);
}
public void update(long timePassed){
player1.update(timePassed);
}
}
abstract class Core {
private static DisplayMode modes[] = {
new DisplayMode(1600, 900, 64, 0),
new DisplayMode(800, 600, 32, 0),
new DisplayMode(800, 600, 24, 0),
new DisplayMode(800, 600, 16, 0),
new DisplayMode(800, 480, 32, 0),
new DisplayMode(800, 480, 24, 0),
new DisplayMode(800, 480, 16, 0),};
private boolean running;
protected ScreenManager s;
//stop method
public void stop() {
running = false;
}
public void run() {
try {
init();
gameLoop();
} finally {
s.restoreScreen();
}
}
//set to full screen
//set current background here
public void init() {
s = new ScreenManager();
DisplayMode dm = s.findFirstCompatibleMode(modes);
s.setFullScreen(dm);
Window w = s.getFullScreenWindow();
w.setFont(new Font("Arial", Font.PLAIN, 20));
w.setBackground(Color.GREEN);
w.setForeground(Color.WHITE);
running = true;
}
//main gameLoop
public void gameLoop() {
long startTime = System.currentTimeMillis();
long cumTime = startTime;
while (running) {
long timePassed = System.currentTimeMillis() - cumTime;
cumTime += timePassed;
update(timePassed);
Graphics2D g = s.getGraphics();
draw(g);
g.dispose();
s.update();
try {
Thread.sleep(20);
} catch (Exception ex) {
}
}
}
//update animation
public void update(long timePassed) {
}
//draws to screen
abstract void draw(Graphics2D g);
}
public class animationThread implements Runnable{
String name;
volatile boolean playing;
Sprite a;
//constructor takes input from keyboard
public animationThread(){
}
//The run method for animation
public void run() {
long startTime = System.currentTimeMillis();
long cumTime = startTime;
while(getRunning()){
long timePassed = System.currentTimeMillis() - cumTime;
cumTime += timePassed;
a.startAnimation(timePassed);
}
}
public String getName(){
return name;
}
public void setAnimation(Sprite a){
this.a=a;
}
public void setName(String name){
this.name=name;
}
public synchronized void setRunning(boolean running){
this.playing = running;
}
public synchronized boolean getRunning(){
return playing;
}
}
class animation {
private ArrayList scenes;
private int sceneIndex;
private long movieTime;
private long totalTime;
//constructor
public animation() {
scenes = new ArrayList();
totalTime = 0;
start();
}
//add scene to ArrayLisy and set time for each scene
public synchronized void addScene(Image i, long t) {
totalTime += t;
scenes.add(new OneScene(i, totalTime));
}
public synchronized void start() {
movieTime = 0;
sceneIndex = 0;
}
//change scenes
public synchronized void update(long timePassed) {
if (scenes.size() > 1) {
movieTime += timePassed;
if (movieTime >= totalTime) {
movieTime = 0;
sceneIndex = 0;
}
while (movieTime > getScene(sceneIndex).endTime) {
sceneIndex++;
}
}
}
//get animations current scene(aka image)
public synchronized Image getImage() {
if (scenes.size() == 0) {
return null;
} else {
return getScene(sceneIndex).pic;
}
}
//get scene
private OneScene getScene(int x) {
return (OneScene) scenes.get(x);
}
//Private Inner CLASS//////////////
private class OneScene {
Image pic;
long endTime;
public OneScene(Image pic, long endTime) {
this.pic = pic;
this.endTime = endTime;
}
}
}
class Sprite {
private animation a;
private float x;
private float y;
private float vx;
private float vy;
//Constructor
public Sprite(animation a) {
this.a = a;
}
//change position
public void update(long timePassed) {
x += vx * timePassed;
y += vy * timePassed;
}
public void startAnimation(long timePassed) {
a.update(timePassed);
}
//get x position
public float getX() {
return x;
}
//get y position
public float getY() {
return y;
}
//set x
public void setX(float x) {
this.x = x;
}
//set y
public void setY(float y) {
this.y = y;
}
//get sprite width
public int getWidth() {
return a.getImage().getWidth(null);
}
//get sprite height
public int getHeight() {
return a.getImage().getHeight(null);
}
//get horizontal velocity
public float getVelocityX() {
return vx;
}
//get vertical velocity
public float getVelocityY() {
return vx;
}
//set horizontal velocity
public void setVelocityX(float vx) {
this.vx = vx;
}
//set vertical velocity
public void setVelocityY(float vy) {
this.vy = vy;
}
//get sprite / image
public Image getImage() {
return a.getImage();
}
}
class ScreenManager {
private GraphicsDevice vc;
public ScreenManager() {
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
vc = e.getDefaultScreenDevice();
}
//get all compatible DM
public DisplayMode[] getCompatibleDisplayModes() {
return vc.getDisplayModes();
}
//compares DM passed into vc DM and see if they match
public DisplayMode findFirstCompatibleMode(DisplayMode modes[]) {
DisplayMode goodModes[] = vc.getDisplayModes();
for (int x = 0; x < modes.length; x++) {
for (int y = 0; y < goodModes.length; y++) {
if (displayModesMatch(modes[x], goodModes[y])) {
return modes[x];
}
}
}
return null;
}
//get current DM
public DisplayMode getCurrentDisplayMode() {
return vc.getDisplayMode();
}
//checks if two modes match each other
public boolean displayModesMatch(DisplayMode m1, DisplayMode m2) {
if (m1.getWidth() != m2.getWidth() || m1.getHeight() != m2.getHeight()) {
return false;
}
if (m1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI && m1.getBitDepth() != m2.getBitDepth()) {
return false;
}
if (m1.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN && m2.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN && m1.getRefreshRate() != m2.getRefreshRate()) {
return false;
}
return true;
}
//make frame full screen
public void setFullScreen(DisplayMode dm) {
JFrame f = new JFrame();
f.setUndecorated(true);
f.setIgnoreRepaint(true);
f.setResizable(false);
vc.setFullScreenWindow(f);
if (dm != null && vc.isDisplayChangeSupported()) {
try {
vc.setDisplayMode(dm);
} catch (Exception ex) {
}
}
f.createBufferStrategy(2);
}
//sets graphics object = this return
public Graphics2D getGraphics() {
Window w = vc.getFullScreenWindow();
if (w != null) {
BufferStrategy s = w.getBufferStrategy();
return (Graphics2D) s.getDrawGraphics();
} else {
return null;
}
}
//updates display
public void update() {
Window w = vc.getFullScreenWindow();
if (w != null) {
BufferStrategy s = w.getBufferStrategy();
if (!s.contentsLost()) {
s.show();
}
}
}
//returns full screen window
public Window getFullScreenWindow() {
return vc.getFullScreenWindow();
}
//get width of window
public int getWidth() {
Window w = vc.getFullScreenWindow();
if (w != null) {
return w.getWidth();
} else {
return 0;
}
}
//get height of window
public int getHieght() {
Window w = vc.getFullScreenWindow();
if (w != null) {
return w.getHeight();
} else {
return 0;
}
}
//get out of full screen
public void restoreScreen() {
Window w = vc.getFullScreenWindow();
if (w != null) {
w.dispose();
}
vc.setFullScreenWindow(null);
}
//create image compatible with monitor
public BufferedImage createCopatibleImage(int w, int h, int t) {
Window win = vc.getFullScreenWindow();
if (win != null) {
GraphicsConfiguration gc = win.getGraphicsConfiguration();
return gc.createCompatibleImage(w, h, t);
}
return null;
}
}
In your animationThread class you are accessing the field "playing". This should be done using synchronized blocks. As one option put the "synchronized" keyword before "playing". As one option put the "volatile" keyword before "playing".
Without "synchronized" one thread may not see a change of "playing" done in another thread. So the threads may run forever. (short answer only, because I am on one of those fancy mobile devices now)
EDIT:
With the "volatile" keyword the "playing" field, the field is accessed each time its value is read or written. Without it, a Thread may use a copy of it and doesn't see when the original field has changed.
You can make blocks "synchronized":
boolean setRunning(boolean running) {
synchronized (this) {
this.playing = running;
}
}
You can make methods "synchronized":
synchronized boolean setRunning(boolean running) {
this.playing = running;
}
"synchronized" ensures, that no two threads execute this code at the same time and it makes sure that a thread sees an "up to date" object. For instance if one thread changes the "playing" field and when another thread enters a synchronized block, then that other thread will see the changed value of the field.
i just figured out something new that may be important to note: when holding down the the right key to move the sprite and update the animation the code is being re executed i found out by doing this
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_ESCAPE){
stop();
}
if(keyCode == KeyEvent.VK_RIGHT){
player1.setVelocityX(0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
player1.setVelocityX(0);
}
at first the spite doesn't move because the velocity is set to zero at the end but if i hold the butten long enough the sprite jumps across the screen.
this has to be the problem but idk how to fix it
hey thanks for all the help i just solved it though.
public void keyPressed(KeyEvent e){
if(godDamn){
godDamn=false;
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_ESCAPE){
stop();
}
if(keyCode == KeyEvent.VK_RIGHT){
player1.setVelocityX(0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}
if(keyCode == KeyEvent.VK_LEFT){
player1.setVelocityX(-0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}
if(keyCode == KeyEvent.VK_DOWN){
player1.setVelocityY(0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}
if(keyCode == KeyEvent.VK_UP){
player1.setVelocityY(-0.3f);
try{
t1.setRunning(true);
Thread th1 = new Thread(t1);;
th1.start();
}catch(Exception ex){System.out.println("noooo");}
}else{
e.consume();
}
}
}
//keyReleased
#SuppressWarnings("static-access")
public void keyReleased(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_LEFT){
player1.setVelocityX(0);
try{
this.t1.setRunning(false);
}catch(Exception ex){}
godDamn=true;
}
if(keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN){
player1.setVelocityY(0);
try{
this.t1.setRunning(false);
}catch(Exception ex){}
}else{
e.consume();
}
}
the new boolean stops the multiple key events from executing. i have to fine tune it but other wise i'm good.

Categories