Im newish to java, and im writing a pong game.
Ive got the ball to move (Thats my first priority) and make it apear on screen.
But for some Reason its leaving a black line behind it, I dont know if im supposed to errase this or something, but heres the code of my 2 classes (The Ball Class is just a class to save the info of the ball)
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Main extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static int Width=650;
public static int Height=600;
public boolean Running=false;
public Thread thread;
public Ball ball = new Ball();
public static void main(String[] args){
Main game = new Main();
JFrame frame = new JFrame();
frame.setSize(Width+25, Height+49);
frame.setTitle("Pong By Poo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.add(game);
game.start();
}
public void start(){
if(Running==true){
return;
} else {
Running=true;
thread = new Thread(this);
thread.start();
}
}
public void run(){
while(Running==true){
try{
Thread.sleep(5);
Draw();
Update();
ball.YVelocity();
ball.XVelocity();
} catch(Exception e){}
}
}
public void Draw(){
BufferStrategy bs = this.getBufferStrategy();
if(bs==null){
createBufferStrategy(2);
} else {
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillOval(ball.BallLocationX, ball.BallLocationY, 20, 20);
g.dispose();
bs.show();
}
}
public void Update(){
if(ball.BallLocationX==0) {
ball.BallMovementX=true;
System.out.println("Ball has hit the Left");
}
if(ball.BallLocationX==Width) {
ball.BallMovementX=false;
System.out.println("Ball has hit the Right");
}
if(ball.BallLocationY==0){
ball.BallMovementY=true;
System.out.println("Ball has hit the Top");
}
if(ball.BallLocationY==Height){
ball.BallMovementY=false;
System.out.println("Ball has hit the bottom");
}
}
}
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Ball extends JPanel{
public int BallLocationX;
public int BallLocationY;
public boolean BallMovementY; //true makes the ball go up, false makes it go down
public boolean BallMovementX; //True makes the ball go right, false makes it go left.
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(BallLocationX, BallLocationY, 10, 10);
}
//moves the ball left to right
public int YVelocity(){
if(BallMovementY==true){
BallLocationY++;
} else {
BallLocationY--;
}
return BallLocationY;
}
//Moves the ball up and down
public int XVelocity(){
if(BallMovementX==true){
BallLocationX+=2;
} else {
BallLocationX-=2;
}
return BallLocationX;
}
}
Please help!
Essentially, everywhere your ball moves stays permanently Color.BLACK on your Canvas. If you want to get rid of that, you need to refresh every time the ball moves and repaint the Canvas to Color.WHITE (or whatever) before painting the ball's position again.
Specifically, look at your code here:
public void Draw(){
BufferStrategy bs = this.getBufferStrategy();
if(bs==null){
createBufferStrategy(2);
} else {
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillOval(ball.BallLocationX, ball.BallLocationY, 20, 20);
g.dispose();
bs.show();
}
}
There is no logic here that overwrites your previous changes to the Canvas indicating the ball's location.
Also, as a side nitpick, Java standards are to have method names in camelCase.
And to answer the question in the comments: there is nothing in the Canvas API which automatically understands what you want the default background of the Canvas to be and can reset all other graphics attributes to that. To get this functionality, however, all you'll need to do is repaint your default layout (whether it's all one color, or a basic background image, or anything else) before painting the ball's position on top of it.
Related
I've made a JFrame with a canvas on it and I want to draw on that canvas. At a later date the canvas will be updating many times a second so I am using a buffer strategy for this. Here is the code:
package mainPackage;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class TickPainter {
//just some presets for a window.
public static JFrame makeWindow(String title, int width, int height) {
JFrame mainWindow = new JFrame();
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(width, height);
mainWindow.setVisible(true);
mainWindow.setLocationRelativeTo(null);
mainWindow.setTitle(title);
return mainWindow;
}
public static void main(String[] args) {
JFrame mainWindow = makeWindow("Practice", 800, 600);
Canvas mainCanvas = new Canvas();
mainWindow.add(mainCanvas);
mainCanvas.setSize(mainWindow.getWidth(), mainWindow.getHeight());
mainCanvas.setBackground(Color.white);
mainCanvas.createBufferStrategy(3);
BufferStrategy bufferStrat = mainCanvas.getBufferStrategy();
Graphics g = bufferStrat.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(250, 250, 250, 250);
g.dispose();
bufferStrat.show();
}
}
The program does not draw the black rectangle as intended, I feel like I've missed something really obvious here and I just can't see it. At the moment the program just makes a blank white canvas. I feel like part of the issue is that the buffer is just passing the frame with the rectangle faster than I can see, but there is no frame to load after that so I don't know why it's doing this.
A BufferStrategy has a number of initial requirements which must be meet before it can be rendered to. Also, because of the nature of how it works, you might need to repeat a paint phases a number of times before it's actually accepted by the hardware layer.
I recommend going through the JavaDocs and tutorial, they provide invaluable examples into how you're suppose to use a BufferStrategy
The following example uses a Canvas as the base component and sets up a rendering loop within a custom Thread. It's very basic, but shows the basic concepts you'd need to implement...
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestCanvas canvas = new TestCanvas();
JFrame frame = new JFrame();
frame.add(canvas);
frame.setTitle("Test");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
canvas.start();
}
});
}
public class TestCanvas extends Canvas {
private Thread thread;
private AtomicBoolean keepRendering = new AtomicBoolean(true);
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void stop() {
if (thread != null) {
keepRendering.set(false);
try {
thread.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void start() {
if (thread != null) {
stop();
}
keepRendering.set(true);
thread = new Thread(new Runnable() {
#Override
public void run() {
createBufferStrategy(3);
do {
BufferStrategy bs = getBufferStrategy();
while (bs == null) {
System.out.println("get buffer");
bs = getBufferStrategy();
}
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
System.out.println("draw");
Graphics graphics = bs.getDrawGraphics();
// Render to graphics
// ...
graphics.setColor(Color.RED);
graphics.fillRect(0, 0, 100, 100);
// Dispose the graphics
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (bs.contentsRestored());
System.out.println("show");
// Display the buffer
bs.show();
// Repeat the rendering if the drawing buffer was lost
} while (bs.contentsLost());
System.out.println("done");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
} while (keepRendering.get());
}
});
thread.start();
}
}
}
Remember, the point of BufferStrategy is to give you full control over the painting process, so it works outside the normal painting process generally implemented by AWT and Swing
"At a later date the canvas will be updating many times a second so I am using a buffer strategy for this" - Before going down the "direct to hardware" solution, I'd consider using a Swing Timer and the normal painting process to see how well it works
My issue here with ball animation is that the ball is moving in a straight line leaving behind a trail. My expected output is that there should be no trail of the ball.
The code determines the movement of the ball in just one direction along X axis.
public class App extends JFrame implements Runnable{
int x=0,y=250;
public void run() {
for(;;) {
try {
repaint();
x++;
Thread.sleep(10);
} catch(Exception e){}
}
}
public void paint(Graphics g) {
g.drawOval(x,y,30,30);
}
public static void main(String[] args) {
App frame= new App();
frame.setTitle("Bounce");
frame.setSize(400, 450);
frame.setVisible(true);
Thread t1 = new Thread(frame);
t1.start();
}
}
You missed to call super.paint in your paint method:
public void paint(Graphics g) {
super.paint(g);
g.drawOval(x,y,30,30);
}
This is not a multi-threading issue, you just never "erase" the ovals you draw for the previous x. Your paint method needs to call super.paint() in order to clear the previous ovals. This is explained here with almost the same code as you but without your issue!
I was suggested not to use sleep for pausing purpose and instead use swing timer but still its not working.The animation i want to achieve is a ball travelling from the top left corner diagonally towards the bottom.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
class Show_starter {
int x, y;
JFrame window = new JFrame("Graphic_show");
Graphic_panel jp = new Graphic_panel();
public static void main(String[] args) {
Show_starter start = new Show_starter();
start.go();
}
private void go() {
window.getContentPane().add(BorderLayout.CENTER, jp);
window.setSize(600,800);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Graphic_panel extends JPanel {
public void paintComponent(Graphics g) {
for ( int i = 0; i < 100; ++i) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
x++;
y++;
try {
Timer tmr = new Timer(1000, new TimerListener()); //This fires an event after every 1 sec after it has started by start().
//But The ball travels too much fast and stops at a point and again travels very fast.
tmr.serRepeats(false); // even this is not working.
tmr.start();
//should i use repaint here or in Listener for this timer?
} catch (Exception e){}
}
}
class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
jp.repaint();
}
}
}
}
The behaviour it is showing is very odd ball first goes at very high speed and stops momentarily at a point and again moves at same speed.
I have also tried to change the time for timer event to fire but the same thing happens.
Even inside loop where I have started timer the follow function call is not working
setRepeats(false);
don't create new timers always one timer is enough .decrees timing interval bit more .1 second is too slow for a animation.you don't need a loop and don't increment x and y inside paintcomponet() method because this method get called for some reason for example when you resize,minimize,maximize.
the unexpected behavior is due to your loop and creating new timers(). for example in x y start at zero but in first second x y increased to 100,100 in next paint you see them in a 100,100 position .that's look like quick move and then stop ...
example code (edited)
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Show_starter {
private Timer tmr;
int x, y;
JFrame window = new JFrame("Graphic_show");
Graphic_panel jp = new Graphic_panel();
public static void main(String[] args) {
Show_starter start = new Show_starter();
start.go();
}
private void go() {
window.getContentPane().add(BorderLayout.CENTER, jp);
window.setSize(600, 800);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tmr = new Timer(10, new ActionListener() { // time gap in millisecond
#Override
public void actionPerformed(ActionEvent ae) {
jp.increse();
jp.repaint();
}
});
tmr.start();
}
class Graphic_panel extends JPanel {
public void increse() {
x++;
y++;
if (x > 100) { // stop animation at x>100
tmr.stop();
}
}
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
}
}
output (smoother than that)
Firstly you should not use a loop inside paint component.
public void paintComponent(Graphics g){
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
Just draw it and make x and y public in the class so that you can easily access from outside
Now run a runnable (consult invokelater and swingUtilities) or create a new Thread
inside public void run() do whatever animations you want to do . You can use a loop but add Thread.sleep(//in miliseconds) and repaint() in each iteration .
note : you need to change the x and y and repaint() so that it is drawn in a new position. And the sleep() is needed to slow down the execution otherwise it can't be visible to viewer.
I am very new to java. Very. Like I basically started today. I have previous programming knowledge in other languages, like c, c++, PHP, javascript, etc, but I can't figure this one out. I started watching tutorials on Youtube about how to make a video game in Java(videos from theChernoProject), but about 7 episodes in, I came across a problem, where we have our window, and we paint a black rectangle across the whole thing, and the application freezes my whole computer. Here is my code:
package com.darksun.theonetruemike.rain;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private Thread thread;
private JFrame frame;
private boolean running = false;
public Game(){
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public synchronized void start(){
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop(){
running = false;
try{
thread.join();
} catch(InterruptedException e){
e.printStackTrace();
}
}
public void run(){
while(running){
update();
render();
}
}
public void update(){
}
public void render(){
BufferStrategy bs = getBufferStrategy();
if(bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public static void main(String args[]){
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Rain");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
I'm using eclipse to make this project(highly against my will), and when I press the Debug button, the window appears, and my computer freezes, resulting in having to force quit the entire computer. Please help if you can, and thanks for help ahead of time!
since i have low reputation, i will post my comment as answer, try not to -rep
i copied your code to netbeans, a black console like window appears, nothing happens, but it doesnt freeze, but the JVM is using about 50% of cpu
I'm trying to use the method addBall to Paint a ball with it's own thread unto the coloredBallPanel
I'm very stuck and would appreiciate any help at all.
Btw I'm trying to make bouncing ball program in which all the balls run on their own separate threads.
public class ColoredBallPanel extends JPanel
{
Ball ball;
public ColoredBallPanel()
{
ball= new Ball();
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, 499, 300);
// ball.paint(g2);
}
}
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BallsFrame extends JFrame
{
private ColoredBallPanel coloredBallPanel;
private final int FRAME_WIDTH = 500;
private final int FRAME_HEIGHT = 500;
private int BallDimensionsx =30,BallDimensionsy=30;
private Ball ball = new Ball();
public BallsFrame()
{
//sets the size of the JFrame
setSize(FRAME_WIDTH, FRAME_HEIGHT);
coloredBallPanel = new ColoredBallPanel();//Initialize a Ball panel
add(coloredBallPanel, BorderLayout.CENTER);//white square in the centre
addBall(); // add two balls to panel(Doesn't work yet)
addBall();
}
public void addBall()
{
Ball ball = new Ball();
coloredBallPanel.add(ball);
Runnable r = new ColoredBallRunnable(ball, coloredBallPanel);
Thread t = new Thread(r);
t.start();
}
}
import java.awt.*;
import javax.swing.*;
public class Ball extends JComponent
{
private int x=(int) (Math.random()*(500 -1)),
y =(int) (Math.random()*(300-1)),
xVelocity=-10,
yVelocity=10;
private int width=30,height=30,size =30;
/**
* #param args
*/
public void update()
{
x+=xVelocity;
y+=yVelocity;
if(x<=0)
{
xVelocity =10;
}
else if(x+size>=500)
{
xVelocity = -10;
}
if(y<=0)
{
yVelocity =10;
}
else if (y+size>=300)
{
yVelocity=-10;
}
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.GREEN);
g2.fillOval(x, y, width, height);
}
}
import javax.swing.JComponent;
import javax.swing.JPanel;
public class ColoredBallRunnable implements Runnable
{
private Ball ball ;
public ColoredBallRunnable(Ball ball, ColoredBallPanel coloredBallPanel)
{
// TODO Auto-generated constructor stub
ball = new Ball();
coloredBallPanel = new ColoredBallPanel();
}
public void run()
{
Ball ball = new Ball();
while(true)
{
ball.update();
ball.repaint();
try{
Thread.sleep(10);
}catch(InterruptedException e){
return;
}
}
}
}
There are so many problems...
Ball is component been added to a Container which is under the control of a LayoutManager, this means that, even if you got Ball to move, you would fighting the layout manager all the time
Ball has no "size" (or position for that matter), so when it is added to the Container, it's sized to it's default size of 0x0, making it, virtually, invisible
Ball is never painted. This is actually for two reasons, but we'll start with the obvious, it doesn't override any valid paint methods that would allow Swing to paint it...if it was larger than 0x0.
Solutions...?
Make Ball just a POJO which knows it's size and location (and can update itself if that's what you need)
Create a "model" of some kind that can be shared between the view ColoredBallPanel and the controller (the thread). This model should maintain a List of Balls currently available...
Allow the ColoredBallPanel to loop through this list of balls and paint them via it's paintComponent method
Allow the controller to loop through this list of balls and update them.
Synchronise access to the balls list, so neither the view or controller can mess with the list while the other is using it. You might consider making a read-only version of the list for the view, but that might be beyond the scope right now...
Call super.paintComponent before you do any custom painting
Perhaps, something more like Java Bouncing Ball