Java Game freezing on mouse click - java

I working on a small project and came across something that I didn't know how to fix. I tried looking into threads to see if this was the problem, but couldn't find anything to help me. The problem is that whenever I click on the frame, the key input, animations, etc, all freeze.
Here's the code for the main class: (let me know if you need code from any of the other classes, but I think the problem lies here)
package me.runeglaive.main;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import me.runeglaive.gamestate.GameStateManager;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static int height = 360;
public static int width = height * 16 / 9;
public static int scale = 2;
private JFrame frame;
private Graphics g;
private boolean running = true;
GameStateManager gsm;
public Game(){
frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setSize(width * scale, height * scale);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gsm = new GameStateManager();
init();
MouseListener ml = new MouseListener(){
public void mousePressed(MouseEvent e) {
gsm.mousePressed(e);
}
public void mouseReleased(MouseEvent e) {
gsm.mouseReleased(e);
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
};
KeyListener kl = new KeyListener(){
public void keyPressed(KeyEvent k) {
gsm.keyPressed(k);
}
public void keyReleased(KeyEvent k) {
gsm.keyReleased(k);
}
public void keyTyped(KeyEvent k) {
}
};
frame.addKeyListener(kl);
frame.addMouseListener(ml);
frame.setFocusable(true);
}
public void init(){
}
public void update(double delta){
gsm.update(delta);
}
public void render(){
//double buffering
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(2);
return;
}
g = bs.getDrawGraphics();
//clear screen
g.clearRect(0, 0, getWidth(), getHeight());
//Draw gameState
gsm.render(g);
g.dispose();
bs.show();
}
public synchronized void start(){
running = true;
new Thread(this).start();
}
public synchronized void stop(){
running = false;
}
public void run() {
//initialize time loop variables
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
double lastFpsTime = 0;
while(running)
{
//Calculate since last update
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double)OPTIMAL_TIME);
//update frame counter
lastFpsTime += updateLength;
//update FPS counter
if(lastFpsTime >= 1000000000)
{
lastFpsTime = 0;
}
//game updates
update(delta);
//graphics (gameState)
render();
try{
Thread.sleep((Math.abs(lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000));
}catch(InterruptedException e){
System.out.println("Error in sleep");
}
}
}
public static void main(String args[]){
new Game().start();
}
}
Heres the Game State Manager:
package me.runeglaive.gamestate;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class GameStateManager {
private ArrayList<GameState> states;
private int currentState;
public static final int MENUSTATE = 0;
public static final int MAINSTATE = 1;
public GameStateManager(){
states = new ArrayList<GameState>();
states.add(new MenuState(this));
states.add(new MainState(this));
setState(MAINSTATE);
}
public void setState(int state){
currentState = state;
states.get(state).init();
}
public int getCurrentState(){
return currentState;
}
public void update(double delta){
states.get(currentState).update(delta);
}
public void render(Graphics g){
states.get(currentState).render(g);
}
public void keyPressed(KeyEvent k){
states.get(currentState).keyPressed(k);
}
public void keyReleased(KeyEvent k){
states.get(currentState).keyReleased(k);
}
public void mousePressed(MouseEvent e){
states.get(currentState).mousePressed(e);
}
public void mouseReleased(MouseEvent e){
states.get(currentState).mouseReleased(e);
}
}

What is the code for gsm.mousePressed(e); and gsm.mouseReleased(e) please? :)
You're misusing Java Swing. You shall not create an own thread and redraw the scene programmatically, since this interferes with the threading model of the input queue.
If you're using swing, then instead of starting an own thread, start up a swing timer. Call the update from the event listener of the timer. Instead of calling render, issue a repaint() on the frame and override the painting code of the frame if you want to play nice.
http://www.oracle.com/technetwork/java/painting-140037.html
In case of AWT, there is both system triggered painting and application triggered paiting.
The code you're doing is a perfectly valid brute force game coder thinking - and perfectly valid if you're having a full control on the screen. In case of Swing, this is not the case, as Swing does take care of a lot more. If you're messing with Mr.Swing, it will bite you sooner or later ;-)
If you prefer taking this game development more seriously, look for a Java 2D game engine, or a Java 3D game engine (such as jMonkey) which takes care of all the details and offer working vertical retrace sync - which is unavoidable for smooth movements. Note that your BufferStrategy will not take care of that, this topic is a way more complex.

Related

Move a rectangle when a key is pressed

