Why the character in my 2D game is not moving? - java

My program has 3 java files, namely Frame, Dude(which contains the character) and Board(which implements the actionListener). My program is not throwing any error and the images(background and character) are rendering good. But the character is not moving forward.
import javax.swing.*;
public class Frame {
public static void main(String[] args){
JFrame frame= new JFrame("2D Game");
frame.add(new Board());
frame.setVisible(true);
frame.setSize(1200, 600);
}
}
import java.awt.*;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Dude {
int x, dx, y;
Image still;
public Dude(){
ImageIcon i = new ImageIcon("/home/amitabh/Pictures/man1.jpg");
still= i.getImage();
x=10;
y=172;
}
public void move(){
x=x+dx;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public Image getImage(){
return still;
}
public void keyPressed(KeyEvent e){
int key= e.getKeyCode();
if(key== KeyEvent.VK_LEFT);
dx= -1;
if(key== KeyEvent.VK_RIGHT);
dx= 1;
}
public void keyReleased(KeyEvent e){
int key= e.getKeyCode();
if(key==KeyEvent.VK_LEFT);
dx=0;
if(key==KeyEvent.VK_RIGHT);
dx=0;
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Board extends JPanel implements ActionListener{
Image img;
Timer time;
Dude p;
public Board(){
p= new Dude();
addKeyListener(new AL());
setFocusable(true);
ImageIcon i= new ImageIcon("/home/amitabh/Pictures/game1.png");
img= i.getImage();
time= new Timer(5,this);
time.start();
}
#Override
public void actionPerformed(ActionEvent e) {
p.move();
repaint();
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d= (Graphics2D)g;
g2d.drawImage(img, 0,0, null);
g2d.drawImage(p.getImage(), p.getX(), p.getY(), null);
}
public class AL extends KeyAdapter{
public void keyReleased(KeyEvent e){
p.keyReleased(e);
}
public void KeyPressed(KeyEvent e){
p.keyPressed(e);
}
}
}

Start by talking a very close look at:
if (key == KeyEvent.VK_LEFT);
Does that look funny to you?
if (key == KeyEvent.VK_LEFT); // <--- What's the ; doing here?
Change it to be more like...
if (key == KeyEvent.VK_LEFT) {
dx = 0;
}
And, yes, this is why you're encouraged to use { ... }
Next, take a closer look at...
public void KeyPressed(KeyEvent e) {
See anything wrong there? Why does it start with an uppercase K, that's not the correct method signature
Change to something more like...
#Override
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
Yes, this is why you're encouraged to use #Override ;)
And finally change your paint method to paintComponent
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
You are encouraged to override paintComponent when performing custom painting, it tends to cause less issues
I'd also encorage you to have a look at the Key Bindings API and favour it over KeyListener as it provides better control of the focus level required to trigger the key events
I'd also encourage your to override getPreferredSize of the Board and return your preferred size from there, rather then setting the frame's size. The frame size includes the frame's decorations, so you content is smaller then the frame size

Related

Problems with repaint()

Im having some trouble using repaint.The code is supposed to draw a line behind your cursor.
package javaapplication6;
import java.awt.*;
import javax.swing.JFrame;
import java.awt.event.*;
class Test extends Canvas implements MouseListener, MouseMotionListener {
int x[]=new int[1024];
int y[]=new int[1024];
int size=0;
public void MouseDemo(){
addMouseListener(this);
addMouseMotionListener(this);
}
public void paint (Graphics g){
g.setColor(Color.red);
for (int i=1;i<size;i++) g.drawLine(x[i],y[i],x[i-1],y[i-1]);
}
public void mousePressed(MouseEvent e){
x[size]=e.getX();
y[size]=e.getY();
size++;
}
public void mouseDragged(MouseEvent e){
y[size]=e.getY();
x[size]=e.getX();
size++;
repaint();
}
public void mouseEntered(MouseEvent e){
size=0;
y[size]=e.getY();
x[size]=e.getX();
repaint();
}
public void mouseExited (MouseEvent e){
size=0;
repaint();
}
public void mouseReleased (MouseEvent e){}
public void mouseClicked (MouseEvent e){
}
public void mouseMoved (MouseEvent e){}
}
public class JavaApplication6 {
public static void main(String[] args) {
JFrame win= new JFrame ("Target");
win.setSize(600,500);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.add(new Test());
win.setVisible(true);
}}
This same code worked at the school computer but when I got home and tried to do another example and it didn't really work so I decided to test this one and it doesn't work either.I would really appreciate some help and an explanation as to why repaint doesn't trigger.
Your primary problem is here...
public void MouseDemo() {
addMouseListener(this);
addMouseMotionListener(this);
}
This is a method, not a constructor, so it will never register your listeners. Instead, change it to...
public MouseDemo() {
addMouseListener(this);
addMouseMotionListener(this);
}
Or, based on you actually example code...
public Test() {
addMouseListener(this);
addMouseMotionListener(this);
}
java.awt.Canvas is a heavy weight component, AWT components don't always play nice with Swing, as they have no concept of z-ordering in the way that Swing implements it.
You'd be better off starting with a JPanel.
By convention, you should then override the paintComponent method and perform your custom painting within it, remembering to call super.paintComponent first
Because frame borders are inserted into the visible area of the frame, you "useable" area will be less then that specified by setSize, instead, you should override the getPreferredSize method of the JPanel and specify the "usable" area you prefer. From there, you can pack the frame around it.
To avoid any possible issues with threads, you should use EventQueue.invokeLater to start you UI in
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test extends JPanel implements MouseListener, MouseMotionListener {
int x[] = new int[1024];
int y[] = new int[1024];
int size = 0;
public Test() {
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
for (int i = 1; i < size; i++) {
g.drawLine(x[i], y[i], x[i - 1], y[i - 1]);
}
}
#Override
public void mousePressed(MouseEvent e) {
x[size] = e.getX();
y[size] = e.getY();
size++;
}
public void mouseDragged(MouseEvent e) {
y[size] = e.getY();
x[size] = e.getX();
size++;
repaint();
}
public void mouseEntered(MouseEvent e) {
System.out.println("Entered");
size = 0;
y[size] = e.getY();
x[size] = e.getX();
repaint();
}
public void mouseExited(MouseEvent e) {
size = 0;
repaint();
}
public void mouseReleased(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Test());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

I cannot draw objects and have them move on the screen

I can draw static things to the screen, but I want to make them move with user key input. I don't know what to do, I've been searching and searching and haven't come up with an answer yet. Please help!
package com.Game.game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JFrame
{
final static int width = 500;
final static int height = 500;
public int x = 250;
public int y = 250;
public int changeX = 10;
public int changeY = 10;
public static void main(String[] args)
{
new Game();
}
public Game()
{
KeyListener listener = new KeyListening();
addKeyListener(listener);
setFocusable(true);
DrawingStuff drawingstuff = new DrawingStuff();
add(drawingstuff);
setSize(width, height);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public class DrawingStuff extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString("Hey there!", 300, 300);
g.setColor(Color.RED);
g.fillRect(x, y, 50, 50);
}
}
public class KeyListening implements KeyListener
{
DrawingStuff drawingstuff = new DrawingStuff();
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP)
{
y = y + changeY;
System.out.println("Hey");
drawingstuff.repaint();
}
}
#Override
public void keyReleased(KeyEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
}
public void update()
{
}
}
EDIT: Fixed it. I took away the key listener stuff in the constructor method, added a command to focus on "drawingstuff" in the constructor method, and, most importantly, added this bit of code to the end of the constructor method:
while(true)
{
drawingstuff.repaint();
}
The problem is that your KeyListening object has a reference to a different DrawingStuff object than the one you added to your UI inside the Game constructor.
public class KeyListening implements KeyListener
{
DrawingStuff drawingstuff = new DrawingStuff();
...
You should pass a DrawingStuff reference to the KeyListening instance so that it can tell the right object to repaint itself.

The most efficient way to draw a lot of circles java

Ok so I have looked around and I didn't find anything that helped me with this so I thought I would go ahead and ask here. I want to have a bunch of circles that collide bounce and generally interact with each other. The problem I am running into is that drawing a lot of circles eats away at the frame rate. So given an array of circles which I have to draw, all of them. Is the only way to draw them simply to draw them all using g.fillOval() in the paintComponent?
For example, in the paint component, I call a function drawBalls(Graphics2D g) that draws all the balls it contains. (that's how I draw stuff by passing it through to the object that draws I don't know if there is a better way)
for(Ball ball:balls){
ball.drawYourself(g) //g is the Graphics2D
}
Thanks
Edit. Sorry if it was a bad question here is the code of my program. I hope it isn't too long.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import java.util.*;
import javax.swing.Timer;
//###################################################\\
public class Game extends JFrame implements ActionListener{
private Timer myTimer;
private GamePanel panel;
public Game() {
super("Things.py");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1000,800);
panel = new GamePanel(this);
add(panel);
myTimer = new Timer(1, this);
myTimer.start();
setResizable(false);
setVisible(true);
}
public void actionPerformed(ActionEvent evt){
panel.repaint();
}
public static void main(String[] arguments) {
Game frame = new Game();
}
}
//###################################################\\
//###################################################\\
class GamePanel extends JPanel implements MouseMotionListener, MouseListener,KeyListener{
// ------------ Variables ----------------------------------------------
private int mx,my;//Mouse position x and y
private boolean[]keys;//If the keys are pressed
private Boolean mousepressed=false;//If the mouse is pressed down
private Game mainframe;//The panel that created this GamePanel
private Color backmenuc;
private Color backcolor;
private bounceBalls bballs;
private bounceBalls bballs2;
// ------------ Constructor --------------------------------------------
public GamePanel(Game m){
//----- Listeners -----
addMouseMotionListener(this);//LISTEN TO ME!!!
addMouseListener(this);//Listen to me!
addKeyListener(this);//listen to me pls
//----- Variables -----
mainframe=m;
keys=new boolean[KeyEvent.KEY_LAST+1];//creates the array for keys
backcolor=new Color(0,0,0);
backmenuc=new Color(255,255,255);
bballs=new bounceBalls(this);
bballs2=new bounceBalls(this);
//----- Load Images -----
//----- End -----
}
// ------------ Drawing ------------------------------------------------
public void paintComponent(Graphics gg){
Graphics2D g=(Graphics2D) gg;
paint.drawRect(g,0,0,getWidth(),getHeight(),backcolor);
if (mousepressed){
bballs.addBall(mx,my,10);
bballs2.addBall(mx+100,my,10);
}
bBallThreading b1=new bBallThreading(g,bballs,"B1");
b1.start();
bBallThreading b2=new bBallThreading(g,bballs2,"B1");
b2.start();
//bballs.update();
//bballs2.update();
bballs.draw(g);
bballs2.draw(g);
System.out.println(bballs.size());
}
// ------------ Misc ---------------------------------------------------
public void addNotify() {
super.addNotify();
}
// ------------ MouseListener ------------------------------------------
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {
mousepressed=false;
}
public void mouseClicked(MouseEvent e){
}
public void mousePressed(MouseEvent e){
mousepressed=true;
}
// ---------- MouseMotionListener --------------------------------------
public void mouseDragged(MouseEvent e){
mx=e.getX();
my=e.getY();
}
public void mouseMoved(MouseEvent e){
mx=e.getX();
my=e.getY();
}
// ---------- KeyListener -----------------------------------------------
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
}
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
}
}
//###################################################\\
class bounceBall{
private double bx,by;
private int br;
private double vx,vy;
public bounceBall(int x,int y,int radius){
bx=(double)x;
by=(double)y;
br=radius;
vx=0;
vy=0;
}
public void move(){
if((by+vy)>800){
vy*=-.9;
}
bx+=vx;
by+=vy;
}
public void addV(double x, double y){
vx+=x;
vy+=y;
}
public void draw(Graphics2D g){
g.setColor(new Color(255,0,0));
g.fillOval((int)bx-br,(int)by-br,br*2,br*2);
}
}
class bounceBalls{
GamePanel gp;
ArrayList<bounceBall> balls;
double gravity;
public bounceBalls(GamePanel gamep){
gp=gamep;
gravity=.1;
balls=new ArrayList<bounceBall>();
}
public void draw(Graphics2D g){
//paint.setAA(g,true);
paint.setAlpha(g,.1f);
for(bounceBall ball:balls.toArray(new bounceBall[balls.size()])){
ball.draw(g);
}
paint.setAlpha(g,1f);
//paint.setAA(g,false);
}
public void setGravity(double g){
gravity=g;
}
public void update(){
for(bounceBall ball:balls.toArray(new bounceBall[balls.size()])){
ball.addV(0,gravity);
ball.move();
}
}
public void addBall(int x, int y, int radius){
balls.add(new bounceBall(x,y,radius));
}
public int size(){
return balls.size();
}
}
class bBallThreading implements Runnable{
private Thread t;
private String threadname;
Graphics2D g;
private bounceBalls bballs;
public bBallThreading(Graphics2D g, bounceBalls bballs,String s){
this.g=g;
this.bballs=bballs;
threadname=s;
}
public void run(){
bballs.update();
}
public void start(){
if (t == null)
{
t = new Thread (this, threadname);
t.start ();
}
}
}
//###################################################\\
When I run this I get 4000 circles at 30 fps
bBallThreading b1=new bBallThreading(g,bballs,"B1");
b1.start();
bBallThreading b2=new bBallThreading(g,bballs2,"B1");
b2.start();
The paintComponent() method is for painting. That is all is should do.
You should NOT be starting a Thread in a painting method. Every time Swing paints the component you will be starting two more Threads.
Add a System.out.println(...) statement to that method to see how many times that method is executed.
You should start the Thread when you start the animation.

How to create a moving object(Dot) on my Jframe (Netbeans)?

Hi guys thanks for your answers ahead of time. I am wondering how i would go about creating a dot and making that dot move across my jFrame. This Dot would only be able to move on a picture of a grid in my jFrame upon keystroke. If anyone can post some code (as example for me to refer to) as to how to create the "dot/point" and how to make this dot move across my jFrame on keystroke i would greatly appreciate it. thanks :)
Once you have a JFrame, you need to add a JPanel to it and put your rendering code in the repaint() method of the JPanel.
I would suggest you look at this example of how to use a JFrame properly.
public class MyJFrame extends JFrame implements KeyListener {
private MyJPanel frame;
public MyJFrame() {
super();
frame = new MyJPanel();
add(frame);
pack();
addKeyListener(this);
repaint();
}
public static void main(String[] args) {
MyJFrame window = new MyJFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setTitle("Test");
}
#Override
public void repaint() {
super.repaint();
}
#Override
public void keyPressed(KeyEvent e) {
frame.keyPressed(e);
repaint();
}
#Override
public void keyTyped(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) { }
}
Here is the MyJPanel class:
public class MyJPanel extends JPanel {
private int x = 0;
private int y = 0;
public MyJPanel() {
setPreferredSize(new Dimension(200,200));
}
#Override
public void update(Graphics g) {
paint(g);
}
#Override
public void paint(Graphics g) {
g.setColor(Color.red);
g.drawRect(x,y,1,1);
}
public void keyPressed(KeyEvent e) {
int k = e.getKeyCode();
switch (k) {
case KeyEvent.VK_D:
x++;
break;
case KeyEvent.VK_A:
x--;
break;
case KeyEvent.VK_W:
y--;
break;
case KeyEvent.VK_S:
y++;
break;
}
}
}
Using KeyListener is optional but allows you to get keyboard input.
I know that this is long and not very direct, but I hope you can learn something from this code. If you have any other questions, feel free to comment, and I'll help you out as best I can.
MyJFrame needs to import:
java.awt.event.KeyEvent;
java.awt.event.KeyListener;
javax.swing.JFrame;
MyJPanel needs to import:
java.awt.Color;
java.awt.Dimension;
java.awt.Graphics;
java.awt.event.KeyEvent;
javax.swing.JPanel;

