motion of rectangle by keyboard - java

I made the following code to move a rectangle using arrowkeys of keyboard. The "keyPressed" function does not seem to be working properly.Infact, i don't think it is even getting called when a key is pressed bcz when i tried to print some text when a key is pressed, it was not getting printed.All i see in the output window is a stationary rectangle fixed at the top left corner of the window.Here is my code....pls help me...i need it desperately
import javax.swing.JFrame;
public class Main
{
public static void main(String args[])
{
JFrame window=new JFrame();
window.setSize(600,400);
window.setTitle("window");
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingComponent DC=new drawingComponent();
window.add(DC);
}
}
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.Timer;
public class drawingComponent extends JComponent implements ActionListener,KeyListener
{
Timer t=new Timer(2000,this);//moving after 5 milliseconds
static int x=0;
static int y=0;
private static int velx=0;
private static int vely=0;
public drawingComponent()
{
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
System.out.println("tr1");
}
public void paintComponent(Graphics g)
{
Graphics2D g2=(Graphics2D) g;
Rectangle rect1=new Rectangle(x,y,50,30);
g2.setColor(Color.RED);
g2.fill(rect1);
System.out.println("tr2");
}
public void actionPerformed(ActionEvent e) //inbuilt fncn f actionListener(interface) which needs to be created
{
x+=velx; //changing values
y+=vely;
System.out.println("tr3");
repaint(); //inbuilt fncn to repeat the paintComponent method
}
public void keyPressed(KeyEvent e)
{
int code=e.getKeyCode();
if(code==KeyEvent.VK_UP)
{ velx=0; vely=-1;repaint(); }
if(code==KeyEvent.VK_DOWN)
{ velx=0; vely=1; repaint(); }
if(code==KeyEvent.VK_LEFT)
{vely=0; velx=-1; repaint(); }
if(code==KeyEvent.VK_RIGHT)
{vely=0; velx=1; repaint();}
}
public void keyTyped(KeyEvent e)
{}
public void keyReleased(KeyEvent e)
{}
}

Welcome to the wonderful world of KeyListeners...
While you have set the component focusable, you've not requested that the component be focused.
You could try calling requestFocusInWindow, but he this raises the question of when to call it.
You could call it within the constructor, but because the component doesn't belong to a valid visible component yet, the call may fail. You could override the components addNotify method and add the call to it, after you call super.addNotify, but the requestFocusInWindow method doesn't gurentee that focus will be given the component
Instead, you could simply avoid all this hassle and use the key bindings API instead, which will give you control over the level of focus require for key events to be triggered
As a side note, you should call setVisible on your frame after you've set up the UI completely

Related

Java game: shooting bullets in a simple game