I need the loop() method to be able to run repaint() but it does nothing when it's called.
Moreover, the loop() method also doesn't update() when executing the code. I've tried many different variations to try and get it to work but nothing has worked. In addition to that, I use the IDE Eclipse because my teacher said we shouldn't use game engines but write the code from scratch.
class:GamePanel
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 {
private static final long serialVersionUID = 1L;
final int originalTilesize=16;
final int scale=3;
final int tileSize=originalTilesize *scale;
final int maxScreenRow=12;
final int maxScreenCol=16;
final int screenWidth=tileSize*maxScreenCol;
final int screenHeight=tileSize*maxScreenRow;
int FPS=60;
KeyHandler keyH = new KeyHandler(); // implements KeyHandler in GamePanel
Thread gameThread;
int playerX=100;
int playerY=100;
int playerSpeed=4;
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;
double nextDrawTime=System.nanoTime()+drawInterval;// TODO Auto-generated method stub
while (gameThread !=null) {
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();
}
};
}
public void update()
{
if (keyH.upPressed == true)
{
playerY-=playerSpeed;
}
else if(keyH.downPressed==true)
{
playerY +=playerSpeed;
}
else if(keyH.leftPressed==true)
{
playerX -=playerSpeed;
}
else if(keyH.rightPressed==true)
{
playerX +=playerSpeed;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g;
g2.setColor(Color.white);
g2.fillRect(playerX,playerY,tileSize,tileSize);
g2.dispose();
}
}
class:KeyListener
package main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyHandler implements KeyListener {
public boolean upPressed,downPressed,leftPressed,rightPressed;
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int code =e.getKeyCode();
if (code==KeyEvent.VK_W) {
upPressed = true;
}
if (code==KeyEvent.VK_S) {
downPressed=true;
}
if (code==KeyEvent.VK_A) {
leftPressed=true;
}
if (code==KeyEvent.VK_D) {
rightPressed=true;
}
}
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
int code=e.getKeyCode();
if (code==KeyEvent.VK_W) {
upPressed = false;
}
if (code==KeyEvent.VK_S) {
downPressed=false;
}
if (code==KeyEvent.VK_A) {
leftPressed=false;
}
if (code==KeyEvent.VK_D) {
rightPressed=false;
}
}
}
You don't need a "game loop" that redraws the GUI every few seconds. You just need to call method repaint. Also, it is not recommended to call method repaint from a thread which is not the Event Dispatch Thread (EDT). Lastly, you should use key bindings rather than a KeyListener.
The below code is not a complete solution. It just sets up a key binding for the down-arrow key which moves the rectangle down when the user presses the down-arrow key. Note that you also need to handle the situation when the rectangle hits the edge of the GamePanel – unless you want to draw the rectangle at such a location that it doesn't appear in the GamePanel.
(More notes after the code.)
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
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 GamePanel extends JPanel {
private static final long serialVersionUID = 1L;
final int originalTilesize = 16;
final int scale = 3;
final int tileSize = originalTilesize * scale;
final int maxScreenRow = 12;
final int maxScreenCol = 16;
final int screenWidth = tileSize * maxScreenCol;
final int screenHeight = tileSize * maxScreenRow;
int playerX = 100;
int playerY = 100;
int playerSpeed = 4;
public GamePanel() {
setPreferredSize(new Dimension(screenWidth, screenHeight));
setBackground(Color.black);
setFocusable(true);
InputMap im = getInputMap();
im.put(KeyStroke.getKeyStroke("DOWN"), "DOWN");
ActionMap am = getActionMap();
am.put("DOWN", new DownAction());
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(playerX, playerY, tileSize, tileSize);
g.dispose();
}
class DownAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
playerY += playerSpeed;
repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame();
frame.add(new GamePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
This line is not required as it is the default.
this.setDoubleBuffered(true);
Method startGameThread is not required (as explained above) and should therefore be removed. Consequently, method run should also be removed which means that class GamePanel does not need to implement interface Runnable. Also no need for variables FPS and gameThread.
As shown in above code, you need to write an Action for each key binding which therefore replaces method update so that method can also be removed. In the above code, I have created one Action, named DownAction. You need to create an Action for the other arrow keys. The keystroke names are:
UP
RIGHT
LEFT
Since we are using key bindings, no need for class KeyHandler nor for variable keyH.
Method paintComponent has protected access so no need to make it public.
In method paintComponent you are only calling methods of class Graphics so no need for the cast.
I added a main method so that the above code is a runnable application.

how do I make this java awt/ swing animation work?

I'm pretty new to java coding, but i know the basic structures of how to code. I am not familiar with awt/swing, and don't know what my error is.
Background: I searched up ways to animate with java, found zetcode tutorials.
I copy/pasted their code, and tested the program, to make sure it works. the JFrame opened, but nothing drew. Maybe this is a system compatibility error? if so, how would I fix it?
these are the two separate classes:
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class ThreadAnimationExample extends JFrame {
public ThreadAnimationExample() {
initUI();
}
private void initUI() {
add(new Board());
setResizable(false);
pack();
setTitle("Star");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame ex = new ThreadAnimationExample();
ex.setVisible(true);
}
});
}
}
This is the main class.
Board.java
package com.zetcode;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Board extends JPanel
implements Runnable {
private final int B_WIDTH = 350;
private final int B_HEIGHT = 350;
private final int INITIAL_X = -40;
private final int INITIAL_Y = -40;
private final int DELAY = 25;
private Image star;
private Thread animator;
private int x, y;
public Board() {
initBoard();
}
private void loadImage() {
ImageIcon ii = new ImageIcon("star.png");
star = ii.getImage();
}
private void initBoard() {
setBackground(Color.BLACK);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
setDoubleBuffered(true);
loadImage();
x = INITIAL_X;
y = INITIAL_Y;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawStar(g);
}
private void drawStar(Graphics g) {
g.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
}
private void cycle() {
x += 1;
y += 1;
if (y > B_HEIGHT) {
y = INITIAL_Y;
x = INITIAL_X;
}
}
#Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
cycle();
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("Interrupted: " + e.getMessage());
}
beforeTime = System.currentTimeMillis();
}
}
}
When I run the program, I get a blank black window. The program is supposed to draw a star. Here is what it is supposed to look like.