Painting Ellipses in Java

I have a java program which displays an ellipse on the screen and changes its direction through the use of the arrow keys. I constantly call repaint() on the ellipse using a while loop.
The ellipse moves, but the problem is that it leaves a trail of ellipses on its path. How do I make it so that it removes the old ellipses and then repaint the new one?
Code:
public void run(){
while (animator != null)
{
setBackground(Color.GREEN);
repaint();
// The direction works and the rest works fine.
player1.move(player1, player1.direction);
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
break;
}
}
}
// The paintComponent of my player1 is fine.
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g;
player1.paintComponent(g2, player1);
}
The problem is likely that your paintComponent(Graphics) overriden method is not calling super.paintComponent(g), which clears the canvas, among other things:
// Bad:
#Override
public void paintComponent(Graphics g) {
// paint the ellipse, etc.
}
// Good:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// paint the ellipse, etc.
}
Here is some basic code which does the very basics (without the use of a continuous while loop):
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class Ellipses extends JFrame {
public static void main(String[] args){
//Ensures application is not run on the main thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Ellipses myEllipses = new Ellipses();
myEllipses.init();
}
});
}
public Ellipses(){
//Set up the frame
this.setTitle("Ellipses Example");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setSize(400, 400);
}
private Ellipse ellipse1;
public void init(){
Container contentPane = this.getContentPane();
//Create a new ellipse and add to the content pane
ellipse1 = new Ellipse();
contentPane.add(ellipse1);
//Add the keyListener to the contentPane
contentPane.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
ellipse1.decreaseY();
}
if(e.getKeyCode() == KeyEvent.VK_DOWN){
ellipse1.increaseY();
}
if(e.getKeyCode() == KeyEvent.VK_LEFT){
ellipse1.decreaseX();
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
ellipse1.increaseX();
}
//Repaint the ellipse
ellipse1.repaint();
}
});
//Request the focus so key presses can be detected
contentPane.setFocusable(true);
contentPane.requestFocus();
}
//Create an ellipse which can be drawn to the screen
public class Ellipse extends JComponent{
private int x , y; //Coordinates of the oval
public Ellipse(){
setCoordinates(100, 100);
}
public void setCoordinates(int x, int y){
this.x = x;
this.y = y;
}
public void increaseY(){
y+=10;
}
public void increaseX(){
x+=10;
}
public void decreaseY(){
y-=10;
}
public void decreaseX(){
x-=10;
}
public void paint(Graphics g){
//Ensures previous paint is cleared
super.paintComponents(g);
g.setColor(Color.RED);
g.fillOval(x, y, 100, 100);
}
}
}
You should draw the background Color before drawing the ellipse in the game loop :)
Also you can call repaint() , it actually calls update() to do
the dirty work of clearing the screen and calling paint().
When you use repaint the update method inherit
public void update(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
g.setColor(getForeground());
paint(g)
}
so the background return to it's original color and the trail of ellipses will be removed

Categories