I'm having trouble with creating an animation of a square that will move at a certain speed when one of the arrow keys are pressed. I have implemented both of the keyPressed, and the actionPerformed methods and also started the tick of the timer at end of the constructor.. But the square still wont' move.. What am i doing wrong?
Below is the JPanel.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class A3JPanel extends JPanel implements KeyListener, ActionListener{
public static final int JFRAME_AREA_WIDTH = A3Constants.JFRAME_AREA_WIDTH;
public static final int JFRAME_AREA_HEIGHT = A3Constants.JFRAME_AREA_HEIGHT;;
public static final Rectangle HOME_AREA = A3Constants.HOME_AREA;
public static final Rectangle LEO_LEFT_AREA = A3Constants.LEO_LEFT_AREA;
public static final Rectangle ALL_WALLS_AREA = A3Constants.ALL_WALLS_AREA;
public static final Rectangle EXITING_SLIDES_AREA = A3Constants.EXITING_SLIDES_AREA;
public static final Color NICE_GRAY_COLOUR = A3Constants.NICE_GRAY_COLOUR;
public static final Color GAME_SCREEN_COLOUR = A3Constants.GAME_SCREEN_COLOUR;
public static final Color SLIDES_AREA_COLOUR = A3Constants.SLIDES_AREA_COLOUR;
public static final Color LEO_AREA_COLOUR = A3Constants.LEO_AREA_COLOUR;
public static final Color HOME_AREA_COLOUR = A3Constants.HOME_AREA_COLOUR;
public static final Color WALL_COLOUR = A3Constants.WALL_COLOUR;
public static final int MAX_WALLS = A3Constants.MAX_WALLS;
public static final Font TINY_FONT = A3Constants.TINY_FONT;
public static final Font LARGE_FONT = A3Constants.LARGE_FONT;
public static final Font HUGE_FONT = A3Constants.HUGE_FONT;
public static final int LARGE_FONT_SIZE = A3Constants.LARGE_FONT_SIZE;
public static final int HUGE_FONT_SIZE = A3Constants.HUGE_FONT_SIZE;
public static final Point TICKS_POSITION = A3Constants.TICKS_POSITION;
public static final Point WINNER_LOSER_INFO_POSITION = A3Constants.WINNER_LOSER_INFO_POSITION;
public static final Point INFORMATION_POSITION1 = A3Constants.INFORMATION_POSITION1;
public static final Point INFORMATION_POSITION2 = A3Constants.INFORMATION_POSITION2;
public static final Point INFORMATION_POSITION3 = A3Constants.INFORMATION_POSITION3;
public static final int TICKS_ALLOWED = A3Constants.TICKS_ALLOWED;
public static final int UP = A3Constants.UP;
public static final int DOWN = A3Constants.DOWN;
public static final int LEFT = A3Constants.LEFT;
public static final int RIGHT = A3Constants.RIGHT;
private CoolCat coolCat;
private Timer t;
public A3JPanel() {
setBackground(Color.GREEN);
coolCat = new CoolCat(A3Constants.LEO_START_AREA.x, A3Constants.LEO_START_AREA.y);
addKeyListener(this);
t = new Timer(30,this);
t.start();
//t.addActionListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
drawGameArea(g);
coolCat.draw(g);
}
private void drawGameArea(Graphics g){
g.setColor(A3Constants.LEO_AREA_COLOUR);
g.fillRect(A3Constants.LEO_LEFT_AREA.x, A3Constants.LEO_LEFT_AREA.y, A3Constants.LEO_LEFT_AREA.width, A3Constants.LEO_LEFT_AREA.height);
g.setColor(A3Constants.WALL_COLOUR);
g.fillRect(A3Constants.ALL_WALLS_AREA.x, A3Constants.ALL_WALLS_AREA.y, A3Constants.ALL_WALLS_AREA.width, A3Constants.ALL_WALLS_AREA.height);
g.setColor(A3Constants.HOME_AREA_COLOUR);
g.fillRect(A3Constants.HOME_AREA.x, A3Constants.HOME_AREA.y, A3Constants.HOME_AREA.width, A3Constants.HOME_AREA.height);
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP){
coolCat.setDirection(A3Constants.UP);
}
if(e.getKeyCode() == KeyEvent.VK_DOWN){
coolCat.setDirection(A3Constants.DOWN);
}
if(e.getKeyCode() == KeyEvent.VK_LEFT){
coolCat.setDirection(A3Constants.LEFT);
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
coolCat.setDirection(A3Constants.RIGHT);
}
}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
public void actionPerformed(ActionEvent e){
coolCat.move();
repaint();
}
}
And below is the other Class.
import java.awt.*;
public class CoolCat {
public static final Rectangle LEO_START_AREA = A3Constants.LEO_START_AREA;
public static final int GAME_SCREEN_AREA_TOP = A3Constants.GAME_SCREEN_AREA_TOP;
public static final int GAME_SCREEN_AREA_BOTTOM = A3Constants.GAME_SCREEN_AREA_BOTTOM;
public static final int GAME_SCREEN_AREA_LEFT = A3Constants.GAME_SCREEN_AREA_LEFT;
public static final int GAME_SCREEN_AREA_RIGHT = A3Constants.GAME_SCREEN_AREA_RIGHT;
public static final int UP = A3Constants.UP;
public static final int DOWN = A3Constants.DOWN;
public static final int LEFT = A3Constants.LEFT;
public static final int RIGHT = A3Constants.RIGHT;
private Rectangle area;
private int speed;
private int direction;
public CoolCat(int x, int y){
this.speed = speed;
speed = (int)(Math.random() * (8 - 4 + 1)) + 4;
area = new Rectangle(A3Constants.LEO_START_AREA.x, A3Constants.LEO_START_AREA.y);
direction = RIGHT;
}
public Rectangle getArea(){
area = new Rectangle(LEO_START_AREA.x, LEO_START_AREA.y, LEO_START_AREA.width, LEO_START_AREA.height);
return area;
}
public void setDirection(int direction){
this.direction = direction;
}
//public boolean hasReachedHome(Rectangle zhomeArea){}
public void move(){
if(direction == A3Constants.UP){
area.y -= speed;
} else if(direction == A3Constants.DOWN){
area.y += speed;
} else if(direction == A3Constants.LEFT){
area.x -= speed;
} else if(direction == A3Constants.RIGHT){
area.x += speed;
}
}
public void draw(Graphics g){
g.setColor(Color.RED);
g.fillOval(A3Constants.LEO_START_AREA.x, A3Constants.LEO_START_AREA.y, A3Constants.LEO_START_AREA.width, A3Constants.LEO_START_AREA.height);
}
}
You are adding a KeyListener to a JPanel, a component that by default cannot accept the focus, and the focus is required for key listeners to work.
A simple solution would be to allow your JPanel to accept focus and then request focus be given to it.
A better solution is to avoid use of KeyListeners for Swing applications and instead use Key Bindings (as has been discussed in similar questions many times previously). For example, please check out: How to make an image move while listening to a keypress in Java.
Try something like this. I just made this quickly, so please excuse any errors.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class g{
public static void main(String args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
create();
}
});
}
public static MyPanel my;
public static void create(){
JFrame f = new JFrame("test");
my = new MyPanel();
f.add(my);
f.setSize(1000,1000);
f.setVisible(true);
f.addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode == 37){ //left
my.move(4); //1 = up, 2 = right, 3 = down, 4 = left
}
if(e.getKeyCode == 39){ //left
my.move(2); //1 = up, 2 = right, 3 = down, 4 = left
}
if(e.getKeyCode == 38){ //left
my.move(1); //1 = up, 2 = right, 3 = down, 4 = left
}
if(e.getKeyCode == 40){ //left
my.move(3); //1 = up, 2 = right, 3 = down, 4 = left
}
}
#Override
public void keyReleased(KeyEvent e){
//do nothings
}
#Override
public void keyTyed(KeyEvent e){
//do nothing
}
});
}
}
public class MyPanel extends JPanel implements ActionListener{
public static Timer time1;
public Square s;
public MyPanel(){
time1 = new Timer(50, this);
time1.start();
}
public void actionPerformed(ActionEvent e){
repaint();
}
public void move(int d){
if(d == 1){
s.setY(s.getY()-1);
}
if(d == 2){
s.setX(s.getX() + 1);
}
if(d == 3){
s.setY(s.getY() + 1);
}
if(d == 4){
s.setX(set.getX() - 1);
}
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
s.paintSquare(g);
}
}
public class Square{
public int x;
public int y;
public void setX(int xPos){
this.x = xPos;
}
public int getX(){
return x;
}
public void setY(int yPos){
this.y = yPos;
}
public int getY(){
return y;
}
public void paintSquare(Graphics g){
g.setColor(Color.WHITE);
g.fillRect(0,0,1000,1000);
g.setColor(Color.RED);
g.fillRect(x,y,30,30);
}
}
Related
I am working on a donkey kong type game and like I said I want the player to only jump if he is on the floor.
I made a sort of a gravity mechanic and I check collision so he don't go through a floor and I came up with an idea that your can jump only when you are colliding. But here comes the main problem that I don't know how to tell that information to a method in another class.
Hope it makes some sense, I am a beginner and don't know if I described the problem well.
I tried to separate my code but it makes more problems
Here's a class with a player:
import java.awt.*;
import java.awt.event.KeyEvent;
public class Mario extends Rectangle {
int rychlost = 5;
int xZrychleni;
int gravitace= 5;
int yZrychleni;
int vyskok = 20;
Mario(int x, int y, int SIRKA_MARIA,int VYSKA_MARIA){
super(x, y, SIRKA_MARIA, VYSKA_MARIA);
}
public void nakresli(Graphics g) {
g.setColor(Color.white);
g.fillRect(x, y, width, height);
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_A) {
nastavSmerX(-rychlost);
}
if(e.getKeyCode()== KeyEvent.VK_D) {
nastavSmerX(rychlost);
}
if(e.getKeyCode()==KeyEvent.VK_SPACE){
nastavSmerY(vyskok);
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_A) {
nastavSmerX(0);
}
if (e.getKeyCode() == KeyEvent.VK_D) {
nastavSmerX(0);
}
if(e.getKeyCode()==KeyEvent.VK_SPACE){
nastavSmerY(0);
}
}
public void nastavSmerX ( int SmerX){
xZrychleni = SmerX;
}
public void nastavSmerY ( int SmerY){
yZrychleni = SmerY;
}
public void move () {
x = x + xZrychleni;
y = y + gravitace;
y = y - yZrychleni;
}
}
Here is a panel class where I check collisions:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class HerniPanel extends JPanel implements Runnable{
static final int HERNI_SIRKA = 1200;
static final int HERNI_VYSKA = 700;
static final Dimension SCREEN_SIZE = new Dimension(HERNI_SIRKA, HERNI_VYSKA);
static final int SIRKA_PLOSINY = 1000;
static final int VYSKA_PLOSINY = 35;
static final int SIRKA_ZEBRIKU = 25;
static final int VYSKA_ZEBRIKU = 180;
static final int MARIO_VELIKOST_XY = 50;
Thread gameThread;
Image image;
Graphics graphics;
Plosina plosina0;
Plosina plosina1;
Plosina plosina2;
Plosina plosina3;
Mario mario;
Zebrik zebrik1;
Zebrik zebrik2;
Zebrik zebrik3;
HerniPanel(){
novaPlosina();
novyMario();
novyZebrik();
this.setFocusable(true);
this.addKeyListener(new AL());
this.setPreferredSize(SCREEN_SIZE);
gameThread = new Thread(this);
gameThread.start();
}
public void novaPlosina() {
plosina0 = new Plosina(0, (HERNI_VYSKA - VYSKA_PLOSINY), HERNI_SIRKA, VYSKA_PLOSINY, 1);
plosina1 = new Plosina((HERNI_SIRKA - SIRKA_PLOSINY),(HERNI_VYSKA - VYSKA_PLOSINY - 180), SIRKA_PLOSINY, VYSKA_PLOSINY, 2 );
plosina2 = new Plosina(0, (HERNI_VYSKA - VYSKA_PLOSINY - 360), SIRKA_PLOSINY, VYSKA_PLOSINY,3 );
plosina3 = new Plosina((HERNI_SIRKA - SIRKA_PLOSINY), (HERNI_VYSKA - VYSKA_PLOSINY - 540), HERNI_SIRKA, VYSKA_PLOSINY,4);
}
public void novyMario(){
mario= new Mario(1000, (HERNI_VYSKA - VYSKA_PLOSINY - MARIO_VELIKOST_XY), MARIO_VELIKOST_XY , MARIO_VELIKOST_XY );
}
public void novyZebrik(){
zebrik1 = new Zebrik(250, (HERNI_VYSKA-VYSKA_PLOSINY-VYSKA_ZEBRIKU),SIRKA_ZEBRIKU,VYSKA_ZEBRIKU);
zebrik2 = new Zebrik(800, (HERNI_VYSKA-VYSKA_PLOSINY-VYSKA_ZEBRIKU-180),SIRKA_ZEBRIKU,VYSKA_ZEBRIKU);
zebrik3 = new Zebrik(300, (HERNI_VYSKA-360-VYSKA_PLOSINY-VYSKA_ZEBRIKU),SIRKA_ZEBRIKU,VYSKA_ZEBRIKU);
}
public void paint(Graphics g) {
image = createImage(getWidth(),getHeight());
graphics = image.getGraphics();
nakresli(graphics);
g.drawImage(image,0,0,this);
}
public void nakresli(Graphics g) {
plosina0.nakresli(g);
plosina1.nakresli(g);
plosina2.nakresli(g);
plosina3.nakresli(g);
mario.nakresli(g);
zebrik1.nakresli(g);
zebrik2.nakresli(g);
zebrik3.nakresli(g);
Toolkit.getDefaultToolkit().sync();
}
public void move() {
mario.move();
}
public void zkontrolujKolizi() {
if(mario.x<=0)
mario.x=0;
if(mario.x >= (HERNI_SIRKA-MARIO_VELIKOST_XY))
mario.x = HERNI_SIRKA-MARIO_VELIKOST_XY;
if (mario.y >= (HERNI_VYSKA-VYSKA_PLOSINY - MARIO_VELIKOST_XY)) {
mario.y = (HERNI_VYSKA - VYSKA_PLOSINY - MARIO_VELIKOST_XY);
}
if(mario.intersects(plosina1)){
mario.y = (HERNI_VYSKA-VYSKA_PLOSINY-MARIO_VELIKOST_XY-180);
}
if(mario.intersects(plosina2)){
mario.y = (HERNI_VYSKA-VYSKA_PLOSINY-MARIO_VELIKOST_XY-360);
}
if(mario.intersects(plosina3)){
mario.y = (HERNI_VYSKA-VYSKA_PLOSINY-MARIO_VELIKOST_XY-540);
}
}
public void run() {
//game loop
long lastTime = System.nanoTime();
double amountOfTicks =60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
while(true) {
long now = System.nanoTime();
delta += (now -lastTime)/ns;
lastTime = now;
if(delta >=1) {
move();
zkontrolujKolizi();
repaint();
delta--;
}
}
}
public class AL extends KeyAdapter{
public void keyPressed(KeyEvent e) {
mario.keyPressed(e);
}
public void keyReleased(KeyEvent e) {
mario.keyReleased(e);
}
}
}
I made a fairly simple code and i got into an error which confused me.
So I have a class that creates two totally different variables and creating them using the new keyword
Player playerLeft = new Player(5,150);
Player playerRight = new Player( 150,150);
Player class:
import javax.swing.*;
import java.awt.*;
public class Player extends JComponent {
private int posY;
private int posX;
public Player(int x, int y) {
posX = x;
posY = y;
//repaint();
}
public float getMovementY() {
return movementY;
}
public void setMovementY(int movementY) {
this.movementY = movementY;
}
int movementY = 0;
public void paintComponent(Graphics g) {
Graphics2D _g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(posX, posY, 20, 150);
_g2.fill(rect);
}
public void setLocation(int x, int y) {
posY = y;
posX = x;
repaint();
}
public void move() {
setLocation(posX, posY + movementY);
}
}
It's probably me not knowing something about Java but for me when I try to instantiate playerRight it just overwrites player left and drawsOut playerRight only.
Here is the complete code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;
public class mainJFrame extends JFrame implements KeyListener {
int relativeTimeMillsec = 0;
Player playerLeft = new Player(5, 150);
Player playerRight = new Player(150, 150);
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
relativeTimeMillsec++;
refreshTimeText(relativeTimeMillsec);
calcMovements();
}
};
//components
JLabel timeCounterLabel = new JLabel("Time: " + 0, SwingConstants.CENTER);
public mainJFrame() {
createComponents();
addKeyListener(this);
}
public void createComponents() {
this.setTitle("The title");
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
timer.scheduleAtFixedRate(task, 0, 10);
JButton testButton = new JButton("Label");
testButton.setSize(100, 25);
testButton.setLocation(this.getWidth() / 2 - testButton.getWidth() / 2, this.getHeight() / 2 - testButton.getHeight() / 2);
timeCounterLabel.setSize(200, 25);
timeCounterLabel.setLocation(this.getWidth() / 2 - timeCounterLabel.getWidth() / 2, 10);
//playerRight = new Player(this.getWidth()-45,this.getHeight()/2);
// this.add(testButton);
this.add(timeCounterLabel);
this.add(playerLeft);
this.add(playerRight);
}
public void paintComponent(Graphics g) {
{
super.repaint();
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_S) {
playerLeft.movementY = +2;
} else if (e.getKeyCode() == KeyEvent.VK_W) {
playerLeft.movementY = -2;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
playerRight.movementY = +2;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerRight.movementY = -2;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
private double calcRealRelativeTime(int _relTime) {
return relativeTimeMillsec / (double) 100;
}
private void refreshTimeText(int _relTime) {
timeCounterLabel.setText("Time: " + Math.round(calcRealRelativeTime(_relTime)));
}
private void calcMovements() {
playerLeft.move();
playerRight.move();
}
}
Understand that a JFrame's contentPane (the container that holds its components) uses BorderLayout by default, and this code:
this.add(timeCounterLabel);
this.add(playerLeft);
this.add(playerRight);
is adding all components to the same default BorderLayout.CENTER position, meaning any components added will replace components added previously.
But more importantly, yours is a common problem and stems from your having your Player class extend from a GUI component. Don't do this, as then you will have a great deal of difficulty drawing multiple Player objects and having them interact easily (as you're finding out). Instead have Player be a logical (non-component) class, and have only one class extend JPanel and do all the drawing. This class can hold Player objects, perhaps held in a collection such as an ArrayList<Player>, and then iterate through the collection within its paintComponent method.
Other issues:
Do not use java.util.Timer and java.util.TimerTask for Swing animations since these classes do not follow Swing threading rules. Use instead a javax.swing.Timer.
Learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others
If/when you do override a painting method such as paintComponent, be sure to call the super's method within your override, usually on the first line, so as not to break the painting chain. Also, use the #Override annotation before this method and any other methods that you think that you may be overriding so that the compiler catches possible errors with this.
For example (but not a complete example)
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.*;
#SuppressWarnings("serial")
public class SimpleAnimation extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 20;
private Player2 playerLeft = new Player2(5, 150, Color.RED);
private Player2 playerRight = new Player2(150, 150, Color.BLUE);
public SimpleAnimation() {
playerLeft.setySpeed(1);
playerRight.setySpeed(-1);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
playerLeft.draw(g);
playerRight.draw(g);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
playerRight.move();
playerLeft.move();
repaint();
}
}
private static void createAndShowGui() {
SimpleAnimation mainPanel = new SimpleAnimation();
JFrame frame = new JFrame("SimpleAnimation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Player2 {
private static final int RECT_WIDTH = 20;
private static final int RECT_HEIGHT = 50;
private int x;
private int y;
private int ySpeed;
private Color color;
public Player2(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setySpeed(int ySpeed) {
this.ySpeed = ySpeed;
}
public int getySpeed() {
return ySpeed;
}
public void setLocation(int x, int y) {
setX(x);
setY(y);
}
public void move() {
setLocation(x, y + ySpeed);
}
public void draw(Graphics g) {
g.setColor(color);
g.fillRect(x, y, RECT_WIDTH, RECT_HEIGHT);
}
}
So here is the code after taking the tips into account.
The map is kept being repainted, the keylistener has changed but there still seems to be a problem.
The problem again is, the little square in the upper left corner will not move, which is the desired outcome.
package schoolgamev2;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Spel {
public static void main(String[] args) {
Speelveld map = new Speelveld();
map.Speelveld();
map.GenerateMap();
}
}
class Speelveld extends JPanel {
final int rijen = 16;
final int kolommen = 16;
Speler speler = new Speler();
Loopgebied loopgebied = new Loopgebied();
Blokken blok = new Blokken();
int[][] coordinaten = new int[rijen][kolommen];
public void Speelveld() {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
setFocusable(true);
addKeyListener(new KeyListener(this));
}
//genereer map
public void GenerateMap() {
Random random = new Random();
int x;
int y;
for (y = 0; y < rijen; y++) { //scan langs y
for (x = 0; x < kolommen; x++) { //scan langs x
//selecteert type blok voor coordinaten x y
coordinaten[x][y] = random.nextInt(4);
//debugprint
}
//debugprint
}
coordinaten[0][0] = 4; //speler begint altijd links boven
coordinaten[15][15] = 5; //finish is altijd rechts onder
}
public int[][] getCoordinaten() {
return coordinaten;
}
public Speler getSpeler2() {
return speler;
}
public int getSpelerX() {
return speler.getX();
}
public int getSpelerY() {
return speler.getY();
}
public void setSpelerX(int x) {
speler.setX(x);
}
public void setSpelerY(int y) {
speler.setY(y);
}
//#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int x;
int y;
for (y = 0; y < rijen; y++) { //scan langs y
System.out.println("");
for (x = 0; x < kolommen; x++) { //scan langs x
blok.setX(x);
blok.setY(y);
blok.setType(coordinaten[x][y]);
System.out.print(coordinaten[x][y] + " ");
switch (blok.getType()) {
case 0:
loopgebied.teken(g);
break;
case 4:
speler.teken(g);
/*case 5:
eindveld.teken(g);
break;*/
default:
break;
}
}
}
}
}
class Speler extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX(), blok.getY(), 10, 10);
}
}
class Loopgebied extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX() * size, blok.getY() * size, size, size);
}
}
class Blokken {
private static int x;
private static int y;
private static int type;
public int size = 16;
//setters voor x y en type
public void setX(int xIn) {
x = xIn;
}
public void setY(int yIn) {
y = yIn;
}
public void setType(int typeIn) {
type = typeIn;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getType() {
return type;
}
}
class KeyListener extends KeyAdapter {
private static final int SCALE = 3;
private Speelveld speelveld;
public KeyListener(Speelveld speelveld) {
this.speelveld = speelveld;
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
int deltaX = 0;
int deltaY = 0;
if (key == KeyEvent.VK_LEFT) {
deltaX = -1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_UP) {
deltaX = 0;
deltaY = -1 * SCALE;
} else if (key == KeyEvent.VK_RIGHT) {
deltaX = 1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_DOWN) {
deltaX = 0;
deltaY = 1 * SCALE;
} else {
return;
}
int x = speelveld.getSpelerX() + deltaX;
int y = speelveld.getSpelerY() + deltaY;
speelveld.setSpelerX(x);
speelveld.setSpelerY(y);
speelveld.repaint();
}
}
As mentioned in comments, you got your player, the Speler class, that extends JPanel and is wired to use a KeyListener, but note that it is not being used as a JPanel, and so the KeyListener is non-functioning, because they only work when they have been added to a visible component that has focus.
Suggestions:
Again as per comments, make Speler a non-GUI logical class. Meaning don't have it extend JPanel or any other Swing component, and certainly don't add a KeyListener to it.
Instead give it code for the player's behavior and for having the player draw itself, and that's it. What I'm suggesting is that you try to separate part of your "Model" here the player from the "View" here the Swing GUI.
Have one JPanel and only one that does drawing. Have it override paintComponent (don't forget to call the super's paintComponent within it), and have it draw each logical component by calling the logical component's draw method (public void verf(Graphics2D g2)? or public void teken(Graphics2D g2)?) within its paintComponent method.
As a general rule, you also don't want your GUI component classes, the JPanel here, directly implementing listener interfaces, such as the KeyListener, but will want to keep them separate.
Either make this drawing JPanel focusable, give it focus and add the KeyListener, a separate class, to it.
Or better, use Key Bindings as per the tutorial: Key Bindings
For example the simple [MCVE] below doesn't use a Swing Timer or change velocities, but rather it uses a KeyListener to change position of the Speler2 object using only one drawing JPanel and a KeyListener. If I were making this more robust and larger, I would use the Swing Timer, would use Key Bindings, and would change the velocities using the key bindings.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Spel2 {
private static final int VELD_WIDTH = 500;
private static void createAndShowGui() {
Speelveld2 speelveld2 = new Speelveld2(VELD_WIDTH, VELD_WIDTH);
JFrame frame = new JFrame("Spel2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(speelveld2);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
speelveld2.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyKeyListener extends KeyAdapter {
private static final int SCALE = 3;
private Speelveld2 speelveld2;
public MyKeyListener(Speelveld2 speelveld2) {
this.speelveld2 = speelveld2;
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
int deltaX = 0;
int deltaY = 0;
if (key == KeyEvent.VK_LEFT) {
deltaX = -1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_UP) {
deltaX = 0;
deltaY = -1 * SCALE;
} else if (key == KeyEvent.VK_RIGHT) {
deltaX = 1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_DOWN) {
deltaX = 0;
deltaY = 1 * SCALE;
} else {
return;
}
int x = speelveld2.getSpelerX() + deltaX;
int y = speelveld2.getSpelerY() + deltaY;
speelveld2.setSpelerX(x);
speelveld2.setSpelerY(y);
speelveld2.repaint();
}
}
#SuppressWarnings("serial")
class Speelveld2 extends JPanel {
private int prefW;
private int prefH;
private Speler2 speler2 = new Speler2();
public Speelveld2(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
setFocusable(true);
addKeyListener(new MyKeyListener(this));
}
public Speler2 getSpeler2() {
return speler2;
}
public int getSpelerX() {
return speler2.getX();
}
public int getSpelerY() {
return speler2.getY();
}
public void setSpelerX(int x) {
speler2.setX(x);
}
public void setSpelerY(int y) {
speler2.setY(y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
speler2.teken(g2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
class Speler2 extends Blokken2 {
private static final int RECT_W = 10;
public Speler2() {
super(BlokkenType.SPELER);
}
#Override
public void teken(Graphics2D g2) {
int x = getX();
int y = getY();
g2.drawRect(x, y, RECT_W, RECT_W);
}
}
class Blokken2 {
private int x;
private int y;
private int velx = 0;
private int vely = 0;
private BlokkenType type;
private BufferedImage img;
public Blokken2(BlokkenType type) {
this.type = type;
}
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 int getVelx() {
return velx;
}
public void setVelx(int velx) {
this.velx = velx;
}
public int getVely() {
return vely;
}
public void setVely(int vely) {
this.vely = vely;
}
public BlokkenType getType() {
return type;
}
public void setType(BlokkenType type) {
this.type = type;
}
public void setImg(BufferedImage img) {
this.img = img;
}
public BufferedImage getImg() {
return img;
}
public void teken(Graphics2D g2) {
if (img != null) {
g2.drawImage(img, x, y, null);
}
}
}
enum BlokkenType {
LOOPGEBIED, BARRICADE, MUUR, SLEUTEN, SPELER, EINDVELD
}
Edit: your latest code has an error here:
class Speler extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX(), blok.getY(), 10, 10);
}
}
Regarding your edit:
Now when you create a Speler instance, you create TWO Blokken instances, one which is the Speler instance since it extends Blokken and the other which is contained by the Speler instance since it also has a Blokken field.
You update the x/y state of the first one, but you draw with the second one, and that's why no motion is being displayed. The solution is obvious: use one or the other but not both. Either have Speler extend Blokken or have it contain a Blokken instance but don't do both.
I have a problem with repaint() method in my Java code. I want to call it in another class but I can't, something doesn't work at all. I've searched on forums, but nothing was able to help me out.
My Main class:
public class Main {
public static Main main;
public static JFrame f;
public Main(){
}
public static void main(String[] args) {
main = new Main();
f = new JFrame();
Ball b = new Ball();
f.getContentPane().setBackground(Color.GRAY);
f.add(b);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setTitle("Test");
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addMouseMotionListener(b);
f.addKeyListener(new Key());
}
}
Ball class where I created 2DGraphics for moving shapes:
public class Ball extends JLabel implements MouseMotionListener{
public Ball(){
}
public static double x = 10;
public static double y = 10;
public static double width = 40;
public static double height = 40;
String nick;
boolean isEllipse = true;
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if(isEllipse){
Ellipse2D e2d = new Ellipse2D.Double(x, y, width, height);
g2d.setColor(Color.RED);
g2d.fill(e2d);
}
else{
Rectangle2D r2d = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(Color.GREEN);
g2d.fill(r2d);
}
}
#Override
public void mouseDragged(MouseEvent e) {
isEllipse = false;
x = e.getX() - 30;
y = e.getY() - 40;
this.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX() - 30;
y = e.getY() - 40;
isEllipse = true;
this.repaint();
}
}
And Key class where I put KeyListener for move the shapes by key pressing:
public class Key extends Ball implements KeyListener {
public Key() {
}
#SuppressWarnings("static-access")
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
super.x += 10;
super.repaint();
System.out.println("x: " + super.x);
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
But something is wrong with this code: super method doesn't work for Key class. Everything in Ball class is working well. Where is the problem?
Super works fine, but your interpretation of what it does is wrong. Your problem is that you're trying to use inheritance to solve a problem that isn't solved with inheritance. You need to call repaint() on the actual visualized and used Ball instance, not on an instance of some completely different class, Key, that inappropriately extends from Ball. First off, make Key not extend Ball, pass in a true Ball reference into Key and the solution will fall from that.
Perhaps do something like this:
f.addKeyListener(new Key(b));
and
public class Key implements KeyListener {
private Ball ball;
public Key(Ball ball) {
this.ball = ball;
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
b.incrX(10); // give Ball a public method for this
b.repaint();
// System.out.println("x: " + super.x);
}
}
// .... etc...
Note, myself, I'd use Key Bindings for this, not a KeyListener, since then I wouldn't have to futz with keyboard focus.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class MoveBall {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static void createAndShowGui() {
BallPanel ballPanel = new BallPanel(PREF_W, PREF_H);
MyMouse myMouse = new MyMouse(ballPanel);
ballPanel.addMouseListener(myMouse);
ballPanel.addMouseMotionListener(myMouse);
new CreateKeyBindings(ballPanel);
JFrame frame = new JFrame("MoveBall");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(ballPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
#SuppressWarnings("serial")
class BallPanel extends JPanel {
private static final Color ELLIPSE_COLOR = Color.RED;
private static final Color SQUARE_COLOR = Color.GREEN;
private static final int BALL_WIDTH = 40;
private int prefW;
private int prefH;
private boolean isEllipse = true;
private int ballX;
private int ballY;
public BallPanel(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
}
public boolean isEllipse() {
return isEllipse;
}
public void setEllipse(boolean isEllipse) {
this.isEllipse = isEllipse;
}
public int getBallX() {
return ballX;
}
public void setBallX(int ballX) {
this.ballX = ballX;
}
public void setXY(int x, int y) {
ballX = x;
ballY = y;
repaint();
}
public void setXYCenter(int x, int y) {
ballX = x - BALL_WIDTH / 2;
ballY = y - BALL_WIDTH / 2;
repaint();
}
public void setXYCenter(Point p) {
setXYCenter(p.x, p.y);
}
public int getBallY() {
return ballY;
}
public void setBallY(int ballY) {
this.ballY = ballY;
}
public void incrementBallX(int x) {
ballX += x;
repaint();
}
public void incrementBallY(int y) {
ballY += y;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (isEllipse) {
g2.setColor(ELLIPSE_COLOR);
g2.fillOval(ballX, ballY, BALL_WIDTH, BALL_WIDTH);
} else {
g2.setColor(SQUARE_COLOR);
g2.fillOval(ballX, ballY, BALL_WIDTH, BALL_WIDTH);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
class MyMouse extends MouseAdapter {
private BallPanel ballPanel;
public MyMouse(BallPanel ballPanel) {
this.ballPanel = ballPanel;
}
#Override
public void mousePressed(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
}
enum Direction {
UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT);
private int key;
private Direction(int key) {
this.key = key;
}
public int getKey() {
return key;
}
}
// Actions for the key binding
#SuppressWarnings("serial")
class MyKeyAction extends AbstractAction {
private static final int STEP_DISTANCE = 5;
private BallPanel ballPanel;
private Direction direction;
public MyKeyAction(BallPanel ballPanel, Direction direction) {
this.ballPanel = ballPanel;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (direction) {
case UP:
ballPanel.incrementBallY(-STEP_DISTANCE);
break;
case DOWN:
ballPanel.incrementBallY(STEP_DISTANCE);
break;
case LEFT:
ballPanel.incrementBallX(-STEP_DISTANCE);
break;
case RIGHT:
ballPanel.incrementBallX(STEP_DISTANCE);
break;
default:
break;
}
}
}
class CreateKeyBindings {
private BallPanel ballPanel;
public CreateKeyBindings(BallPanel ballPanel) {
this.ballPanel = ballPanel;
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = ballPanel.getInputMap(condition);
ActionMap actionMap = ballPanel.getActionMap();
for (Direction direction : Direction.values()) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(direction.getKey(), 0);
String keyString = keyStroke.toString();
inputMap.put(keyStroke, keyString);
actionMap.put(keyString, new MyKeyAction(ballPanel, direction));
}
}
}
I have a very strange bug in my 2d game made using Java.
Description of the game: the player can move a rocket sprite with the mouse, and must dodge a rectangle that is going to follow the player and kill the player(by collision). Instead of following the player, it only moves to the beginning coordinates of the player, which is 400,400. It should move to the direction the player goes to. Please help me if you know what is wrong.
Main class:
import javax.swing.*;
public class Main extends JFrame{
private static final long serialVersionUID = 1L;
final static int WW = 800;
final static int WH = 600;
public Main(){
setSize(WW,WH);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setTitle("Space Game");
add(new GameClass());
setVisible(true);
}
public static void main(String[] args) {
new Main();
}
}
GameClass class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GameClass extends JPanel implements ActionListener, KeyListener{
private static final long serialVersionUID = 1L;
Enemy enemy = new Enemy();
Player player = new Player();
public GameClass(){
Timer time = new Timer(15, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
player.openImage();
}
public void update(){
player.update();
enemy.update();
}
public void paintComponent(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0,0,Main.WW,Main.WH);
player.paint(g);
enemy.paint(g);
g.dispose();
}
public void actionPerformed(ActionEvent e){
update();
repaint();
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT){
player.setSpeed(-5);
}
else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
player.setSpeed(5);
}
else if(e.getKeyCode() == KeyEvent.VK_UP){
player.setFly(-5);
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
player.setFly(5);
Player.goDown = true;
}
}
public void keyReleased(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_RIGHT){
player.setSpeed(0);
}
if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN){
player.setFly(0);
Player.goDown = false;
}
}
public void keyTyped(KeyEvent e){
}
}
Enemy class:
import java.awt.*;
public class Enemy {
private int x = -100;
private int y = -100;
Player player = new Player();
public void update(){
System.out.println(player.getX());
if(player.getX() < this.x){
this.x -= 5;
}
if(player.getX() > this.x){
this.x += 5;
}
if(player.getY() > this.y){
this.y += 5;
}
if(player.getY() < this.y){
this.y -= 5;
}
}
public void paint(Graphics g){
g.setColor(Color.ORANGE);
g.fillRect(x, y, 50, 50);
}
}
Player class:
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.awt.*;
public class Player {
private Image image;
private int player_x = Main.WW/2;
private int player_xspeed = 0;
private int player_y = Main.WH/2;
private int player_yspeed = 0;
private int flamey = player_y + 100;
private int flamex;
private int newx;
private int newy;
static boolean goDown = false;
public Player(){
newx = player_x;
newy = player_x;
}
public void openImage(){
try {
image = ImageIO.read(new File("spaceship.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void paint(Graphics g){
flamex = player_x + 20;
g.drawImage(image,player_x,player_y,null);
g.setColor(Color.YELLOW);
g.fillRect(flamex, flamey+5, 6, 6);
g.fillRect(flamex+10, flamey, 6, 6);
g.fillRect(flamex+10, flamey+15, 6, 6);
g.fillRect(flamex+20, flamey+5, 6, 6);
}
public void update(){
player_x += player_xspeed;
player_y += player_yspeed;
if(flamey < (player_y + 125)){
if(goDown == false)
flamey += 5;
else
flamey += 10;
}else
flamey = player_y + 100;
newx = player_x;
newy = player_y;
}
public void setSpeed(int speed){
player_xspeed = speed;
}
public void setFly(int speed){
player_yspeed = speed;
}
public int getX(){
return newx;
}
public int getY(){
return newy;
}
}
Sorry for bad English, please help me.
Any help appreaciated :)
It's because the Player it follows is created inside Enemy via the line:
public class Enemy {
//...
Player player = new Player();
//...
}
so it's a different player instance to the one you are controlling, which is created in GameClass via:
public class GameClass extends JPanel implements ActionListener, KeyListener{
Enemy enemy = new Enemy();
Player player = new Player();
//...
}
You need to inject the controlled player instance either as a constructor parameter on Enemy, e.g.
public class GameClass extends JPanel implements ActionListener, KeyListener{
Player player = new Player();
Enemy enemy = new Enemy(player);
//...
}
public class Enemy {
//...
Player player;
public Enemy(Player player) { this.player = player; }
//...
}
or via a setter.