I'm kind of new to java.im trying to write a simple game which it has a player and enemies and when you press some keys like "space", the player most shoot a bullet in right direction but i don't know how to render bullet in game. Actually it doesn't appear and doesn't move in Game.
Shooting system
package com.company;
import javax.swing.*;
import java.awt.*;
public class Bullet {
GamePanel panel;//Game panel
Rectangle hitBox;//Bullet
public int x,y,width,height;
boolean Shoot;
public Bullet(int x , int y ,GamePanel panel)
{
this.panel = panel;
this.x=x;
this.y=y;
height=15;
width=15;
hitBox = new Rectangle(x,y,width,height);
}
public void set()
{
if(Shoot) // where I have problem which Bullet doesn't move or doesn't appear
move();
}
public void move()
{
x=x+10;
}
public void draw(Graphics2D gtd)
{
gtd.setColor(Color.RED);
gtd.fillRect(x,y,width,height);
}
}
Game Panel which sets Game Objects
package com.company;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
public class GamePanel extends JPanel implements ActionListener {
Player player;
Timer gameTimer;
Bullet bullet;
public GamePanel(){
player = new Player(400,300,this);
bullet = new Bullet(player.x, player.y, this);
gameTimer = new Timer();
gameTimer.schedule(new TimerTask() {
#Override
public void run() {
player.set();
bullet.move();
repaint();
}
},100,15);
}
public void paint(Graphics g){
super.paint(g);
Graphics2D gtd = (Graphics2D) g;
player.draw(gtd);
bullet.draw(gtd);
}
void keyPressed(KeyEvent e)
{
if(e.getKeyChar()=='w')
player.keyUp=true;
if(e.getKeyChar()=='a')
player.keyLeft=true;
if(e.getKeyChar()=='s')
player.keyDown=true;
if(e.getKeyChar()=='d')
player.keyRight=true;
if(e.getKeyChar()=='t')
bullet.Shoot=true;
}
void keyReleased(KeyEvent e)
{
if(e.getKeyChar()=='w')
player.keyUp=false;
if(e.getKeyChar()=='a')
player.keyLeft=false;
if(e.getKeyChar()=='s')
player.keyDown=false;
if(e.getKeyChar()=='d')
player.keyRight=false;
if(e.getKeyChar()=='t')
bullet.Shoot=false;
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
I think the problem is that you're calling bullet.move(); continuously in the Timer in your GamePanel class. Apart from that I'm not entirely sure how you're fetching keyboard input. Your GamePanel class contains the methods a KeyListener usually would utilize, but the class does not implement a KeyListener, but an ActionListener, which isn't being used in your code.
So what you should be doing is:
Verify that your keyPressed and keyReleased functions are actually being called when a keyboard button is pressed, and if they aren't, you should implement a KeyListener instead of an ActionListener in the GamePanel class
Make sure that bullet.move(); is only being called when it should be, as it's currently being called on every iteration of your timer

Relation and implementation of Graphics and paint? [duplicate]

I tried few source codes of drawing in java and they were working fine, but when i tried to make one of my own I could not get the paint(Grahpics g) method to work! I looked again at the codes I have and checked some of the tutorials in Oracle's pages but i don't seem to be able to know why it would not work.
can someone please check it and tell me what is wrong here??
main method:
public class main
{
public static void main(String[] args)
{
new board();
}
}
board:
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class board implements ActionListener
{
private JFrame f = new JFrame("Speedy");
private JPanel gamePanel = new JPanel();
private Image bg = new ImageIcon(this.getClass().getResource("road.png")).getImage();
private Timer t;
private car myCar = new car();
public board()
{
t = new Timer(50,this);
t.start();
gamePanel.setSize(600,400);
gamePanel.setDoubleBuffered(true);
gamePanel.setFocusable(true);
gamePanel.addKeyListener(new TAdapter());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(gamePanel,BorderLayout.CENTER);
//f.addKeyListener(new TAdapter());
f.setBounds(200,100,600,400);
f.setVisible(true);
f.revalidate();
f.repaint();
}
public void paint(Graphics g) {
gamePanel.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(bg,0,0,null);
g2d.drawImage(myCar.getImg(), myCar.xPos, myCar.yPos, null);
System.out.println("Painted");
g.dispose();
}
public void actionPerformed(ActionEvent e)
{
gamePanel.repaint();
//System.out.println("Painting..");
}
private class TAdapter extends KeyAdapter {
public void keyReleased(KeyEvent e) {}
public void keyPressed(KeyEvent e)
{
myCar.keyPressed(e);
System.out.println("You pressed: "+e);
}
}
}
car.java:
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.ImageIcon
;
public class car
{
private Image image;
public int xPos,yPos;
public car()
{
image = new ImageIcon(this.getClass().getResource("car.png")).getImage();
xPos = 300;
yPos = 200;
System.out.println(image.getWidth(null));
}
public Image getImg() {return image;}
public void move() {}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) xPos -= 1;
if (key == KeyEvent.VK_RIGHT)xPos += 1;
if (key == KeyEvent.VK_UP) yPos -= 1;
if (key == KeyEvent.VK_DOWN) yPos += 1;
}
}
There are no errors, it shows me the width of the image which is right, also the timer triggers the ActionListener, also KeyListener is working, but the images would not draw! the paint(Graphics g) method just does not want to get triggered!
Googling it did not help.. I thought this would be a common problem but nobody has the problem I have, all solutions failed me.
help please?
If someone can explain it would be most appreciated!
Your class Board does not extend the JPanel class. So the paint() method is never called by the Swing.
Also, the statement gamePanel.repaint() will only execute the default JPanel paint() method of gamePanel. Instead you want the overridden paint method to be executed, so might want to do this:
public class Board extends JPanel implements ActionListener {
....
public void paint(Graphics g) {
this.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(bg,0,0,null);
g2d.drawImage(myCar.getImg(), myCar.xPos, myCar.yPos, null);
System.out.println("Painted");
g2d.dispose();
}
....
}
Replace your action functionality with this:
public void actionPerformed(ActionEvent e) {
this.repaint();
}
Alternative solution:
If you do not want your Board class to extend JPanel, you can also override the paint() method of the gamePanel as you initialize it.
gamePanel = new JPanel() {
#Override
public void paint(Graphics g) {
this.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(bg,0,0,null);
g2d.drawImage(myCar.getImg(), myCar.xPos, myCar.yPos, null);
g2d.dispose();
}
};
However, I would recommend the first solution rather than this one with anonymous classes.
When you call repaint on some container, then what happens is that Swing looks at all the components in that container and calls their paint method.
However, your board class (you should be calling it Board, by the way. Class names should always start with a capital) is not a component of your JFrame. When you call repaint, Swing will attempt to call the paint method of the JPanel that is a component of that JFrame. But you didn't override that method. You just added a paint method to your board, and board is not a component of the JFrame.
For this reason, usually you are supposed to create a class that extnds JPanel or some other component, and then add the current object of that class as a component to the JFrame. This way, your paint method will be called when the JFrame is repainted.
Your "main" class (board) should extend JPanel to work as expected.
With your way, paint would never be called. it acts like any normal self-written function.
If you want to keep things as they are, you can do something ike that:
gamePanel = new JPanel()
{
#Override
public void paint(Graphics g)
{
//your code here
}
};
Please keep in mind that a Class name should start with a capital letter. It won't make any errors but it is a naming convention as you can see here:
http://www.oracle.com/technetwork/java/codeconventions-135099.html

