So I am working on a project for a class. And I've been struggling with this issue for a while now. The code below is a start screen, and when the enter key is pressed (when atTitle turns to false) I would like it to draw the next image. The problem with that is I can not think of a way for it to draw the next image when it turns to false. I've tried using ifs and whiles. Mainly the problem is that you obviously put another public void paintComponent in an if statement. And I can't carry the Graphics g variable to the KeyPressed method.
I'm stuck.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
AffineTransform at = new AffineTransform();
g2.setTransform(at);
if (atTitle == true) {
g.drawImage(titlescreen, 0, 0, this);
if (start_visible == true) {
g.drawImage(start_symbol, -70, 30, this);
jf.addKeyListener(this);
}
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
//int keyCode = e.getKeyCode();
if (atTitle == true) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
atTitle = false;
System.out.println("It Works.");
}
}
}
you need to call repaint and wait system calls to paint function. you should not keep graphic object and use it in a function is not child function of paint
as a simple canvas component, you can use this one
class Game extends Canvas implements Runnable {
private Thread thread;
public Game(){
thread = new Thread(this);
thread.start();
}
#Override
public void paint(Graphics g) {
// paint your game
}
public void stop(){
thread = null;
}
#Override
public void run() {
while (thread == Thread.currentThread()){
long ti = System.currentTimeMillis();
repaint();
long ti2 = System.currentTimeMillis();
long waitTime = 60 - (ti2-ti);
if (waitTime > 0){
try {
Thread.sleep(waitTime);
} catch (Exception e){
}
}
}
}
}
If you are using JPanel you should:
panel.setFocusable(true);
panel.requestFocusInWindow();
Referenced here
Also you can call panel.revalidate() and/or panel.repaint() in the key press.
Maybe try to stay away from JPanel and Swing altogether (not suited for gaming, but for forms) and just use the graphics2D functionality with a Window, Frame and Canvas, as suggested in previous comment.
Related
I am trying to make Pong. I sent this program to a friend and when he ran it the first time he got my bug but later it ran fine. I always seem to get the bug. My paddle can move up and down. It seems to move correctly and it gets drawn in the right place but it always flickers to the start position and back again. It looks like it gets drawn once at the start position and then at the right positions, flickering between the 2 positions forever.
NetBeans complains about this.addKeyListener(this);. It says "Leaking this in constructor". Here is my code: (sorry in advance, first time posting)
I exported it from netbeans if anyone wants to take a look:
http://s000.tinyupload.com/?file_id=00856291054786890080
public class LeikGluggi extends javax.swing.JPanel implements ActionListener, KeyListener {
Spilari1 spilari1 = new Spilari1();//make paddle
Bolti bolti = new Bolti(); //make ball
public LeikGluggi() {
initComponents();
setSize(Leikbord.GLUGGI_BREIDD,Leikbord.GLUGGI_HAED);
this.addKeyListener(this);
this.setFocusable(true);
int i = 0;
Timer tim = new Timer(50, this);
tim.start();
}
private void uppfaera()//update
{
spilari1.uppfaera();//paddle update
bolti.uppfaera(); // ball update
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);//
g.setColor(Color.WHITE);
g.fillRect(0,0,Leikbord.GLUGGI_BREIDD,Leikbord.GLUGGI_HAED); //background
g.setColor(Color.BLUE);
spilari1.paint(g); //paddle drawn
bolti.paint(g); //ball drawn
}
#Override
public void actionPerformed(ActionEvent e)
{
uppfaera();//update called
repaint();
}
#Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_UP)
{
spilari1.setyHradi(-4);
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN)
{
spilari1.setyHradi(4);
}
}
#Override
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_UP)
{
spilari1.setyHradi(0);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN)
{
spilari1.setyHradi(0);
}
}
public void keyTyped(KeyEvent e)
{
}
And the code for my paddle
package is.hi.vidmotsforritun.pong2.teikning;
import java.awt.Color;
import java.awt.Graphics;
public class Spilari1 {
private final int breidd = 10 ;
private final int lengd = 75;
private int y = (Leikbord.GLUGGI_HAED/2)-lengd/2;
private int yHradi = 0;
public Spilari1()
{
}
public void uppfaera()
{
y = y + yHradi;
System.out.println("HRAÐI ER "+yHradi);
}
public void paint(Graphics g)
{
g.setColor(Color.BLUE);
g.fillRect(25, y, breidd, lengd);
System.out.println("Y er "+y);
}
public void setyHradi(int hradi)
{
yHradi = hradi;
}
}
According to this Thread ("http://forums.netbeans.org/post-134877.html") the problem is that you pass a reference of this to an outside class while not fully initialized (in constructor). So you need to do this later in an initialization method
I'm creating a java game. In the game there are a hero and a bubble. The hero is supposed to move when I press the arrow keys and the bubble is supposed to have continuous diagonal movement. When I add the hero or the bubble directly into to the JFrame separately I get the desired behavior, but when I add them both I just get a very small square! I tried to add them to the same JPanel and after add that JPanel to the JFrame but it is not working. Probably I have to define some type of layout to the JPanels.
What am I doing wrong?
Code:
public class Pang {
public static void main(String[] args) {
JFrame f=new JFrame();
JPanel gamePanel=new JPanel();
gamePanel.setPreferredSize(new Dimension(800, 600));
DrawHero d=new DrawHero();
DrawBubble bubble=new DrawBubble();
gamePanel.add(d);
gamePanel.add(bubble);
f.add(gamePanel);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
}
}
public class DrawHero extends JPanel implements ActionListener, KeyListener {
Timer myTimer = new Timer(5, this);
int x = 0, y = 0, dx = 0, dy = 0, step = 10;
private transient Image imageHero = null;
public DrawHero() {
myTimer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
imageHero = getHeroImage();
g2.drawImage(imageHero, x, y, 40, 40, null);
}
public Image getHeroImage() {
Image image = null;
image = getImage("hero.png");
return image;
}
public Image getImage(String path) {
Image tempImage = null;
try {
URL heroiURL = DrawHero.class.getResource(path);
tempImage = Toolkit.getDefaultToolkit().getImage(heroiURL);
} catch (Exception e) {
System.out.println("Error loading hero image! - "
+ e.getMessage());
}
return tempImage;
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void moveUp() {
y = y - step;
}
public void moveDown() {
y = y + step;
}
public void moveLeft() {
x = x - step;
}
public void moveRight() {
x = x + step;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) {
moveUp();
}
if (keyCode == KeyEvent.VK_DOWN) {
moveDown();
}
if (keyCode == KeyEvent.VK_LEFT) {
moveLeft();
}
if (keyCode == KeyEvent.VK_RIGHT) {
moveRight();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
public class DrawBubble extends JPanel implements ActionListener, KeyListener {
Timer myTimer = new Timer(5, this);
int x = 100, y = 200, dx = 0, dy = 0, step = 10;
private transient Image imageHero = null;
public DrawBubble() {
myTimer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
}
public void actionPerformed(ActionEvent e) {
x=x+dx;
y=y+dy;
repaint();
}
public void moveBubble() {
dy=2;
dx=2;
}
public void keyPressed(KeyEvent e) {
moveBubble();
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
I recommend that neither the DrawHero nor DrawBubble (which should be called Hero nor Bubble respectively) should extend any JComponent. Instead each should simply know how to draw itself to a Graphics object passed to it, when requested to do so.
Then a single GameField or PlayingArea class should keep references to all the Bubble objects and the Hero and draw call the draw(Graphics) method of those objects.
Using this approach it is not necessary to worry about layouts within the GameField component (they become irrelevant).
That is the basic strategy I pursue for rendering the stationary objects in this answer to [Collision detection with complex shapes.
When I add the hero or the bubble directly into to the JFrame separately I get the desired behavior, but when I add them both i just get a very small square!
The default layout manager for a JFrame is a BorderLayout. When you use add(component) without a constraint the component goes to the CENTER. Only one component can be added to the CENTER, so only the last one added is displayed.
I tried to add them to the same JPanel and after add that JPanel to the JFrame but it is not working.
The default layout manager for a JPanel is the FlowLayout which respects the preferred size of component. The problem is you don't override the getPreferredSize() method so the size is (0, 0) and there is nothing to paint.
Probably I have to define some type of layout to the JPanels.
Actually since you want random motion you need to use a null layout on the panel and then use the setSize() and setLocation() method of your components to position the components.
Then when you do this the custom painting should always be done at (0, 0) instead of (x, y) since the location will control where the component is painted on the panel.
so I am trying to make a simple program where you click on the screen and it creates a block that falls and collides with a larger block beneath and sticks to it. Kind of like a simple collision program. The problem is when I create one block it deletes the block previously. I made an array, but it still does this. Do any of you know what Im doing wrong? Im sure its a simple fix.
public class Screen extends JPanel implements Runnable {
public static JLabel statusbar; //displays a status bar showing what mouse movements are taking place
private Image cat; //image of the cat
public int xCoord ; //get the coordinates of the mouse pressed
public int yCoord ;
public int xCreate;
public int yCreate;
public Rectangle Ground;
public Rectangle Block;
public boolean isClicked = false;
public int clickCount = 0;
Rectangle blocks[] = new Rectangle[10];
int blocknum = 0;
public Screen(Frame frame) {
loadPic(); //calls the loadPic method above
Handlerclass handler = new Handlerclass(); //creates a new class to use the mouse motion listener
System.out.println("mouse works!");
addMouseListener(handler);
addMouseMotionListener(handler);
statusbar = new JLabel("default");
add(statusbar);
}
public void run(){ //this is the game run loop
System.out.println("this is running");
try{
} catch(Exception e) {} //exception handling
}
public void loadPic(){ //loads the picture from the other project but its the same pic
cat = new ImageIcon("C:\\Users\\Camtronius\\Documents\\NetBeansProjects\\Moving Block Proj\\src\\MovingBlock\\catIcon1.png").getImage(); //gets the image
System.out.println("Image Loaded!");
}
#Override public void paintComponent(Graphics g){
super.paintComponent(g); //paints the component, the picture, on top
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(cat, xCoord, yCoord, null);
g2d.setColor(Color.BLUE);
Ground = new Rectangle(0,450,550,50);
g2d.fillRect(0,450, 550, 50);
for(Rectangle blocknum : blocks){
if (blocks != null) {
g2d.setColor(Color.RED);
g2d.fillRect(xCreate,yCreate,50,50);
System.out.println(blocknum);
}
}
//move();
}
public void move(){
if(yCreate<400){
yCreate+=1;
}else{
}
if(Ground.intersects(blocks[blocknum])){
yCreate=400;
System.out.println("contains!");
}
}
private class Handlerclass implements MouseListener, MouseMotionListener{
public void mouseClicked(MouseEvent event){
}
public void mousePressed(MouseEvent event){
}
public void mouseReleased(MouseEvent event){
if(blocknum<blocks.length){
xCreate=event.getX();
yCreate=event.getY();
blocks[blocknum] = new Rectangle(50,50, xCreate, yCreate);
repaint();
}
blocknum=blocknum+1;
}
public void mouseEntered(MouseEvent event){
}
public void mouseExited(MouseEvent event){
}
public void mouseDragged(MouseEvent event){
}
public void mouseMoved(MouseEvent event){
statusbar.setText(String.format("Coordinates are: %d, %d", event.getX(),event.getY()));
xCoord=event.getX();
yCoord=event.getY();
}
}
}
Painting is a destructive process. That is, when a new paint cycle runs, the previous contents of the Graphics context should be cleared...
So, in you paintComponent method you are only painting the last block...
if(isClicked = true){
blocks[blocknum] = new Rectangle(50,50, xCreate, yCreate);
g2d.setColor(Color.RED);
g2d.fillRect(xCreate,yCreate,50,50);
System.out.println(blocknum);
repaint(); // THIS IS A BAD IDEA
}
DO NOT call any method that might cause repaint to be called. This will put you in a potential cycle of death that will consume your CPU.
Instead, you should loop through the blocks array and paint each one...
for (Rectangle block : blocks) {
if (block != null) {
g2d.setColor(Color.RED);
g2d.fill(block);
}
}
And in you mouseReleased method, you should be adding the new rectangles...
public void mouseReleased(MouseEvent event){
blocknum=blocknum+1;
if (blocknum < blocks.length) {
xCreate=event.getX();
yCreate=event.getY();
blocks[blocknum] = new Rectangle(xCreate, yCreate, 50, 50);
}
}
I'd suggest you take a look at Custom Painting, Painting in AWT and Swing and Concurrency in Swing for more details
I have been trying to load imageicons into a jframe. I have no idea why this code doesn't work. I have tried using jpanels and jlabels, and also other ways of loading images, but those don't work either. I think because of this it has something to do with my JFrame that I set up . I would like to stay away from jpanels and jlabels, because at least as far as my knowledge goes, they cannot be scaled. If anyone has a solution to adding the images, please tell me. here is the code:
import java.awt.Canvas;
import javax.swing.JFrame;
import java.awt.*;
import javax.swing.ImageIcon;
import java.awt.event.KeyEvent;
import java.awt.Graphics;
public class Base extends Canvas implements Runnable {
private static final long serialVersionUID = 001;
private Image rock1;
private Image rock2;
private Image wood1;
private Thread thread;
private boolean running = (false);
private boolean paused = (false);
int x = 0;
int y = 0;
int z = 512;
private void start() {
if (running)
return;
running = true;
thread = new Thread(this);
}
public void run(){}
public Base(){}
public static void main(String[] Args) {
Base game = new Base();
JFrame frame = new JFrame();
frame.add(game);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.setTitle("Game");
System.out.println("Running...");
game.start();
game.loadPics();
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_A) {
x = x - 5;
}
if (e.getKeyCode() == KeyEvent.VK_D) {
x = x + 5;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
y = y - 5;
}
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
y = y + 5;
}
if (e.getKeyCode() == KeyEvent.VK_W) {
z = z + 5;
}
if (e.getKeyCode() == KeyEvent.VK_S) {
z = z - 5;
}
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
paused = (true);
}
}
public void loadPics(){
rock1 = new ImageIcon("C\\...\\rock1.png").getImage();
rock2 = new ImageIcon("C\\...\\rock2.png").getImage();
wood1 = new ImageIcon("C\\....\\wood1.png").getImage();
repaint();
}
public void paint(Graphics g){
while(paused = false){
g.drawImage(rock1, x, y, z, z, this);
g.drawImage(rock2, x + 512, y, z, z, this);
g.drawImage(wood1, x, y + 512, z, z, this);
try{
Thread.sleep(16);
}catch(Exception e){}
g.dispose();
}
}
}
Again, I think the problem lies with my JFrame, but I can't be too sure since I am not the most experienced java programmer. Anyway, if you know a solution or what to change, please help.
This statement
while (paused = false){
will always evaluate to false as you're using an assignment expression, so the subsequent calls to drawImage won't occur. You probably meant to use the == operator to compare the primitive boolean value:
while (paused == false){
Don't use paint, Use paintComponent from a subclassed JComponent
Don't call Thread.sleep in any paint method. Swing has its own concurrency mechanisms. Instead of calling Thread.sleep here, you could use a Swing Timer to periodically perform graphical updates.
Aside from that, AWT are heavyweight components are don't render well with lightweight Swing components. Use Key Bindings rather than Key Listeners for Swing applications.
I have had many recurring problems like this and have developed a way to solve this.
First of all, your public class Base needs to be double buffered. Change method paint(Graphics g) to paintComponent(Graphics g). Add a new paint(Graphics g) method and add this code:
public void paint(Graphics g) {
// TODO Auto-generated method stub (IGNORE!!!)
dbi = createImage (getWidth(),getHeight());
dbg = dbi.getGraphics();
paintComponent(dbg);
g.drawImage(dbi , 0 , 0 , this);
}
And at the top of public class Base, add these variables:
private Image dbi;
private Graphics dbg;
This automatically calls paintComponent(Graphics g) and has completed the first step.
Next, remove the try statement in paintComponent() and write this in run()
#Override
public void run() {
try {
while (true) {
Thread.sleep(5); // we want this so the computer doesn't go too fast
}
} catch (Exception e) { // Never have an empty catch statement
System.out.println ("Error! stacktrace: ");
e.printStackTrace();
}
}
The #Override annotation has to be there or it will not repaint.
The next part is crititcal:
before anything else, put super.paint(g); at the top of paintComponent(Graphics g)
and repaint(); at the bottom.
This should have solved it, but there are some potential problems I found;
JFrame initialization
public Base(){
add(game);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
setTitle("Game");
start();
loadPics();
}
public static void main(String[] Args) { // Makes game smoother
Base base = new Base ();
Thread t = new Thread (base);
t.start();
}
Remove private void start() as this does not affect game play.
Check the file directories, as they may be incorrect. Hint: C\ doesn't cut it. It's C:\
Hope it works out and happy coding!
I am learning something new and somewhat difficult in Java-which is graphics! Below I explain what the two classes do. My new obstacle right now is coming up with a way to draw a different image for (ie: a projectile like a laser) coming from the ball by only pressing Z.
The problem is if I write a method for example: "g.drawImage(laser,laser_dx,laser_dy,this) in the if statement that contains "KeyEvent.VK_Z", my keyPressed method all of sudden says "this method is not used locally". What are my approaches to solving such an obstacle?
What I've done so far is written a nested class inside the "GameBoard" class that contains all the keyboard events of my program.
private class Adapter extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_RIGHT)
{
ball_dx += ball_velocity;
}
if(keyCode == KeyEvent.VK_LEFT)
{
ball_dx -= ball_velocity;
}
if(keyCode == KeyEvent.VK_Z){
}
}
}
Here's the drawing graphics method in a separate class called "Gameboard": This class just draws the image of a green ball(which is a .png image) and it can move left and right with the arrow keys!
public class GameBoard extends JPanel implements ActionListener
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(ball, ball_dx, ball_dy, this);
Toolkit.getDefaultToolkit().sync();
}
public void actionPerformed(ActionEvent arg0)
{
repaint();
}
}
You have to rethink the logic: the code that handles the key events and the code that draws everything should share a state so that
events set the state
drawings change according to the state
Just to make it simple and to give you the idea:
boolean isLaser = false;
public void keyPressed(KeyEvent e) {
isLaser = true;
}
public void keyReleased(KeyEvent e) {
isLaser = false;
}
public void paintComponent(Graphics g) {
if (isLaser)
// do something
}
Of course in a more complex environment you would have a more structured solution like
List<Entity> entities = new ArrayList<Entity>();
public void paintComponent(Graphics g) {
for (Entity e : entities)
e.draw(g);
}
public void keyPressed() {
entities.add(new LaserEntity(...));
}