Rectangle X axis move issue - java

I was just doing random stuff with GUI and I came to this issue.When I press right arrow key, rectangle really moves on X axis, but distance moved is not constant.It's raising pretty fast and rectangle does after each press bigger moves.In my recent code line X=X+1 seemed to work pretty fine.Here's my code:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Buffer extends JPanel implements KeyListener{
public static JFrame frame;
public int x;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(x,0,20,20);
frame.addKeyListener(this);
}
public static void main(String args[]){
Buffer z=new Buffer();
frame=new JFrame();
frame.setSize(500,500);
frame.setVisible(true);
frame.setFocusable(true);
frame.add(z);
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
x=x+1;
repaint();
}
}
}

Remove the following line from public void paintComponent(Graphics g)
frame.addKeyListener(this);
and add the following line to public static void main(String args[])
frame.addKeyListener(z);
The problem was that after every repaint(); through the keyPressed method, the paintComponent method added a new KeyListener to your frame.
But if you have several KeyListeners, every Listener will invoke the keyPressed method for the same event. So if you have 5 Listeners and you press the right arrow once, the keyPressed method is invoked five times and x is incremented by five.
That meant that the rectangle moved with every hit of the right arrow a bit faster.

Try keyReleased instead of keyPressed. It may be so that while the key is pressed, it keeps invoking the keyPressed event.

Related

Draw circle to the screen

import javax.swing.*;
import java.awt.*;
public class Drag extends JFrame {
Drag(){
setSize(500,400);
setTitle("Drag");
setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.RED);
g.fillOval(0,0,30,30);
}
public static void main(String args[]){
Drag frame1 = new Drag();
}
}
I don't know where did i get wrong, but it just didn't create a circle to the screen for some reason
The JFrame coordinates begin at the top left corner of the window created with the y axis going down. To see your circle at the center of this window try
g.fillOval(this.getWidth()/2,this.getHeight()/2,30,30);
Not 100% sure but by any chance is it because you're instantiating a JFrame outside of the event dispatch thread?
I can't test because I'm on my phone but if you want to you can try replacing mains code with this :
EventQueue.invokeLater(new Runnable () {
public void run () {
new Drag ()
}
});

Resizing only way to repaint JFrame . repaint(); seems to not work

