Flappy Bird Graphics Slow - java

I'm trying to write a simple flappy bird game as a Java Applet. The problem I'm having is that the graphics are extremely unresponsive, typically taking 5-10 seconds to respond after the key is pressed. Also, it only responds if the key is pressed a certain number of times, around 6 or 7. I don't think it's a problem with my computer, since I'm running it on a high-specs MacBook Pro (8 GB RAM, i5 processor). Here's the two main classes I use:
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
//The main class I use to run the game
public class Flap extends Applet implements Runnable, KeyListener
{
final int WIDTH = 700, HEIGHT = 500;
Thread thread;
Bird b;
boolean beenPressed = false;
public void init()
{
this.resize(WIDTH, HEIGHT);
this.addKeyListener(this);
b = new Bird();
thread = new Thread(this);
thread.start();
}
public void paint(Graphics g)
{
g.setColor(Color.CYAN);
g.fillRect(0, 0, WIDTH, HEIGHT - 100);
g.setColor(Color.green);
g.fillRect(0, 400, WIDTH, HEIGHT);
b.draw(g);
}
public void update(Graphics g)
{
paint(g);
}
#Override
public void run()
{
for(;;)
{
//Pillar upPillar = new Pillar()
b.move();
repaint();
try
{
Thread.sleep(500);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP)
{
if(!beenPressed)
{
b.setUp(true);
}
beenPressed = true;
}
else
{
b.setDown(true);
}
}
#Override
public void keyReleased(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP)
{
beenPressed = false;
b.setUp(false);
}
else
{
b.setDown(false);
}
}
#Override
public void keyTyped(KeyEvent arg0)
{
}
}
import java.awt.Color;
import java.awt.Graphics;
//The Bird class, which has the methods for the player to move
public class Bird
{
int x, y, yvel;
boolean goingUp, goingDown;
public Bird()
{
x = 200;
y = 200;
}
public void draw(Graphics g)
{
g.setColor(Color.yellow);
g.fillRect(x, y, 60, 25);
}
public void move()
{
if(goingUp)
{
yvel -= 50;
}
else if(goingDown)
{
yvel += 50;
}
y += yvel;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public void setUp(boolean b)
{
goingUp = b;
}
public void setDown(boolean b)
{
goingDown = b;
}
}
It's still unfinished, but at this stage, I think the bird should at least be moving.

The graphics isn't slow, the time between updates is to large. It basically allows for the key to be pressed and released before a update cycle takes place.
I would reduce Thread.sleep(500); to something more like Thread.sleep(10); and change the movement delta to something more like...
public void move()
{
if(goingUp)
{
yvel -= 1;
}
else if(goingDown)
{
yvel += 1;
}
y += yvel;
}
as a starting point.
Recommendations...
Using applets, bad idea. Applets are deprecated and a dead technology. Applet is also not double buffered, so you're probably going to end up with some horrible flashing going on. KeyListener is will known for having issues (not responding), while it's the only solution when using AWT, the ket bindings API is a better solution when using Swing
The first thing I would suggest, is having a look at using a JPanel as your base component and then have a look at Performing Custom Painting and Painting in Swing to get a better understanding of how painting works
If you "really" need high performance (or just want more control over the painting process), you should also have a look at BufferStrategy and BufferCapabilities
I'd also recommend having a look at JavaFX which has better APIs for this kind of thing

Related

Trying to move object with KeyListener in simple game

I am trying to create a simple game similar to brick-breaker. I was able to figure out some of the basic concepts of the game (moving the ball, collision detection, etc)
I am trying to move the platform object in an x-direction by using the left and right arrow keys. The if conditions for the keyPressed method work, after testing with some println statements but I am unable to move the platform object using keyListener. Is is something to do with the moveLeft , moveRight methods in the Platform class, because I tried d to changing the values of the dx, so I could maybe see some movement in the platform.
Here are the 3 classes.
import java.applet.*;
import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class tennisGame extends Applet implements Runnable, KeyListener{
Ball b;
Platform p;
public void init() {
setSize(640, 480);
addKeyListener(this);
}
public void start () {
b= new Ball();
p= new Platform();
Thread thread = new Thread (this);
thread.start ();
}
public void paint(Graphics g) {
b.paint(g);
p.paint(g);
}
public void run(){
while (true){
b.update(this);
p.update(this,b);
repaint();
try {
Thread.sleep(20);
}
catch (InterruptedException e){
//e.printStackTrace();
}
}
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == e.VK_RIGHT){
System.out.println("Pressed RIGHT");
p.moveRight();
}
if(e.getKeyCode() == e.VK_LEFT){
System.out.println("Pressed LEFT");
p.moveLeft();
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
import java.awt.*;
public class Ball{
private int x=0;
private int y=0;
private double dx=10;
private double dy=10;
private int width=20;
private int height=20;
private int radius=10;
public Ball() {
}
public void update(tennisGame tg){
if ( x + dx > tg.getWidth()-radius-1){
x = tg.getWidth()-radius-1;
dx= -dx;
}
else if ( x + dx < 0 + radius ){
x= 0 + radius;
dx= -dx;
}
else{
x+=dx;
}
if ( y + dy> tg.getHeight()-radius-1){
y = tg.getHeight()-radius-1;
dy= -dy;
}
else if ( y + dy < 0 + radius ){
y= 0 + radius;
dy= -dy;
}
else{
y+=dy;
}
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public double getDx() {
return dx;
}
public void setDx(int dx) {
this.dx = dx;
}
public void setDy(double dy) {
this.dy = dy;
}
public double getDy() {
return dy;
}
public int getRadius() {
return radius;
}
public void paint(Graphics g) {
g.setColor(new Color(0,0,250,250));
g.fillOval(x-radius,y-radius,width, height);
}
}
import java.awt.Color;
import java.awt.Graphics;
public class Platform {
private int x=275;
private int y=400;
int dx=0;
private int width=120;
private int height=20;
public void update(tennisGame tg,Ball b) {
checkForCollosion(b);
}
private void checkForCollosion(Ball b) {
int ballX= b.getX();
int ballY= b.getY();
int radius= b.getRadius();
if (ballY + radius > y && ballY + radius < y + height){
if (ballX > x && ballX < x + width){
double newDy= b.getDy()* -1 ;
b.setDy(newDy);
}
}
}
public void moveRight() {
if ( dx + 1 < 20){
dx+=1;
}
}
public void moveLeft() {
if ( dx -1 > -20){
dx-=1;
}
}
public void paint(Graphics g){
g.setColor(Color.red);
g.fillRect(x , y, width, height);
}
}
Your first problem is that in your moveRight() and moveLeft() methods you are checking the value of and updating dx, which isn't used anywhere in your code regarding the painting of the platform.
e.g.
public void moveRight() {
if (dx + 1 < 20) {
dx += 1; // updating dx, but x is used to paint
}
}
public void moveLeft() {
if (dx - 1 > -20) {
dx -= 1; // updating dx, but x is used to paint
}
}
Even if we change your methods to use x instead of dx your second problem is that incrementing or decrementing by one pixel isn't going to move by very much. However, if you hold down the left arrow key long enough you will the platform slowly creeping along. Nothing will happen when you press the right array (at first) because of your third problem: bounds checking.
The bounds checking in your move methods is based off of a value for x of 20, but the initial value of x is 275.
public void moveRight() {
if (x + 1 < 20) { // can't move very far from the left side of the screen
x += 1;
}
}
public void moveLeft() {
if (x - 1 > -20) { // goes left only a little bit off the screen
x -= 1;
}
}
You need to be using values which reflect the size of the applet. This code works, but for time's sake I've just hardcoded the boundary values. You should really calculate them based on the size of the tennisGame:
public void moveRight() {
if (x < 520) { // enable moving to the edge of the screen
x += 10; // move a little faster
}
}
public void moveLeft() {
if (x > 0) { // enable moving to the edge of the screen
x -= 10; // move a little faster
}
}
Call super.paint or be prepared for additional weirdness
KeyListener will only respond to key events when the component it is registered to is focusable and has focus
Consider using The Swing API instead of AWT. AWT components aren't double buffered and will flicker when updated. Instead, start with something like a JPanel and then add it to what ever you want
You could call, setFocusable(true) and requestFocusInWindow() but there's no guarantee that it will work or continue to work 100% of the time.
Instead, update the code to use Swing and take advantage of the key bindings API, which provides you with ability to control the level of focus required into order to trigger the key events
Updated...
You're also not updating the x position of the Platform, for example...
public void update(Tennis tg, Ball b) {
x += dx;
checkForCollosion(b);
}
This will now require you to perform range checking on the Platform to see if passes beyond the visible range of the view, if you about such things...
I also ended up adding a MouseListener which called requestFocusInWindow each time it was clicked, for example...
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
requestFocusInWindow();
}
});
This is why I don't like applets or KeyListener, to much stuffing about

Java Simple Bouncing Ball, SingleThread, Mouse Listener, JFrame

I've created a Bouncing Ball application in in Java. The goal is to have a ball appear on mousePressed() and have it bounce off the walls without leaving the frame. Only one Ball One Thread, should be easy.. My problem is that every time I click to make the ball appear it gets faster and I have no idea why. Can somebody help me please. PS: I'm new to threads.
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyFrame extends JPanel {
public int xPos, yPos, xDir = 3, yDir = 4;
public int diameter = 50;
public MyFrame(){
final JFrame thisFrame = new JFrame();
thisFrame.add(this);
thisFrame.setTitle("Bouncing Ball");
thisFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisFrame.setLocationRelativeTo(null);
thisFrame.setSize(500, 500);
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
xPos = e.getX();
yPos = e.getY();
Thread t = new Thread() {
#Override
public void run() {
while(true){
try{
Thread.sleep(10);
}catch(Exception e){};
xPos += xDir;
yPos += yDir;
if(xPos + diameter >= thisFrame.getWidth() - 25 || xPos <= 0) xDir = -xDir;
if(yPos + diameter >= thisFrame.getHeight() - diameter || yPos <= 0) yDir = -yDir;
repaint();
}
}
};
t.start();
}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
});
thisFrame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(xPos, yPos, diameter, diameter);
}
}
public class MyMain{
public static void main(String[] args) {
new MyFrame();
}
}
Every time you click, you are starting a new Thread, which means you have another thread updating the x/y positions.
For example, 1 thread means your update the x/p once per sync, 2 means you're updating the x/y position at least twice per cycle and this just gets compounded each time you add a new thread.
A better solution would be to start the Thread at some time earlier and then use a List to maintain the position and direction of the ball.
This will require a little but synchronisation to keep things safe
FYI a delay of 40 milliseconds is roughly 25 fps, 16 milliseconds is roughly 60 fps. IMHO, for what you are doing, 10 milliseconds seems excessive...

