I transferred a few programs from a computer at my school(a mac) at school to my home pc. Once on my computer, I noticed the keys now do not work in each program. I've spent hours try to figure out why KeyPressed isn't working. Both computers used Eclipse
Is it because of different Java version or because of a different OS?
Thank you!
example of code:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.text.DecimalFormat;
import java.util.Random;
import javax.swing.JApplet;
public class Skeleton extends JApplet implements Runnable, MouseMotionListener, MouseListener, KeyListener {
Random generator = new Random();
boolean GameRunning = true, PlayAgain = true;
int width, height;
int score = 0;
Image offscreenImage;
int XX;
int XY;
Image Cart;
Image candy[];
int candyX[];
int candyY[];
boolean up = false, down = false, left = false, right = false;
boolean candyRemaining[];
Graphics offscr;
Random r;
Thread t;
boolean inBounds = true;
boolean onScreen = true;
Image Title;
boolean hasStarted = false;
public Skeleton() {
r = new Random();
t = new Thread(this);
t.start();
}
public void init() {
XX = 0;
XY = 0;
candy = new Image[3];
candyRemaining = new boolean[3];
candyY = new int[3];
candyX = new int[3];
addKeyListener(this);
addMouseMotionListener(this);
addMouseListener(this);
setVisible(true);
setSize(500, 500);
width = getSize().width;
height = getSize().height;
Title = getImage(getCodeBase(), "BKG.png");
offscreenImage = createImage(width, height);
// offscr = offscreenImage.getGraphics();
Cart = getImage(getCodeBase(), "Untitled-1.png");
candy[0] = getImage(getCodeBase(), "candy1.png");
candy[1] = getImage(getCodeBase(), "candy2.png");
candy[2] = getImage(getCodeBase(), "candy3.png");
candyRemaining[0] = true;
candyRemaining[1] = true;
candyRemaining[2] = true;
candyX[0] = 100;
candyX[1] = 300;
candyX[2] = 400;
candyY[0] = 425;
candyY[1] = 0;
candyY[2] = 210;
}
public void paint(Graphics g) {
super.paint(g);
DecimalFormat df = new DecimalFormat("0.00");
Random generator = new Random();
if (hasStarted) {
if (inBounds) {
g.drawImage(Cart, XX, XY, this);
this.Candy(g);
if (left) {
XX -= 5;
if (XX < 0) {
XX += 5;
}
}
if (right) {
XX += 5;
if (XX > 500) {
XX -= 5;
}
}
if (down) {
XY += 5;
if (XX > 500) {
XY -= 5;
}
}
if (up) {
XY -= 5;
if (XY < 0) {
XY += 5;
}
}
} else {
GameRunning = false;
}
} else {
g.drawImage(Title, 0, 0, this);
}
}
public void Candy(Graphics g) {
for (int count = 0; count < 3; count++) {
if (candyRemaining[count]) {
g.drawImage(candy[count], candyX[count], candyY[count], this);
if (candyX[count] < XX + 50 && candyX[count] + 50 > XX) {
if (candyY[count] < XY + 50 && candyY[count] + 50 > XY) {
System.out.println(count);
candyRemaining[count] = false;
}
}
}
}
}
public void update(Graphics g) {
paint(g);
}
public void run() {
while (PlayAgain == true) {
while (GameRunning == true) {
repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
};
}
if (GameRunning == false) {
}
}
}
public void mouseDragged(MouseEvent ev) {
}
public void mouseMoved(MouseEvent ev) {
}
public void mouseClicked(MouseEvent ev) {
if (!hasStarted) {
hasStarted = true;
}
if (GameRunning == false) {
if (ev.getX() > 0 && ev.getX() < 1000 && ev.getY() > 0 && ev.getY() < 1000) {
GameRunning = true;
}
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
onScreen = true;
inBounds = true;
}
public void mouseExited(MouseEvent ev) {
onScreen = false;
inBounds = false;
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Pressed");
int key = e.getKeyCode();
if (key == e.VK_A) {
left = true;
}
if (key == e.VK_D) {
right = true;
}
if (key == e.VK_S) {
down = true;
}
if (key == e.VK_W) {
up = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("Released");
int key = e.getKeyCode();
if (key == e.VK_A) {
left = false;
}
if (key == e.VK_D) {
right = false;
}
if (key == e.VK_S) {
down = false;
}
if (key == e.VK_W) {
up = false;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Don't use the object e for your keycodes, use the static KeyEvent class. In addition your code will look prettier if you use a switch statement instead of if statements:
switch (e.getKeyCode()) {
case KeyEvent.VK_A: // here's the change
left = true;
break;
For comparing the keypressed or released you are using the current KeyEvent class's object.
As everytime the key is pressed the new KeyEvent object is created and for keypressed you are checking with the current object which doesn't hold the keyvalue, it just hold's that which key was pressed.
So to check refer to the static variables of the KeyEvent Class.
switch(e.getKeyCode){
case: KeyEvent.VK_A;
Left =false;
break;
case: KeyEvent.VK_D;
right=false;
break;
.
.
.
.
}
KeyListener is nutritiously fickle about focus. A KeyListener can only be notified of key events when the component is focusable and has focus
The short answer would be to use
setFocusable(true);
requestFocusInWindow();
at the end of the init method
The more appropriate answer would be to use key bindings API, which provides you with the ability to control the level of focus required in order to generate key events
As a side note, it would be more appropriate to use something like a JPanel and override it's paintComponent and use it as the primary gaming component instead of the JApplet, which isn't double buffered and can flash when it's updated...
You should also move you gaming logic out of your paint method and probably into you main gaming loop (or called from your gaming loop). A paint cycle could be called at any time, many times outside of your control, which could effect your output.
I also doubt you need 500fps, Thread.sleep(40); or even Thread.sleep(16); will probably give you far more stable results
Related
I am generally a very bad programmer but have been trying to learn game development for a school project. My problem is that I have a draw method that draws a white rectangle and have a key Listener for movement but for some reason it moves upward despite what key I press not just W A S and D.
If you could help with this I would appreciate.
thanks
package Main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
final int screenHeight = 600;
final int screenWidth = 800;
final int playerSize = 48;
int fps = 60;
KeyHandler keyH = new KeyHandler();
Thread gameThread;
//player default position
int playerX = 100;
int playerY = 100;
int playerSpeed = 1;
public GamePanel() {
this.setPreferredSize(new Dimension (screenWidth, screenHeight));
this.setBackground(Color.black);
this.setDoubleBuffered(true);
this.addKeyListener(keyH);
this.setFocusable(true);
}
public void startGameThread() {
gameThread = new Thread (this);
gameThread.start();
}
public void run() {
double drawInterval = 1000000000/fps; // 0.01666 seconds = 60 times per seconds
double nextDrawTime = System.nanoTime() + drawInterval;
while(gameThread != null) {
System.out.println("this gmae is runing");
// update information such as character positions
// draw the screen with the updated information
update();
repaint();
try {
double remainingTime = nextDrawTime - System.nanoTime();
remainingTime = remainingTime/1000000;
if(remainingTime<0) {
remainingTime = 0;
}
Thread.sleep ((long) remainingTime);
nextDrawTime += drawInterval;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void update() {
if(keyH.upPressed ==true) {
playerY = playerY - playerSpeed;
}
else if (keyH.downPressed ==true){
playerY = playerY + playerSpeed;
}
else if (keyH.leftPressed== true){
playerX = playerX - playerSpeed;
}
else if (keyH.rightPressed == true) {
playerX = playerX +playerSpeed;
}
}
public void paintComponent(Graphics g) {
// to draw something
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.white);
g2.fillRect(playerX, playerY, playerSize, playerSize);
g2.dispose();
}
}
package game;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyHandler implements KeyListener {
public boolean leftPressed;
public boolean rightPressed;
public boolean upPressed;
public boolean downPressed;
public boolean spacePressed;
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_D);{
rightPressed = true;
}
if(code == KeyEvent.VK_A);{
leftPressed = true;
}
if(code == KeyEvent.VK_W);{
upPressed = true;
}
if(code == KeyEvent.VK_S);{
downPressed = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
int code = e.getExtendedKeyCode();
if(code == KeyEvent.VK_D);{
rightPressed = false;
}
if(code == KeyEvent.VK_A);{
leftPressed = false;
}
if(code == KeyEvent.VK_W);{
upPressed = false;
}
if(code == KeyEvent.VK_S);{
downPressed = false;
}
}
}
I have created a game similar to snake in which the user is first prompted with a jpanel asking which difficulty they want, and whatever JButton they pick influences the size of the map as well as the delay between the snake movements. I have the map size working just fine, but the delay variable never seems to change. I suspect it has something to do with the way the timer is being casted, but I have no idea how to fix it. I am also wondering how when the program is first ran it seems some of the variables don't update, but the second time it is ran all of them are updated. Here is my class with the original variables and collision detection:
import java.util.Random;
import javax.swing.JLabel;
public class GameEngine extends JPanel implements ActionListener{
//creates the size of the panel as well as creating the resolution for all objects, including the players and food.
static final int sWidth = 600;
static final int sHeight = 600;
public static int size = 24;
static int objectSize = (sHeight*sWidth) / size;
public static int delay = 100;
final int playerX[] = new int[objectSize];
final int playerY[] = new int[objectSize];
int bodySize = 4;
int score = 0;
int appleX;
int appleY;
char direction = 'D';
boolean started = false;
Random random;
Timer timer;
boolean easy;
JLabel score1;
public static String difficulty;
GameEngine(){
random = new Random();
this.setPreferredSize(new Dimension(sWidth,sHeight));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new UserMovement());
gameStart();
}
public void gameStart() {
newApple();
started = true;
timer = new Timer(delay,this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void drawHead(Graphics g) {
g.setColor(new Color(100,252,0));
g.fillRect(playerX[0], playerY[0], size, size);
}
public void draw(Graphics g) {
if(started) {
//draws the apples
g.setColor(Color.red);
g.fillOval(appleX, appleY, size, size);
for (int i = 0; i < bodySize; i++) {
if(i == 0) {
drawHead(g);
}
else {
g.setColor(new Color(60,180,0));
g.fillRect(playerX[i], playerY[i], size, size);
}
}
g.setColor(Color.white);
g.setFont(new Font("Bold", Font.BOLD, 20));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Score: " + score,(sWidth - metrics.stringWidth("Score: " + score))/2,g.getFont().getSize());
}
}
public void newApple(){
appleX = random.nextInt((int)(sWidth/size))*size;
appleY = random.nextInt((int)(sHeight/size))*size;
}
//moves the player by using and modifying their coordinates
public void move() {
for (int i = bodySize; i > 0; i--) {
playerX[i] = playerX[i-1];
playerY[i] = playerY[i-1];
}
switch(direction) {
case 'W':
playerY[0] = playerY[0] - size;
break;
case 'S':
playerY[0] = playerY[0] + size;
break;
case 'A':
playerX[0] = playerX[0] - size;
break;
case 'D':
playerX[0] = playerX[0] + size;
break;
}
}
public void checkFood() {
if(playerX[0] == appleX && playerY[0] == appleY)
{
bodySize++;
score++;
newApple();
}
}
public void checkCol() {
//checks for head collision with the body
for(int i = bodySize; i > 0; i--) {
if((playerX[0] == playerX[i]) && (playerY[0] == playerY[i])) {
started = false;
}
}
//checks if head touches any of the walls of the program
if(playerX[0] < 0) {
started = false;
}
if(playerX[0] > sWidth) {
started = false;
}
if(playerY[0] < 0) {
started = false;
}
if(playerY[0] > sHeight) {
started = false;
}
if(started != true) {
timer.stop();
}
}
public void actionPerformed(ActionEvent e){
if(started == true) {
move();
checkFood();
checkCol();
}
repaint();
}
public class UserMovement extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction != 'D') {
direction = 'A';
}
break;
case KeyEvent.VK_RIGHT:
if(direction != 'A') {
direction = 'D';
}
break;
case KeyEvent.VK_UP:
if(direction != 'S') {
direction = 'W';
}
break;
case KeyEvent.VK_DOWN:
if(direction != 'W') {
direction = 'S';
}
break;
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
}
and here is the code calling and changing the delay and size variables:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StartMenu extends JPanel {
StartMenu()
{
JButton easy = new JButton();
JButton hard = new JButton();
this.setPreferredSize(new Dimension(350,240));
this.setLayout(null);
this.setBackground(Color.black);
this.setFocusable(true);
easy.setBounds(75,40,200,40);
hard.setBounds(75,120,200,40);
this.add(easy);
this.add(hard);
easy.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setVisible(false);
new SnakeStart();
GameEngine.size = 48;
GameEngine.delay = 140;
}
});
hard.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setVisible(false);
new SnakeStart();
GameEngine.size = 24;
GameEngine.delay = 70;
}
});
}
}
I assume your GameEngine instance is created before the StartMenu action listeners are executed. If that assumption is correct, that means that GameEngine.timer with the default value of delay is created in the GameEngine constructor and is not updated after the delay is changed.
You need to make sure that you explicitly update your timer with the new delay value after StartMenu actions are called.
I am making a JFrame holding several images that refresh using repaint(). The problem, however, was that the more images I added (or as the area that was being rendered increased) the framerate drastically decreased.
I was initially attempting to reduce the lag that Swing's unpredictable Timer experiences, but was unsuccessful. This time, I tried to call
repaint()
every 10 milliseconds based on system time. (To bypass the timer, desktop.screenPaint.drawWindow(); is called instead of repaint())
while(true)
{
long starttime = System.currentTimeMillis();
while(System.currentTimeMillis()-starttime < 10)
{
}
desktop.screenPaint.drawWindow();
desktop2.screenPaint.drawWindow();
}
Each "desktop" is just one of the draggable windows that you see if you run the code below. I noticed that when only "desktop" is added to "frame," there is no flickering. However, when "desktop2" is also added, flickering does not go away until the time until each refresh is set to 20 or more milliseconds. It is extremely strange, because when I was still using the timer, even thought the wait was set to 10 milliseconds, the framerate would lower to a frame every 20 milliseconds! I tested a little and noticed a trend: you will get flickering until the wait time to the amount of time that the 10 millisecond timer lagged behind. My question: Why is this happening? And is there any way to prevent the flickering, other than going back to the timer?
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.SwingUtilities.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;
import java.io.File;
import java.io.IOException;
public class Display extends JPanel
{
public static int width, height;
public static JFrame frame = new JFrame("");
private static int rh = 10;
public static Display desktop = new Display();
public static Display desktop2 = new Display();
public static void main(String[] args)
{
Dimension screen = new Dimension();
screen = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
width = (int)screen.getWidth();
height = (int)screen.getHeight();
frame.setLayout(null);
frame.setLocation(0, 0);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
desktop.setBounds(0, 0, 620, 500+rh);
desktop2.setBounds(1000, 200, 620, 500+rh);
frame.add(desktop);
frame.add(desktop2);
frame.setUndecorated(true);
frame.setSize(width, height);
frame.setVisible(true);
while(true)
{
long starttime = System.currentTimeMillis();
while(System.currentTimeMillis()-starttime < 10)
{
}
desktop.screenPaint.drawWindow();
//desktop2.screenPaint.drawWindow();
}
}
private BufferedImage image;
private Graphics2D g;
public Listener screenPaint = new Listener();
private Display identify;
public Display()
{
identify = this;
image = new BufferedImage(620, 500+rh, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D)image.getGraphics();
Timer timer = new Timer(1, screenPaint);
timer.start();
addMouseListener(new mMouse());
addMouseWheelListener(new wWheel());
setFocusable(true);
}
private BufferedImage toCompatibleImage(BufferedImage image)
{
GraphicsConfiguration gfx_config = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration();
if (image.getColorModel().equals(gfx_config.getColorModel()))
return image;
BufferedImage new_image = gfx_config.createCompatibleImage(
image.getWidth(), image.getHeight(), image.getTransparency());
}
public void paint(Graphics view)
{
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
view.drawImage(toCompatibleImage(image), 0, 0, 620, 500+rh, null);
view.dispose();
}
private class Listener implements ActionListener
{
int y = 0;
int wy = 0;
int b = 500;
int c = 1500;
int iy = (int)(wy/(c/(double)b));
int a = -1;
int i = -1;
int j = -1;
boolean d = false;
boolean u = false;
int f = 0;
public void moveY(int sy)
{
f += sy;
}
public void actionPerformed(ActionEvent e)
{
//drawWindow();
}
public void drawWindow()
{
int lx = (int)(identify.getLocation().getX());
int ly = (int)(identify.getLocation().getY());
g.setColor(Color.white);
g.fillRect(0, 0, 620, 500+rh);
g.drawImage(new ImageIcon("image.png").getImage(), 0, wy+rh, 610, c, null);
if(c > b)
{
if(d || Mouse.withinRect(610+lx, (int)(-wy/(c/(double)b))+rh+ly, 10, (int)Math.ceil(Math.pow(b, 2)/(double)c)))
{
if(Mouse.pressLeft())
{
if(!d)d = true;
if(a == -1)a = Mouse.y()-(int)(-wy/(c/(double)b));
y = (int)((Mouse.y()-a)*(c/(double)b));
f = y;
g.setColor(Color.black);
}
else
{
if(d)d = false;
if(a != -1)a = -1;
g.setColor(new Color(60, 60, 60));
}
}
else
{
g.setColor(Color.gray);
if(a != -1)a = -1;
}
if(y == f){}
else if(y < f)
{
y += (int)((f-y)*0.1);
if(y < f)y++;
}
else
{
y -= (int)((y-f)*0.1);
if(y > f)y--;
}
if(y < 0)
{
y = 0;
f = 0;
}
else if(y > c-b)
{
y = c-b;
f = y;
}
wy = -y;
if(u || Mouse.withinRect(lx, ly, 620, 10))
{
if(Mouse.pressLeft())
{
if(!u)u = true;
if(i == -1)i = Mouse.x()-lx;
if(j == -1)j = Mouse.y()-ly;
identify.setLocation(Mouse.x()-i, Mouse.y()-j);
}
else
{
if(u)u = false;
if(i != -1)i = -1;
if(j != -1)j = -1;
}
}
else
{
if(u)u = false;
if(i != -1)i = -1;
if(j != -1)j = -1;
}
int scrollBarLength = (int)Math.ceil(Math.pow(b, 2)/(double)c);
g.fillRect(610, (int)(-wy/(c/(double)b))+rh, 10, scrollBarLength);
}
else
{
g.setColor(new Color(200, 200, 200));
g.fillRect(610, rh, 10, b);
}
g.setColor(new Color(50, 50, 50));
g.fillRect(0, 0, 620, rh);
if(identify == desktop)
repaint();
else if(false)
{}
}
}
}
public static boolean LMPress, LMRelease = false;
public static boolean LMRight, LMLeft = false;
private class mMouse extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
LMPress = true; LMRelease = false;
if(SwingUtilities.isRightMouseButton(e))
{
LMRight = true;
LMLeft = false;
}
else if(SwingUtilities.isLeftMouseButton(e))
{
LMLeft = true;
LMRight = false;
}
}
public void mouseReleased(MouseEvent e)
{
LMRelease = true; LMPress = false;
if(SwingUtilities.isRightMouseButton(e))
{
LMRight = true;
LMLeft = false;
}
else if(SwingUtilities.isLeftMouseButton(e))
{
LMLeft = true;
LMRight = false;
}
}
}
private class wWheel implements MouseWheelListener
{
public void mouseWheelMoved(MouseWheelEvent e)
{
int notches = e.getWheelRotation();
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {}
e.getScrollAmount();
screenPaint.moveY(e.getUnitsToScroll()*60); //desired pixel jump: 120
}
}
}
Mouse class:
import java.awt.*;
import java.awt.event.*;
public class Mouse {
public static int x() {
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
return (int) b.getX();
}
public static int y() {
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
return (int) b.getY();
}
public static boolean withinRect(int x, int y, int w, int h) {
if (x() >= x && x() < x + w && y() >= y && y() < y + h) return true;
else return false;
}
public static boolean press() {
return Display.LMPress;
}
public static boolean release() {
return Display.LMRelease;
}
public static boolean pressLeft() {
if (Display.LMPress && Display.LMLeft)
return true;
else return false;
}
public static boolean releaseLeft() {
if (Display.LMRelease && Display.LMLeft)
return true;
else return false;
}
public static boolean pressRight() {
if (Display.LMPress && Display.LMRight)
return true;
else return false;
}
public static boolean releaseRight() {
if (Display.LMRelease && Display.LMRight)
return true;
else return false;
}
}
Updating the view at 1 kHz is unrealistic; instead, consider the alternatives cited here. See this AnimationTest for an example of self-timing to determine your animation budget.
Addendum: The while(true) loop at the top is running at 100 Hz.
The available resolution of System.currentTimeMillis() may vary by platform.
Addendum: I am reopening this question because I was not able to fix it. Any more help?
Absent a Minimal, Complete, Tested and Readable Example, it's hard to say. You appear to be overriding paint(); was noted in Painting in AWT and Swing: The Paint Methods, "Swing programs should override paintComponent()." Moreover, you need to invoke super.paintComponent(), as shown here, to avoid visual artifacts.
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.
I am trying to make a space ship (PlayerShip.gif) in my game move left, right, up, and down when the coresponding keys are pressed. I know i need an keyboardListener but im having issues figuring out where it goes and how it is actually implimented. my code is as follows.
public class GamePanel extends JPanel implements KeyListener {
Timer timer1;
Timer timer2;
ArrayList<Ships> ship;
int x;
int y;
double speed;
int size;
int shipxCoord;
int shipyCoord;
int shipHeight;
int shipWidth;
int shipRise;
int shipRun;
boolean left = false;
boolean right = false;
boolean up = false;
boolean down = false;
Image enemyShip1;
Image enemyShip2;
Image playerShip;
ImageIcon ic = new ImageIcon("Ship.gif");
ImageIcon ic2 = new ImageIcon("Ship2.gif");
int width = ic.getIconWidth();
int height = ic.getIconHeight();
Image background = Toolkit.getDefaultToolkit().createImage("background.jpg");
public GamePanel(int size, double speed) {
super();
x = 450;
y = 510;
ship = new ArrayList<Ships>();
// call timer for 1st type of enemy Ship with a delay of 5 seconds between ships
enemy1Timer(5);
// call timer for 2nd type of enemy Ship with a delay of 3 seconds between ships
enemy2Timer(3);
this.size = size;
this.speed = speed;
enemyShip1 = new ImageIcon("ship.gif").getImage();
enemyShip2 = new ImageIcon("ship2.gif").getImage();
playerShip = new ImageIcon("playerShip.gif").getImage();
// this.add(image);
} // end constructor
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, null);
for (Ships s : ship) {
s.paintComponent(g);
}
g.drawImage(playerShip, x, y, this);
//g.drawImage(enemyShip2,x,y,this);
}// end method paintComponent
public void move() {
for (Ships s : ship) {
s.moveship(this);
// s.detectCollision(ship);
}
if (left) {
x -= speed;
}
if (right) {
x += speed;
}
if (up) {
y -= speed;
}
if (down) {
y += speed;
}
if (x > getWidth() - size) {
x = getWidth() - size;
}
if (x < 0) {
x = 0;
}
if (y > getHeight() - size) {
y = getHeight() - size;
}
if (y < 0) {
y = 0;
}
}// end method move
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_LEFT) {
left = true;
}
if (e.getKeyCode() == e.VK_RIGHT) {
right = true;
}
if (e.getKeyCode() == e.VK_UP) {
up = true;
}
if (e.getKeyCode() == e.VK_DOWN) {
down = true;
}
} // end method keyPressed
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == e.VK_LEFT) {
left = false;
}
if (e.getKeyCode() == e.VK_RIGHT) {
right = false;
}
if (e.getKeyCode() == e.VK_UP) {
up = false;
}
if (e.getKeyCode() == e.VK_DOWN) {
down = false;
}
}
public void enemy1Timer(int seconds) {
timer1 = new Timer();
timer1.schedule(new ShipSwarm1(), 1000, seconds * 1000);
}// end method enemy1Timer
class ShipSwarm1 extends TimerTask {
public void run() {
for (int Wave = 1; Wave > 0; Wave--) {
Ships enemy = new Ships(ic, enemyShip1);
ship.add(enemy);
}// end for
}// end method run
}// end class Enemy1Swarm
public void enemy2Timer(int seconds) {
timer2 = new Timer();
timer2.schedule(new ShipSwarm2(), 3000, seconds * 1000);
}// end method enemy1Timer
class ShipSwarm2 extends TimerTask {
public void run() {
for (int Wave = 1; Wave > 0; Wave--) {
Ships enemy = new Ships(ic2, enemyShip2);
ship.add(enemy);
}// end for
}// end method run
}
}
Take a look at this link for a game impelemented in Java and it does exactly what you are looking for. Key presses - up left right and down keys.
Its the famous 15-game
An excerpt from that,
private void processKeys(){
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e){
if(e.getID() == KeyEvent.KEY_PRESSED){
handleKeyPress(e.getKeyCode());
if(areThingsInPlace() && !dialogShown){
dialogShown = true;
JOptionPane.showMessageDialog(null,"Congratulations!!! YOU WIN!!");
System.exit(1);
}
}
return false;
}
});
}
The handleKeyPress() method for handling the arrow keys
private void handleKeyPress(int keyCode) {
int emptyIndex = findEmptyIndex();
int x = emptyIndex/SIZE;
int y = emptyIndex%SIZE;
switch (keyCode) {
case 37://LEFT KEY
if(y==SIZE-1) return;
doSwap(x,y,x,y+1);
break;
case 38://UP KEY
if(x==SIZE-1) return;
doSwap(x,y,x+1,y);
break;
case 39://RIGHT KEY
if(y==0) return;
doSwap(x,y,x,y-1);
break;
case 40://DOWN KEY
if(x==0) return;
doSwap(x,y,x-1,y);
break;
}
}
Also consider adding conrol over all eight (semi-) cardinal directions, as shown in this game. For greater flexibility, consider actions and key bindings, discussed here.