Im currently trying to make my first game and i am having trouble getting the repaint() method to work. I have checked my keyListeners and have confirmed that they are working a ok! The ship that i have created moves but only if i forcibly resize the window by dragging on the sides. If anyone has any tips i would be very greatful!
If you need any more information feel free to ask!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Main extends Canvas implements KeyListener{
public static Ship playerShip = new Ship(150,450,"F5S4-Recovered.png");
public int numberOfEnemies = 0;
public static void createFrame(){
Window frame1 = new Window();
final JPanel pane = new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1000, 1000);
g.drawImage(playerShip.image, playerShip.xPos1, playerShip.yPos1, this);
}
};
frame1.add(pane);
}
public void keyTyped(KeyEvent e){System.out.println("KeyTyped");}
public void keyPressed(KeyEvent e){
switch(e.getKeyCode())
{
case KeyEvent.VK_LEFT :
playerShip.xPos1-=2;
break;
case KeyEvent.VK_RIGHT:
playerShip.xPos1+=2;
break;
}
repaint();
}
public void keyReleased(KeyEvent e){}
public static void main(String args[]){
createFrame();
}
}
Window class ----------------------------------------------------------
import javax.swing.*;
public class Window extends JFrame{
public Window()
{
setTitle("Space Game");
setSize(800,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addKeyListener(new Main());
setVisible(true);
}
}
Your call to repaint() is repainting the class Canvas, but the painting is done on the JPanel pane. The resizing causes an automatic repaint of the panel. So to fix you want to pane.repaint(), but you can't do that unless you put the panel as a class member, so you can access it from the listener method. Right now, it's currently locally scoped in the createFrame() method.
Also, you should probably add the listener to the panel instead, and not even extend Canvas, since you're not even using it
Other Notes:
Look into using Key Bindings instead of low-level KeyListener
Swing apps should be run from the Event Dispatch Thread (EDT). You can do so by simply wrapping the code in your main in a SwingUtilities.invokeLate(..). See more at Initial Threads
Again, I'll just add, Don't extends Canvas

Animated drawing of a successively complex image in Java

I am trying to draw an image on a JPanel that requires thousands of calculations, and I want to animate the progression of the drawing. I.e., instead of doing all 100K iterations of drawing in one go, and then repainting the JPanel, I want to repaint after each iteration, then pause for a fraction of a second, so the user sees the image gradually appearing. However, each refresh of the JPanel erases previous drawings, so my method doesn't work. How can I do this without replicating all (1..N-1) calculations on the Nth iteration?
Consider this example: I want "snow" to gradually appear on the screen. However, this code will only show the 100,000th "snowflake" as all previous ones get erased each time repaint() is called.
import javax.swing.*;
import java.awt.*;
import java.util.Random;
class spanel extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawLine(snow.x, snow.y, snow.x, snow.y);
}
}
class snow extends Thread {
static int x,y;
Random r = new Random();
public void run(){
JFrame sboard = new JFrame();
sboard.setSize(600,600);
sboard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
spanel mypanel = new spanel();
sboard.add(mypanel);
sboard.setVisible(true);
for (int i=0;i<100000;i++){
x=r.nextInt(600);
y=r.nextInt(600);
sboard.repaint();
try {
snow.sleep((long)10);
} catch (InterruptedException e) {};
}
}
}
public class SnowAnim {
public static void main(String[] args) {
(new snow()).start();
}
}
Custom Painting Approaches shows how to draw on a BufferedImage. There are also plenty of other examples in the forum.
Also, when doing animation you should use a Swing Timer to schedule the animation.
How can I do this without replicating all (1..N-1) calculations on the Nth iteration?
Add them to a BufferedImage as seen in this example.
You should probably do your painting on a buffer, then draw the current state of the buffer in paintComponent();
You could also skip the call to super.paintComponent(g);, but then you would have to worry about other elements getting visually "stuck" in your panel.
Thanks all! I figured it out. BufferedImage solves it. For the record, here is my updated code. It also implements camickr's suggestion to use a Swing timer instead of a thread to schedule the animation. I also made some aesthetic changes to make the output look more like snow :-) Thanks again!
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.util.Random;
import java.awt.event.*;
class spanel extends JPanel{
int x,y,rad,i;
static Random r = new Random();
BufferedImage image;
Graphics2D g2d;
Timer timer;
spanel(){
image = new BufferedImage(600, 600, BufferedImage.TYPE_INT_ARGB);
g2d = (Graphics2D)image.getGraphics();
setBackground(Color.black);
g2d.setColor(Color.white);
i=0;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
iterate();
}
};
timer = new Timer(10, listener);
timer.start();
}
public void iterate(){
x=r.nextInt(600);
y=r.nextInt(600);
rad=r.nextInt(5)+5;
g2d.fillOval(x, y, rad, rad);
repaint();
i++;
if (i==1000){timer.stop();}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image,0,0,null);
}
}
public class SnowAnim {
public static void main(String[] args) {
JFrame sboard = new JFrame();
sboard.setSize(600,600);
sboard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
spanel mypanel = new spanel();
sboard.add(mypanel);
sboard.setVisible(true);
}
}

create game loop thread