How to stop moving image in a JApplet from flickering

I managed to create a (basic) animated JApplet for the first time in 3 years, but I am annoyed with the image flickering when it moves. The Timer object is what is making the image move, and my private inner class "TimerListener" is responsible for the animated motion of the moving image.
Here is the code of my TimerListener class, where I think this problem may be able to be solved:
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(smileyFace.getImage(), xCoord, yCoord, this);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//Following if-else manipulates Y coordinate
if (goingUp) {
if (yCoord > minY) {
yCoord -= move;
}
else {
goingUp = false;
}
} else {
if (yCoord < (getContentPane().getHeight() - (smileyFace.getIconHeight()+ Y_OFFSET))) {
yCoord += move;
}
else {
goingUp = true;
}
}
//Following if-else manipulates X coordinate
if (goingSideways) {
if (xCoord > 0) {
xCoord -= move;
}
else {
goingSideways = false;
}
} else {
if (xCoord < (getContentPane().getWidth() - (smileyFace.getIconWidth() + X_OFFSET))) {
xCoord += move;
}
else {
goingSideways = true;
}
}
repaint();
}
}
If it helps, here is a screenshot of my JApplet - in this case, the troll face should be moving in the black area, and bouncing off the sides as it hits them:
For those of you who want to run and test the JApplet, you can get the Netbeans project from https://github.com/rattfieldnz/Java_Projects/tree/master/JAppletAnimation.
Thanks to the user 'arynaq', I have fixed my problem. I put the following paint method:
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(smileyFace.getImage(), xCoord, yCoord, this);
}
...into an inner class which extends JPanel (notice how I changed 'paint' to 'paintComponent'):
class ImagePanel extends JPanel
{
public ImagePanel()
{
setBackground(Color.BLACK);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(smileyFace.getImage(), xCoord, yCoord, this);
}
#Override
public void setBackground(Color bg) {
super.setBackground(bg); //To change body of generated methods, choose Tools | Templates.
}
}
... then added it to my JApplet via it's init() method (I'm not sure if I'd be correct by calling this the JApplet's constructor...):
#Override
public void init() {
smileyFace = new ImageIcon("images/happyFace.png");
**add(new ImagePanel());**
timerDelay = 10;
timer = new Timer(timerDelay, new TimerListener());
timer.start();
//getContentPane().setBounds(0, 0, CONTENTPANE_WIDTH, CONTENTPANE_HEIGHT);
getContentPane().setBackground(Color.BLACK);
//maxY = getContentPane().getHeight();
minY = 0;
xCoord = 0;
yCoord = 0;
move = 2;
}
You can see it running by cloning my GitHub JApplet project and running it in NetBeans :).

