I'm attempting to make Frogger in java for a school project but I'm having a lot of difficulties setting up KeyListener for the actual frog character.
I've tried setting up key bindings, requesting focus for the JPanel and JFrame, moving around where the character is initiated but nothing has seemed to work. This is the remnants of my attempts.
This is the program that runs my game.
import javax.swing.*;
public class Frogger
{
JFrame frame = new JFrame("Frogger");
CPT c = new CPT();
public Frogger()
{
frame.setBounds(0,0,700,500);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(c);
}
public static void main(String[] args){
new Frogger();
}
}
The main game
public CPT() {
setLayout(new BorderLayout());
label = new JLabel("Frogger");
frame1 = new JFrame("Main");
label.setFont(new Font("Serif", Font.BOLD,50));
label.setBounds(275,10,250,250);
button1 = new JButton("PLAY");
button1.setBounds(300,350,100,50);
button1.setOpaque(false);
button1.setVisible(true);
this.setOpaque(false);
this.setLayout(null);
this.add(label);
button1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setVisible(true);
frame1.setSize(700,500);
frame1.setResizable(false);
frame1.setFocusable(false);
button1.setVisible(false);
frame1.add(new TrainCanvas());
frame1.add(p1);
p1.requestFocus();
}
});
this.add(button1); }
This is the TrainCanvas class that Draws the cars in the games as well as the frog
class TrainCanvas extends JComponent
{
private int lastX = 0;
private int lastX_1 = 0;
private int lastX_2 = 0;
public TrainCanvas() {
Thread animationThread = new Thread(new Runnable() {
public void run() {
while (true) {
repaint();
try {Thread.sleep(10);} catch (Exception ex) {}
}
}
});
animationThread.start();
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
//Draws Train 1
int w = getWidth();
int h = getHeight();
int trainW_1 = 100;
int trainH_1 = 5;
int trainSpeed_1 = 3;
int x = lastX + trainSpeed_1;
if (x > w + trainW_1) {
x = -trainW_1;
}
gg.setColor(Color.BLACK);
gg.fillRect(x, h/2 + trainH_1, trainW_1, trainH_1);
lastX = x;
Graphics2D g3 = (Graphics2D) g;
frog = new Rectangle(f_x,f_y,25,25);
g3.fill(frog);
g3.setColor(Color.GREEN);
}
}
Finally, the Key Listener
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()== KeyEvent.VK_UP)
{
CPT.f_y -= 100;
repaint();
}
else if(e.getKeyCode()== KeyEvent.VK_RIGHT)
{
CPT.f_x += 100;
repaint();
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
CPT.f_x -= 100;
repaint();
}
else if(e.getKeyCode()==KeyEvent.VK_DOWN)
{
CPT.f_y += 100;
repaint();
}
else {}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
The program runs perfectly fine without giving me any errors, which is making this troublesome. Whenever it gets to the main game window, none of the keys seem to work.
This question already has answers here:
Non-static variable cannot be referenced from a static context
(15 answers)
Closed 4 years ago.
I know there are many questions out there regarding action listeners etc.
However, none can help me with my specific issue...no matter which way I try to do it I always get an error.
Here is my simple bouncing ball program:
public class ControlledBall extends JPanel implements Runnable {
int diameter;
long delay;
private int x;
private int y;
private int vx;
private int vy;
public ControlledBall(int xvelocity, int yvelocity) {
diameter = 30;
delay = 40;
x = 1;
y = 1;
vx = xvelocity;
vy = yvelocity;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g.setColor(Color.blue);
g.fillOval(x,y,30,30);
g.setColor(Color.black);
g2.drawOval(x,y,30,30); //draw
}
public void run() {
while(isVisible()) {
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
System.out.println("Something Went Wrong!");
}
move();
repaint();
}
}
public void move() {
if(x + vx < 0 || x + diameter + vx > getWidth()) {
vx *= -1;
}
if(y + vy < 0 || y + diameter + vy > getHeight()) {
vy *= -1;
}
x += vx;
y += vy;
}
public void stop(){
x=0;
y=0;
}
public class Action implements ActionListener{
public void actionPerformed(ActionEvent e){
stop();
}
}
public static void main(String[] args) {
ControlledBall ball2 = new ControlledBall(12,2);
JFrame window = new JFrame("Controlled Ball");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton stop = new JButton("Stop");
stop.setSize(4,400);
stop.setVisible(true);
stop.setText("Stop");
// stop.addActionListener(new Action());
stop.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
window.add(stop);
JButton start = new JButton("Start");
start.setSize(100,100);
start.setVisible(true);
start.setText("Start");
window.add(start);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
c.ipadx = 400;
c.ipady = 400;
c.gridx = 10;
c.gridy = 10;
window.add(ball2,c);
c.ipadx = 50;
c.ipady = 20;
c.gridx = 10;
c.gridy = 10;
window.pack();
window.setSize(600,600);
window.setLocation(250,200);
window.setVisible(true);
new Thread(ball2).start();
}
}
as you can see by the commented bits I've tried a few different techniques and none have worked. any advice would be greatly appreciated.
Thanks
The main error I get is:
non static field cannot be referenced from a static context
and I assume that's because I'm running it from the main method.
The first thing you really want to do is get rid of your run method (and your reliance on Runnable). This is really an inappropriate way to perform regular updates in Swing.
Swing is single threaded and NOT thread safe, your current approach risks dirty read/writes across thread boundaries.
Instead, you want to use a Swing Timer, see How to Use Swing Timers for more details.
The next thing you want to do is add a start method and update the stop method to support the use of a Swing Timer...
public class ControlledBall extends JPanel {
//...
private Timer timer;
public void stop() {
if (timer == null) {
return;
}
timer.stop();
timer = null;
x = 0;
y = 0;
}
public void start() {
if (timer != null) {
return;
}
timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
move();
repaint();
}
});
timer.start();
}
Then, your start and stop buttons just need to be updated to call these methods...
stop.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ball2.stop();
}
});
//...
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ball2.start();
}
});
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Giving me a Syntax error that "cannot find MyKeyListener". I am trying to add it so player class can be implemented into the grid.So far i have created both player and maze but cant seem able to add player to maze because of this syntax error. Can anyone point out what mistake i am making.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; // Needed for ActionListener
import javax.swing.event.*; // Needed for ActionListener
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class www extends JFrame
{
static Maze maze = new Maze ();
static Timer t;
//======================================================== constructor
public www ()
{
// 1... Create/initialize components
// 2... Create content pane, set layout
JPanel content = new JPanel (); // Create a content pane
content.setLayout (new BorderLayout ()); // Use BorderLayout for panel
JPanel north = new JPanel ();
north.setLayout (new FlowLayout ()); // Use FlowLayout for input area
DrawArea board = new DrawArea (500, 500);
// 3... Add the components to the input area.
content.add (north, "North"); // Input area
content.add (board, "South"); // Output area
// 4... Set this window's attributes.
setContentPane (content);
pack ();
setTitle ("MAZE");
setSize (490, 500);
setKeyListener(new MyKeylistener());
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo (null); // Center window.
}
public static void main (String[] args)
{
www window = new www ();
window.setVisible (true);
//jf.setTitle("Tutorial");
//jf.setSize(600,400);
}
class DrawArea extends JPanel
{
public DrawArea (int width, int height)
{
this.setPreferredSize (new Dimension (width, height)); // size
}
public void paintComponent (Graphics g)
{
maze.show (g); // display current state of colony
}
}
}
class Maze
{
private int grid [][];
public Maze ()
{
int [][] maze =
{ {1,0,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1,1,1,0,1},
{1,0,0,0,1,1,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,0,0,1},
{1,0,1,0,1,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,0,1},
{1,1,1,1,1,1,1,1,1,1,1,0,1}};
grid = maze;
}
public void show (Graphics g)
{
for (int row = 0 ; row < grid.length ; row++)
for (int col = 0 ; col < grid [0].length ; col++)
{
if (grid [row] [col] == 1) // life
g.setColor (Color.black);
else
g.setColor (Color.white);
g.fillRect (col * 30 + 30, row * 30 + 30, 30, 30); // draw life form
}
//g.setColor(Color.RED);
//g.fillRect(60,30,30,50);
}
class MyKeyListener extends KeyAdapter {
int x = 0, y = 0,velX = 0, velY = 0;
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if(c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if (c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if( c==KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c==KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public MyKeyListener ()
{
tm.start ();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x,y,50,30);
}
public void actionPerformed(ActionEvent e)
{
x = x+velX;
y = y +velY;
repaint();
}
}
// public void player ()
// {
//
// Timer tm = new Timer(5,this);
// int x = 0;
// int y = 0;
// int velX = 0 ;
// int velY = 0;tm.start();
// addKeyListener(this);
// setFocusable(true);
// setFocusTraversalKeysEnabled(false);
// }
// public void actionPerformed(ActionEvent e)
// {
// x = x+velX;
// y = y +velY;
// repaint();
// }
// public void keyPressed(KeyEvent e)
// {
// int c = e.getKeyCode();
// if(c == KeyEvent.VK_LEFT)
// {
// velX = -1;
// velY = 0;
// }
// if (c == KeyEvent.VK_UP)
// {
// velX = 0;
// velY = -1;
// }
// if( c==KeyEvent.VK_RIGHT)
// {
// velX = 1;
// velY = 0;
// }
// if(c==KeyEvent.VK_DOWN)
// {
// velX = 0;
// velY = 1;
// }
// }
//
// public void keyTyped(KeyEvent e){}
//
// public void keyReleased(KeyEvent e){}
}
MyKeyListener is an inner Class of Maze. You could reference it through Maze.MyKeyListener.
Note that this does not seem to be a good idea either : the www class is your UI component and should be the one defining the key listener, rather than the Maze model.
You've written MyKeyListener inside of your Maze class. Usually, if you want to add a new listener that's only going to be referenced once, you can actually write the listener within the setKeyListener() method's parameter.
The new setKeyListener() line would look like this,
setKeyListener(new Keylistener(){
int x = 0, y = 0,velX = 0, velY = 0;
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if(c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if (c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if( c==KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c==KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public MyKeyListener ()
{
tm.start ();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x,y,50,30);
}
public void actionPerformed(ActionEvent e)
{
x = x+velX;
y = y +velY;
repaint();
}
});
The MyKeyListener class can then be deleted.
It's worth noting that you usually want to define your key listeners in top level UI objects, like panes, or in this case your Maze model. Right now you are setting your key listener in a child UI item, so it may not trigger if that item is out of focus.
Im working on an assignment where an image moves around and when the user clicks on the panel the image stops. When the user clicks on the panel again the image starts. As of now i can only start and stop the image once before it stays going. I need help to loop this process so that the user can keep starting and stopping the image.
Here is my code
Main:
import javax.swing.*;
public class Rebound {
//-----------------------------------------------------------------
// Displays the main frame of the program.
//-----------------------------------------------------------------
public static void main (String[] args)
{
JFrame frame = new JFrame ("Rebound");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ReboundPanel());
frame.pack();
frame.setVisible(true);
}
}
Panel:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ReboundPanel extends JPanel
{
private final int DELAY = 10, IMAGE_SIZE = 35;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY;
public ReboundPanel()
{
timer = new Timer(DELAY, new ReboundListener());
addMouseListener (new StopListener());
image = new ImageIcon ("happyFace.gif");
x = 0;
y = 40;
moveX = moveY = 3;
setPreferredSize (new Dimension(1900, 1000));
setBackground (Color.black);
timer.start();
}
public void paintComponent (Graphics page)
{
super.paintComponent (page);
image.paintIcon (this, page, x, y);
}
private class ReboundListener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{
x += moveX;
y += moveY;
if (x <= 0 || x >= 1900-IMAGE_SIZE)
moveX = moveX * -1;
if (y <= 0 || y >= 1000-IMAGE_SIZE)
moveY = moveY * -1;
repaint();
}
}
// Represents the action listener for the timer.
public class StopListener extends MouseAdapter
{
public void mouseClicked (MouseEvent event)
{
if (event.getButton() == MouseEvent.BUTTON1)
{
timer.stop();
}
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent event) {
if(event.getButton() == MouseEvent.BUTTON1)
{
timer.start();
removeMouseListener(this);
}
}
});
}
}
}
You can simply reuse the same listener, and check the state of the timer before starting/stopping it:
public void mouseClicked(MouseEvent event)
{
if (event.getButton() == MouseEvent.BUTTON1)
{
if (timer.isRunning()) {
timer.stop();
}
else {
timer.start();
}
}
}
In you StopListener class have an instance variable bool isMoving = true;
Then in your handler should use that to determine whether to stop or start the timer:
public void mouseClicked( MouseEvent event )
{
if( event.getButton() == MouseEvent.BUTTON1 )
{
if( isMoving )
timer.stop();
else
timer.start();
isMoving = !isMoving;
}
}
so i using netbeans, and i'm starting to get into coding games... and i've done this so far with no errors, however when i run it just a grey box with my title "zachs game appears and thats it.... please help if you know the problem 1 -thank you
package swing9;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class JavaApplication2 extends JFrame implements Runnable {
int x, y, xDirection, yDirection;
Font font = new Font("Arial", Font.BOLD | Font.ITALIC, 30);
public void run() {
try {
while (true) {
move();
Thread.sleep(5);
}
} catch (Exception e) {
System.out.println("Error");
}
}
public void move() {
x += xDirection;
y += yDirection;
if (x <= 0)
x = 0;
if (x >= 300)
x = 300;
if (y <= 50)
y = 50;
if (y <= 300)
y = 300;
}
public void seyXDir(int xdir) {
xDirection = xdir;
}
public void setYDirection(int ydir) {
yDirection = ydir;
}
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
int setXDirection = -1;
}
if (keyCode == e.VK_RIGHT) {
int setXDirection = +1;
}
if (keyCode == e.VK_UP) {
int setYDirection = -1;
}
if (keyCode == e.VK_DOWN) {
int setYDirection = +1;
}
}
}
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
int setXDirection = 0;
}
if (keyCode == e.VK_RIGHT) {
int setXDirecetion = 0;
}
if (keyCode == e.VK_UP) {
int setYDirectiom = 0;
}
if (keyCode == e.VK_DOWN) {
int setYDirecction = 0;
}
}
public JavaApplication2() {
addKeyListener((KeyListener) new JavaApplication2.AL());
setTitle("Zachs Game");
setSize(300, 300);
setResizable(false);
setVisible(true);
setBackground(Color.blue);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 150;
y = 150;
}
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.drawString("Play", 40, 40);
g.setFont(font);
g.setColor(Color.red);
g.fillOval(x, y, 15, 15);
repaint();
}
public static void main(String[] args) {
new JavaApplication2();
// threads
Thread t1 = new Thread();
t1.start();
}
}
JFrame or any of its super classes do not implement the paintComponent method so is never invoked. Check this yourself by adding the #Override annotation.
Move this method to a new class that extends JComponent and invoke super.paintComponent(g) as the first statement.
Don't call repaint from within paintComponent, this create an infinite loop and degrades performance. Swing Timers were designed to interact more easily with swing components. Use these over than raw Threads for periodic updates.
Aside: JFrame is not focusable by default so KeyEvents which require focus will not be triggered without making the window focusable. Use Key Bindings instead.