How do I make a (keyPressed) KeyListener?

Im trying to write a very simple program that allows you to control a sprite with arrow keys and move around the screen. From what I understand, to do this I need a keyPressed() KeyListener. I believe Im doing this correctly based on the Java Doc but its not returning the correct output when I press the designated key. Can someone please tell me what is wrong with my code, and if possible, provide a simple example of the usage of this class? Thanks!
(Note, code is unfinished)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Display extends JPanel implements ActionListener, KeyListener {
Display() {
// super();
loadImages();
initTimer();
this.addKeyListener(this);
}
BufferedImage sprite;
Timer timer;
int up = 0;
public void loadImages() {
File spriteImage = new File("Pacman_sprite.png");
try {
sprite = ImageIO.read(spriteImage);
} catch (IOException e) {
System.out.println("Sprite import failed");
}
}
public void initTimer() {
timer = new Timer(100, this);
timer.start();
this.addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
System.out.println("Key press registered"); //does not print this?
if (key == KeyEvent.VK_UP) {
System.out.println("sucess"); // does not print this?
up++;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("release");
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(sprite, 500, 500 + up, null);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
repaint();
}
}
EDIT:
May have found the answer here. I moved the key handling code to a new class called KeyHandler then added these two lines to the constructor:
addKeyListener(new KeyHandler());
setFocusable(true);
It now appears to be working just fine (sort of, at least it is detecting when the up key is hit. My graphics aren't.)
You are not adding the listener to the JPanel.
Note: I would suggest you to change your design. Right now, Display class is both a JPanel and a Listener (which doesn't make sense in my opinion).
But to add the listener in your code do something like,
this.addKeyListener(this); // This looks awkward right. That's why you should change the design.
in your constructor.

Java: Repaint in Swing Not Working

I am learning java swing and am having trouble with the following program. It creates a small frame with a quit button at top. The objective is to display coordinates wherever the mouse is clicked. When I click the mouse 2 unwanted things are happening:
the quit button is overridden by the mouse clicks and it no longer responds (instead of responding to event and quitting, it displays coordinates on top of the quit button).
when I click at a new location, the coordinates from the old location persist.
I used removeAll() and revalidate() before doing repaint() based on this discussion but that has not helped. This code is taken from here and the code to says to research online documentation for why this is happening.
Any pointers?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
public class QuitCoordinateTest {
public static void main(String[] args){
GUI gui = new GUI();
}
}
class MyFrame extends JFrame implements ActionListener{
int clickX;
int clickY;
public void paint(Graphics g){
g.drawString("" + clickX + ", " + clickY, clickX, clickY);
}
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
//=======================================================//
class GUI extends MyFrame {
JButton quitButton = new JButton("Quit");
public GUI(){
MyFrame displayWindow = new MyFrame();
displayWindow.setTitle("Title");
/*
JPanel buttonPanel = new JPanel();
buttonPanel.add(quitButton);
displayWindow.getContentPane().add(buttonPanel,BorderLayout.NORTH);
JPanel textPanel = new JPanel();
*/
displayWindow.getContentPane().add(quitButton,BorderLayout.NORTH);
quitButton.addActionListener(displayWindow);
displayWindow.setSize(201,201);
displayWindow.setVisible(true);
// displayWindow.pack();
displayWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
displayWindow.addMouseListener(new MouseProc(displayWindow));
}//end constructor
}//end class GUI definition
//=======================================================//
//This listener class monitors for mouse presses and
// displays the coordinates of the mouse pointer when the
// mouse is pressed on the source object.
class MouseProc extends MouseAdapter{
MyFrame refToWin;
MouseProc(MyFrame inWin){
refToWin = inWin;
}
//Override the mousePressed method to determine and
// display the coordinates when the mouse is pressed.
public void mousePressed(MouseEvent e){
refToWin.removeAll();
refToWin.clickX = e.getX();
refToWin.clickY = e.getY();
//Force the JFrame object to be repainted in order to
// display the coordinate information.
refToWin.removeAll();
refToWin.validate();
refToWin.repaint();
}
}
repaint() is working fine.
Avoid drawing directly on the JFrame.
Instead draw in the protected void paintComponent(Graphics g) method override of a JPanel that is then displayed in your JFrame.
Be sure to call the super's paintComponent(g) method inside of your paintComponent override -- this will erase the old images and is the reason for one of your problems.
Use reasonable comments in your code. Too many comments and too much text distracts and makes understanding your code harder, not easier.
Calling removeAll() on your JFrame will do just that -- remove all components including your button. Why are you calling this? Are you sure that you want to call this method?
A minor nitpick -- you'll want to avoid directly setting the fields of another class, such as your clickX and clickY fields. Instead, make them private, and only allow outside classes to modify them through public methods. While it may not matter much for this small program, it will matter greatly when you start scaling up your programming and create large programs with complex interactions. The key to success here will be to limit and control all communication between classes to avoid hard to detect side effects.
For example, something like...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
String str = String.format("[%d, %d]", clickX, clickY);
g.drawString(str, clickX, clickY);
}
public int getClickX() {
return clickX;
}
public void setClickX(int clickX) {
this.clickX = clickX;
}
public int getClickY() {
return clickY;
}
public void setClickY(int clickY) {
this.clickY = clickY;
}
For example
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class DetectClicks extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private int clickX;
private int clickY;
public DetectClicks() {
MyMouseListener mouseAdapter = new MyMouseListener(this);
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter); // to allow dragging!
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
String str = String.format("[%d, %d]", clickX, clickY);
g.drawString(str, clickX, clickY);
}
public int getClickX() {
return clickX;
}
public void setClickX(int clickX) {
this.clickX = clickX;
}
public int getClickY() {
return clickY;
}
public void setClickY(int clickY) {
this.clickY = clickY;
}
private static void createAndShowGui() {
DetectClicks mainPanel = new DetectClicks();
JFrame frame = new JFrame("DetectClicks");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyMouseListener extends MouseAdapter {
private DetectClicks detectClicks;
public MyMouseListener(DetectClicks detectClicks) {
this.detectClicks = detectClicks;
}
#Override
public void mousePressed(MouseEvent evt) {
showPoint(evt);
}
#Override
public void mouseDragged(MouseEvent evt) {
showPoint(evt);
}
private void showPoint(MouseEvent evt) {
detectClicks.setClickX(evt.getX());
detectClicks.setClickY(evt.getY());
detectClicks.repaint();
}
}
Your event is getting consumed by the handler that prints the coordinates, you need to redispatch the event so that the button can see it. You can do it like this, inside the coordinate display event handler:
Component c = e.getComponent();
c.getParent().dispatchEvent( e );
Also, I'd be tempted to use the glass pane of the frame, and put a JLabel on it with the co-ordinates rather than messing with the paint method.
you don't have to use any of repaint(),invalidate() etc.
i highly recommend to use
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//TODO udpdate UI compontents, layouts etc.
}
});
this guarantees that UI components update on real time. Because we don't know when the system update UI hierarchy so we can't force it. This allow system to determine by it's self.