How to fix bad Double-Buffering [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I tried following a double buffering tutorial, and I really don't know what I did wrong. It works before then before I did the tutorial, but there is still and occasional flicker here and there. I have two files Game and gameLoop
Game:
import java.awt.Graphics;
public class Game extends gameLoop
{
public void init()
{
setSize(854,480);
Thread th = new Thread(this);
th.start();
offscreen = createImage(854,480);
d = offscreen.getGraphics();
}
public void paint(Graphics g)
{
d.clearRect(0, 0, 854, 480);
d.drawImage(disk, x, y, this);
g.drawImage(offscreen , 0, 0, this);
}
public void Update(Graphics gfx)
{
paint(gfx);
}
}
gameLoop
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
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.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class gameLoop extends Applet implements Runnable, MouseListener, MouseMotionListener
{
public int x, y, counter, mouseX, mouseY;
public Image offscreen;
public Graphics d;
public boolean up, down, left, right, pressed;
public BufferedImage disk1, disk2, disk3, disk4, disk;
public int ballSpeedX = -6;
public int ballSpeedY = -3;
public void run()
{
x = 400;
y = 200;
try {
disk1 = ImageIO.read(new File("disk1.png"));
disk2 = ImageIO.read(new File("disk2.png"));
disk3 = ImageIO.read(new File("disk3.png"));
disk4 = ImageIO.read(new File("disk4.png"));
} catch (IOException e1) {
e1.printStackTrace();
}
while(true)
{
if(x >= (854 - 150))
{
ballSpeedX = ballSpeedX * -1;
}
if(y >= (480 - 140))
{
ballSpeedY = ballSpeedY * -1;
}
if(y < (0 - 10))
{
ballSpeedY = ballSpeedY * -1;
}
if(x < (0- 10))
{
ballSpeedX = ballSpeedX * -1;
}
x = x + ballSpeedX;
y = y + ballSpeedY;
counter ++;
if(counter >= 4)
counter = 0;
if(counter == 0)
disk = disk1;
if(counter == 1)
disk = disk2;
if(counter == 2)
disk = disk3;
if(counter == 3)
disk = disk4;
System.out.println(counter);
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseMoved(MouseEvent m) {}
public void mousePressed(MouseEvent m)
{
}
public void mouseReleased(MouseEvent m)
{
pressed = false;
}
public void mouseDragged(MouseEvent e) {
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
mouseX = (int)b.getX();
mouseY = (int)b.getY();
ballSpeedX = mouseX;
ballSpeedY = mouseY;
}
}
public void Update(Graphics gfx)
{
paint(gfx);
}
Should be lower case, as you're trying to override the update(Graphics g) method in the Applet.
So it should be
#Override
public void update(Graphics gfx)
{
paint(gfx);
}
As for changing the background, a background is simply a big rectangle that covers the screen and makes it a certain color. In your paint, you're doing clearRect, which clears the screen. Instead just switch that to fillRect after setting the color.
It might look something like
public void paint(Graphics g)
{
//setColor to whatever you want
//fillRect to cover the screen
}
When you're doing this though, one thing you have to remember is to not confuse your two graphics objects. As a concept, double buffering works by drawing to memory first (drawing it on an offscreen image) and then to the screen. You want to always draw onto this offscreen image, as it is much faster (and we lose the flicker).
So make sure you're doing imageGraphicsObject.setColor not screenGraphicsObject.setColor or imageGraphicsObject.fillRectnotscreenGraphicsObject.fillRect`. Otherwise you're no longer double-buffering.
There are a number of different types "double buffers". The basic is a simple off screen image that you update and this gets painted to the screen instead. If done right, painting the image is often faster then drawing graphics to the screen.
Another type is page flipping. That is, you have an active buffer which is always rendered to the screen and a off screen/scratch buffer which is what you actually render to. You then flip these buffers when you are ready to render the updates to the screen (this is closer to how film animation works).
The following example is a REALLY basic example of page flipping.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.image.BufferedImage;
import static testdoublebuffer.TestDoubleBuffer.UPDATE;
public class AppletDoubleBuffer extends Applet {
private BufferedPane pane;
#Override
public void init() {
pane = new BufferedPane();
setLayout(new BorderLayout());
add(pane);
}
#Override
public void start() {
pane.start();
}
#Override
public void stop() {
pane.stop();
}
public class BufferedPane extends Panel {
private BufferedImage activeBuffer;
private BufferedImage scratch;
private boolean running = false;
public BufferedPane() {
}
public void start() {
if (!running) {
running = true;
Thread thread = new Thread(new MainLoop());
thread.setDaemon(true);
thread.start();
}
}
public void stop() {
running = false;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
public void invalidate() {
synchronized (UPDATE) {
activeBuffer = null;
scratch = null;
}
super.invalidate();
}
#Override
public void update(Graphics g) {
if (activeBuffer != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(activeBuffer, 0, 0, this);
g2d.dispose();
}
}
public class MainLoop implements Runnable {
private int delay = 1000 / 25;
private int x = 0;
private int velocity = 5;
private int size = 10;
public void update() {
x += velocity;
if (x + size >= getWidth()) {
x = getWidth() - size;
velocity *= -1;
} else if (x <= 0) {
x = 0;
velocity *= -1;
}
if (getWidth() > 0 && getHeight() > 0) {
synchronized (UPDATE) {
if (scratch == null) {
scratch = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2d = scratch.createGraphics();
int y = (getHeight() - size) / 2;
g2d.setBackground(Color.BLUE);
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.setColor(Color.RED);
g2d.fillOval(x, y, size, size);
g2d.dispose();
// Flip the buffers...
BufferedImage tmp = activeBuffer;
activeBuffer = scratch;
scratch = tmp;
}
}
}
#Override
public void run() {
while (running) {
long startTime = System.currentTimeMillis();
update();
repaint();
long duration = System.currentTimeMillis() - startTime;
if (duration < delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
}
}
}
}
}
}
}
I personally, would just skip using AWT and move to Swing which provides better/built in functionality for this type of thing.

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