Thread Animation Example not working

I was trying to follow these tutorials http://zetcode.com/tutorials/javagamestutorial/animation/ and none of the three examples on that page seem to be working for me. One of them uses a swing timer, one uses the utility timer, and the last and supposedly most effective and accurate according to the page uses a thread to animate.
I will show you the one using the thread, since it is the way that I think I will be doing thing's when using animation for making games.
ThreadAnimationExample.java (in the tutorial it is called star.java but obviously that wont work)
import java.awt.EventQueue;
import javax.swing.JFrame;
public class ThreadAnimationExample extends JFrame {
public ThreadAnimationExample() {
add(new Board());
setTitle("Star");
pack();
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame ex = new ThreadAnimationExample();
ex.setVisible(true);
}
});
}
}
Board.java (the main class)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Board extends JPanel
implements Runnable {
private final int B_WIDTH = 350;
private final int B_HEIGHT = 350;
private final int INITIAL_X = -40;
private final int INITIAL_Y = -40;
private final int DELAY = 25;
private Image star;
private Thread animator;
private int x, y;
public Board() {
loadImage();
initBoard();
}
private void loadImage() {
ImageIcon ii = new ImageIcon("star.png");
star = ii.getImage();
}
private void initBoard() {
setBackground(Color.BLACK);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
setDoubleBuffered(true);
x = INITIAL_X;
y = INITIAL_Y;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawStar(g);
}
private void drawStar(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
private void cycle() {
x += 1;
y += 1;
if (y > B_HEIGHT) {
y = INITIAL_Y;
x = INITIAL_X;
}
}
#Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
cycle();
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("Interrupted: " + e.getMessage());
}
beforeTime = System.currentTimeMillis();
}
}
}
If you are using Eclipse you should create a source folder and add that image to the source folder. Then you could use this:
ImageIcon ii = new ImageIcon( getClass().getResource("/imageName.png") );

Why Won't the Screen Change Color