Mouse Pointer Problem in Java Swing

I have created the following simple Java Swing program which outputs a 3*3 square in the window every time the user clicks their mouse. The squares remain in the window even if the user clicks more than once. The program compiles and runs just fine, however, when one clicks in the window the square is drawn far below where the mouse pointer is. I've been racking my brain over this one for a while -- what can I change here to get the square to appear exactly with the pointer on each click? Many thanks for any help!
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class ClickCloud extends JComponent {
final ArrayList<Point2D> points = new ArrayList<Point2D>();
public void addPoint(Point2D a) {
points.add(a);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < points.size(); i++) {
Point2D aPoint = points.get(i);
g2.draw(new Rectangle2D.Double(aPoint.getX(), aPoint.getY(), 3, 3));
}
}
public static void main(String[] args) {
final ClickCloud cloud = new ClickCloud();
JFrame aFrame = new JFrame();
class ClickListen implements MouseListener {
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
cloud.addPoint(arg0.getPoint());
cloud.repaint();
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
aFrame.setSize(500, 500);
aFrame.add(cloud);
aFrame.addMouseListener(new ClickListen());
aFrame.setVisible(true);
}
}
You're adding the MouseListener to the JFrame, but displaying the results in the JComponent and relative to the JComponent. So the location of the Point clicked will be relative to the JFrame's coordinates, but then displayed relative to the JComponent's coordinates which will shift things down by the distance of the title bar. Instead simply add the MouseListener to the same component that is responsible for displaying the results so that the display and clicking coordinates match:
aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
aFrame.setSize(500, 500);
aFrame.add(cloud);
//!! aFrame.addMouseListener(new ClickListen()); // !! Removed
cloud.addMouseListener(new ClickListen()); // !! added
aFrame.setVisible(true);
By the way: Thanks for creating and posting a decent SSCCE as this makes it so much easier to analyse and solve your problem.

Categories