Hi I have just been messing about polygons and awt. I have created a Jframe and can draw the polygons ok and have one of them move with keypresses.
I'm wondering how to start a gameloop thread(and where to put it!) that will update the jframe independently.
From googling im led to believe that I should have one thread for user input and one for the game itself.
At the moment I have implemented KeyListener on the board class(code shown below),should I put that out into its own class and make it implement runnable?As the code stands I repaint the JFrame in the keypressed() method just so i can see that it moves correctly
Being at it most of the day and I have myself very very confused :)
As always any help much appreciated!
Also while im at it from online tutourials should I use JPanel instead of JFrame and paintComponent() instead of paint()?
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
public class Board extends JFrame implements KeyListener{
AffineTransform identity = new AffineTransform();
Graphics2D g2d;
Ship ship = new Ship();
public static final int ALIENS = 3;
Alien[] alien = new Alien[ALIENS];
Board(){
super("The Board");
setSize(1280,1024);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setBackground(Color.BLACK);
for(int x=0;x<ALIENS;x++){
alien[x]=new Alien();
}
}
public void paint(Graphics g){
super.paint(g);
addKeyListener(this);
//draw ship
g2d = (Graphics2D)g;
g2d.setTransform(identity);
g2d.translate(ship.getxPos(),ship.getyPos());
g2d.scale(2,2);
g2d.setColor(Color.ORANGE);
g2d.fill(ship.getShape());
g2d.setColor(Color.BLACK);
g2d.draw(ship.getShape());
// draw aliens
for(int x=0;x<ALIENS;x++){
//if alien alive
if(alien[x].isAlive()){
//draw alien
g2d = (Graphics2D)g;
g2d.setTransform(identity);
g2d.translate(alien[x].getxPos(),alien[x].getyPos());
g2d.scale(2,2);
g2d.setColor(Color.BLUE);
g2d.fill(alien[x].getShape());
g2d.setColor(Color.BLACK);
g2d.draw(alien[x].getShape());
}
}
}//end paint
/*****************************************************
* key listener events
*****************************************************/
public void keyReleased(KeyEvent k) { }
public void keyTyped(KeyEvent k) { }
public void keyPressed(KeyEvent k) {
int keyCode = k.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_A:
//move ship left
if(ship.getxPos()<20){
ship.setxPos(20);
}else
ship.setxPos(ship.getxPos()-1);
break;
case KeyEvent.VK_D:
if(ship.getxPos()>1260){
ship.setxPos(1260);
}else
ship.setxPos(ship.getxPos()+1);
}
repaint();
}//end keypressed event
public static void main(String[] args){
new Board();
}
}
These answers depend somewhat on what kind of game you're trying to create.
From googling I'm led to believe that I should have one thread for user input and one for the game itself.
You create one main game loop, which runs in its own thread. In psudeocode
while (running) {
update game model
draw game
wait x milliseconds
}
Your user input would update the game model directly. The game loop updates the game model if the computer is required to make moves or react to your moves. Then, the game loop reads the game model and draws the game based on the values in the model.
At the moment I have implemented KeyListener on the board class(code shown below),should I put that out into its own class and make it implement runnable?
Yes, you should put KeyListener into its own class. No, you don't have to make it a separate thread.
To save yourself future trouble, your Swing components should be defined and used on the Event Dispatch thread.
Here's how you do that.
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Board();
}
});
}
Should I use JPanel instead of JFrame and paintComponent() instead of paint()?
Yes.
You should have a JPanel inside of a JFrame. The JPanel is where you perform the draw game psudeocode, using the paintComponent method.
Some people are going to disagree with me, but I've found it best if every object in the game has a draw method to draw itself.
public void draw(Graphics g)
The game model would also have a draw method, which draws all of the objects in the model.
The JPanel paintComponent method would look like this:
public void paintComponent(Graphics g) {
super.paintComponent(g);
gameModel.draw(g);
}

simple intro java game programming

My question is where did i go wrong. it is supposed to make a frame where i can control an oval, move it around back forth left and right, and then make it move with the arrows. but right now i cant even make the oval, or even insert a word into it.
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class JavaGame extends JFrame{
int x, y;
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode ==e.VK_LEFT){
x--;
}
if(keyCode ==e.VK_RIGHT){
x++;
}
if(keyCode ==e.VK_DOWN){
y--;
}
if(keyCode==e.VK_UP){
y++;
}
}
public void keyReleased(KeyEvent e){
}
}
public JavaGame (){
addKeyListener(new AL());
setTitle("Game");
setSize(250,250);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void Paint(Graphics g){
x = 150;
y = 150;
g.fillOval(x, y, 15, 15);
repaint();
}
public static void main(String[] Args){
new JavaGame();
}
}
Probably because Paint isn't a standard Java paint method. I don't see anything resembling an event loop, either--have you considered checking out any Swing tutorials/etc.?
Recommendations:
As Dave says, you need to override the correct method
even so, you shouldn't be drawing directly in a top-level window but rather in a component that derives from JComponent such as JPanel or JComponent itself.
draw in this class's paintComponent(...) method (usually).
Use the #Override annotation to make sure that you are truly overriding a class's method.
Don't use KeyListener's with Swing but rather Key Bindings.
For example, please have a look at my sample code here: How to make an image move while listening to a keypress in Java.

Categories

Resources