I looked and the codes seems fine to me. Got an error but hopefully it's the source code, not something wrong with the cpu I have nor JDK.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.*;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
public static int width = 300;
public static int height = width / 16*9;
public static int scale = 3;
private Thread thread;
private boolean running = false;
private JFrame frame;
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){
tick();
render();
}
}
public void tick() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs==null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
bs.dispose();
bs.show();
}
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Title");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Then I got this error, even when I countlessly modified the source code I had.
Exception in thread "Display" java.lang.NullPointerException
at java.awt.Component$BltBufferStrategy.showSubRegion(Component.java:4307)
at java.awt.Component$BltBufferStrategy.show(Component.java:4255)
at com.thecherno.Rain.Game.render(Game.java:58)
at com.thecherno.Rain.Game.run(Game.java:39)
at java.lang.Thread.run(Thread.java:695)
Im starting to seem if it because of an outdated JDK. Current Version I have is JDK 6.
You state:
What Im trying to do is change color as seen in the render method. The background to be black.
Use Swing components such as a JComponent or JPanel.
Simply call setBackground(Color.BLACK) on the component will do.
You appear to be creating a game loop of some type. Consider using a Swing Timer for this.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Game2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W / 16 * 9;
private static final int SCALE = 3;
private static final Color BACKGROUND = Color.BLACK;
private static final int TIMER_DELAY = 20;
private Timer swingTimer;
public Game2() {
setBackground(BACKGROUND);
swingTimer = new Timer(TIMER_DELAY, new TimerListener());
swingTimer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: add any custom painting here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W * SCALE, PREF_H * SCALE);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO add code that gets called in game loop
}
}
private static void createAndShowGui() {
Game2 mainPanel = new Game2();
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Note that this code is based on your stated requirements and what I'm guessing are other requirements based on your code. If there are further requirements not mentioned, please elaborate them for us.
Try using g.dispose(); followed by bs.show(); and then
g = (Graphics2D)bs.getDrawGraphics();. I know it looks weird, but you are emptying the canvas and then refilling it using your strategy. You may also need to do an initial check for g being null and initialize it before the first display loop.

Why wont my Java program acknowledge any key strokes using KeyListener?

I have literally no idea why my program isn't recognizing keyboard input. I have places print statements throughout the program to determine the issue, and I have determined that the keyPressed method never activates. This is for a game which I am making for a class project, and yes I am a relatively beginner programmer. Thanks in advance! (Code below)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
public class Dodger extends JApplet implements Runnable, KeyListener {
Thread myThread;
public Image bg;
public Image pic;
public boolean loaded;
public int cx, cy, speed, x, y;
public void init(){
setSize(800,800);
loaded = false;
x = 2;
y = 400;
cx = 0;
cy = 0;
speed = 3;
myThread = new Thread(this);
myThread.start();
addKeyListener(this);
}
public void run(){
loadpic();
repaint();
while (myThread!=null)
{
try{
myThread.sleep(18);
}catch(InterruptedException e){
e.printStackTrace();
}
repaint();
}
}
public void upMotion(){
cy = cy + speed;
}
public void downMotion(){
cy = cy - speed;
}
public void leftMotion(){
cx = cx - speed;
}
public void rightMotion(){
cx = cx + speed;
}
#Override
public void keyPressed(KeyEvent k) {
if (k.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("work");
leftMotion();
}
if (k.getKeyCode() == KeyEvent.VK_RIGHT) {
rightMotion();
}
if (k.getKeyCode() == KeyEvent.VK_UP) {
upMotion();
}
if (k.getKeyCode() == KeyEvent.VK_DOWN) {
downMotion();
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
public void loadpic(){
bg = new ImageIcon(getClass().getResource("back.png")).getImage();
pic = new ImageIcon(getClass().getResource("smile.png")).getImage();
loaded = true;
repaint();
}
public void paint(Graphics g){
g.drawImage(bg, 0, 0, this);
g.drawImage(pic, cx, cy, this);
}
}
The key events are detected just fine when the applet is focusable & has focus. Managing focus has always been a problem with applets. The problem is mostly that Sun never bothered to specify the focus behavior that should ideally apply to a mixed page of focusable HTML elements and applet(s).
As per Tom's advice, add to the end of init()
setFocusable(true);
To be safe, also override:
public void start() {
this.requestFocusInWindow();
}
As an aside, generally it is better to use key bindings in Swing. They also require the applet to have input focus.
First off, you probably want to separate out your class from your KeyListener, as it makes it a bit harder to read.
Next, you want to get rid of the bare Thread and wrap it in a timer.
import javax.swing.Timer;
class Dodger extends JApplet {
Timer imageUpdater; //replaces Thread
/*...*/
public void init() {
/*etc*/
loadpic();
int repaintInterval = 100;
imageUpdater = new Timer(repaintInterval,
new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
}
);
imageUpdater.start();
addKeyListener(new KeyHandler());
setFocusable(true);
}
/*...*/
private class KeyHandler extends KeyAdapter {
/* Note that with this implementation, you do not have to override
* unnecessary methods, as KeyAdapter is an abstract class that
* implements all of the methods of KeyListener.
*/
#Override
public void keyPressed(KeyEvent e) {
/*...*/
}
}
/*...*/
}
Most of this is just code cleanup - the actual problem may be fixed (according to Tom, see comments) with the setFocusable(true).
I'm not really sure if it applies to Applets, but your Thread may not allowing the event dispatching to occur.
Try to run your "work" with SwingWorker.

Categories