I am creating a pong game. I have fininshed the ball and paddle classes, the animator and everything else related. However when I open my created program only 1 paddle shows, while the other paddle and the ball do not show. If I change the way I draw things, the ball will show and the other 2 paddles don't. So it only draws 1 thing, whatever comes first. Here is the code for part which paints to the buffer.
public void renderlojen(){ // render game function
if(pamja==null){
pamja=createImage(GJERESIA,LARTESIA); // Image - serves as buffer
}
g =(Graphics2D) pamja.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, GJERESIA, LARTESIA);
doreza1.vizatodorezen(g); // paddle1
doreza2.vizatodorezen(g); // paddle2
topi1.vizatotopin(g); // ball
g.dispose();
}
public void updatolojen(){ // update game function
topi1.leviztopin();
doreza1.levizdorezen();
doreza2.levizdorezen();
}
public void pikturolojen(){ // draw from buffer to screen
if (pamja!=null){
g=(Graphics2D)this.getGraphics();
g.drawImage(pamja, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
g.dispose();
System.out.println(doreza1.merrX());
System.out.println(doreza2.merrX());
}
else
System.out.println("Ska pamje");
}
public void vizatotopin(Graphics2D g2d){ // draw the ball code
topiforma =new Ellipse2D.Float(pozicioniX,pozicioniY,2*rrezja,2*rrezja);
g2d.setColor(Color.CYAN);
g2d.fill(topiforma);
g2d.dispose();
}
public void vizatodorezen (Graphics2D g2d){ // draw paddle code
drejtkendeshforma = new Rectangle2D.Float(pozicioniX,pozicioniY,GJERESIA,LARTESIA);
g2d.setColor(ngjyra);
g2d.fill(drejtkendeshforma);
g2d.dispose();
}
The problem is calling Graphics.dispose() in the rendering methods of the game objects. Drawing to the Graphics is not valid after that, so only the first object gets drawn.
In general, call Graphics.dispose() only in the same method where you created it. Not in methods that receive one as a parameter.
Related
I figured out a solution minutes after posting, but due to low reputation I couldn't delete the post
For the fun of it I decided to start working on something which might turn into a game at some point.
I'm trying to draw some circles and move them in a given direction currently. This causes flickering. It's very likely that I oversee something very basic but I can't figure out why it doesn't render smoothly.
My board class looks something like (removed what I deemed unnecessary):
public class Board extends Canvas implements Runnable {
public static void main(String[] args) {
Board board = new Board();
board.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame("Circles");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(board);
frame.pack();
frame.setVisible(true);
board.start();
}
#Override
public void run() {
while (running) {
process();
repaint();
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
The paint method:
public void paint(Graphics g1) {
super.paint(g1);
Graphics2D g = (Graphics2D) g1;
for (Ball ball : Ball.BALLS) {
g.drawOval((int) ball.getLocation().getX(), (int) ball.getLocation().getY(), ball.getRadius(), ball.getRadius());
}
}
My process method:
private void process() {
if (utilities.randInt(1, 100) < 10 && Ball.getBallCount() < 40) {
Ball.spawnNew(this);
}
for (Ball ball : Ball.BALLS) {
ball.move(this);
}
Ball.BALLS.removeAll(Ball.TO_REMOVE);
Ball.TO_REMOVE.clear();
}
The move method basically increments the x-value of the ball by a given value each time its called (moving it right).
Like I said, I'm unsure why it flickers so if you have any pointers please do tell.
Thanks!
This sounds like a case where you need to perform double-buffering, so that one copy of your canvas can remain shown while you are updating the other.
You're using AWT here, and I don't know how to implement double-buffering manually with AWT. However, if you're willing to use Swing here you can take advantage of automatic double-buffering. See the question about How to make canvas with Swing? as well as Oracle Technology Network's article on Painting in AWT and Swing.
The basic idea would be:
extend javax.swing.JPanel instead of Canvas (which means when you override paint(Graphics) you're now overriding it from javax.swing.JComponent instead of java.awt.Component)
create a constructor with super(true) to enable double-buffering.
Edit: Also, as iccthedral points out, you're better off overriding paintComponent(Graphics) and including a call to super.paintComponent(Graphics). See Difference between paint, paintComponent and paintComponents in Swing.
You need double buffering. To do this you need to create a BufferedImage and get the Graphics from it. Paint everything to the image, render the image on to the screen, then finally fill the image with a the background color or image to reset it.
Sample:
//one time instantiation
BufferedImage b = new BufferedImage(width, height, mode);
In paint(Graphics g):
Graphics buffer = b.getGraphics();
//render all of the stuff on to buffer
Graphics2D g = (Graphics2D) buffer;
for (Ball ball : Ball.BALLS) {
g.drawOval((int) ball.getLocation().getX(), (int) ball.getLocation().getY(), ball.getRadius(), ball.getRadius());
}
g1.drawImage(b, 0, 0, width, height, null);
g.setColor(Color.BLACK);
//reset the image
g.drawRect(0, 0, width, height);
g.dispose();
I have the following code that draws an invisible window on the entire screen:
Window w=new Window(null)
{
private int x = 200; private int y=200;
private int dx = 2; private int dy = 2;
private final int CIRCLE_DIAMETER = 400;
#Override
public void paint(Graphics g)
{
g.setColor(Color.ORANGE);
g.fillOval(x, y, CIRCLE_DIAMETER, CIRCLE_DIAMETER);
}
#Override
public void update(Graphics g)
{
if(x<=0)
dx*=-1;
if(y<=0)
dy*=-1;
if(x+CIRCLE_DIAMETER>=this.getWidth())
dx*=-1;
if(y+CIRCLE_DIAMETER>=this.getHeight())
dy*=-1;
x+=dx;
y+=dy;
this.paint(g);
}
};
w.setAlwaysOnTop(true);
w.setBounds(w.getGraphicsConfiguration().getBounds());
w.setBackground(new Color(0, true));
w.setVisible(true);
//Lazy way of making calls to paint for testing
while(true){
w.repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This draws an orange circle on the screen at the coordinates x and y. When I call repaint in my infinite loop, paint gets called and the x and y get updated, but the circle never gets drawn in another position. If I print the values of x and y to every call of paint they are getting updated properly, so I do not know why it isn't getting drawn. Does anyone know what I am doing wrong here?
Thanks for any suggestions!
I am new here so I may be wrong.
I think that your problem is something to do with how you are using a Window object and not a JPanel. So change your Window object to a JPanel. You should probably close that up with a JFrame in order to complete the final window.
You should be using a JPanel I think so that the methods that you can use to perform the drawing of the ball to move are implemented properly.
Instead of overriding the paint() method you need to override the paintComponent() method.
Following the cycle of drawing your objects.
Like so...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillOval(x, y, CIRCLE_DIAMETER, CIRCLE_DIAMETER);
}
The super.paintComponent() should empty the original image out of the JPanel and you should then be able to draw your updated image.
These may help you as well(I haven't really looked at them properly):
Java ball moving
http://docs.oracle.com/javase/tutorial/uiswing/painting/
Java Bouncing Ball
Sorry if I missed something. (I haven't tested your code)
I'm trying to draw inside my JPanel but everytime I click, the background of my JPanel disappears. It draws a line where the mouse is. I think it has something to do with the 2D graphics
Can someone help?
public Brush() {
addMouseListener(this);
addMouseMotionListener(this);
setBackground(Color.white);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2;
// super.paintComponent(g);
g2 = (Graphics2D) g;
g2.setColor(brushColor);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
//Ellipse2D.Double circle = new Ellipse2D.Double(p1.x,p1.y,20,20);
g2.fillOval(p1.x,p1.y,20,20);
}
#Override
public void mousePressed(MouseEvent e) {
dragging = true;
p1 = e.getPoint();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
dragging = false;
p1 = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (dragging) {
p1 = e.getPoint();
repaint();
}
}
Always call the super.paintComponent(g) method inside of your override.
You're drawing wrong then. If you want to draw a bunch of ovals, then either
create a collection of them and draw them with a for loop in paintComponent, or
draw them in a BufferedImage which is then drawn in your paintComponent method.
If I want to draw a curve with the mouse, I usually create an ArrayList<Point> and draw lines between contiguous points, either in paintComponent or in a BufferedImage.
Again, your code is written to draw only one point (oval actually) within paintComponent. If coded correctly, this is all it will do.
I suggest, the easiest thing to do is:
Give you class an ArrayList<Point>
Add points when mouse is pressed and call repaint
In paintComponent, call the super method, and then use a for loop to iterate through the ArrayList.
Start the loop at the Point at item 1, not 0, and then draw a line between the previous Point and the current point.
To get fancier, you may wish to have an ArrayList<ArrayList<Point>> where you start a new ArrayList<Point> with each press of the mouse, finish it with each release and add it to the overall collection. This will allow several lines to be drawn.
Why not give this a go on your own first?
So, I have a map, that I want to be able to draw rectangles on to highlight an area. When the mouse is released a permanent rectangle is drawn on the map that persists until the mouse is dragged again to start the creation of a new rectangle. While the mouse is being dragged the rectangle outline should be created as it goes along.
The persisting rectangle is removed when the mouse is reclicked which given the application would mean that a new drag event would be started.
What happens is that the first rectangle is painted correctly and everything is fine, but subsequent rectangles that are currently being dragged have the corner cut off (image link at bottom).
If I click and then wait for the image to repaint before I start dragging then this problem does not exist, as well as if I sleep the thread before beginning to draw the rectangle in onMouseDragged so that it has time to repaint.
I'd like a more elegant solution than those to allow the screen to repaint before the rectangle created in onMouseDragged is shown on the screen. So what is the best way to get the repaint to complete without zapping part of the drawn rectangle?
Note that despite the look of the outline, the persisting rectangle that gets drawn is correct.
This is what the rectangle looks like
public void onMousePressed(MapMouseEvent ev)
{
startPos = new Point(ev.getPoint());
drawer.removeDrawings(pane.getMapContent());
pane.repaint();
pane.setIgnoreRepaint(true);
}
public void onMouseDragged(MapMouseEvent ev)
{
super.onMouseDragged(ev);
if (enabled) {
ensureGraphics();
if (dragged)
{
// because we're in XOR mode, this has the effect of erases the previous rectangle
graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
}
else
{
}
rect.setFrameFromDiagonal(startPos, ev.getPoint());
graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
dragged = true;
}
}
public void onMouseReleased(MapMouseEvent ev)
{
super.onMouseReleased(ev);
if (dragged) {
ensureGraphics();
dragged = false;
drawer drawable = new drawer();
drawable.drawRectangle((Graphics2D) parentComponent.getGraphics().create(), rect.x, rect.y, rect.width, rect.height, pane.getMapContent());
graphics.dispose();
graphics = null;
pane.setIgnoreRepaint(false);
pane.repaint();
}
}
You need to maintain a List<Rectangle> and add the current Rectangle to the list on mouseReleased(). GraphPanel illustrates the basic mouse handling. In your case, simply render the image, any existing rectangles and the current rectangle.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// render background
g.drawImage(image, 0, 0, this);
// render existing rectangles
for (Rectangle r : list) {
r.draw(g);
}
// render the current dragged rectangle
if (selecting) {
g.setColor(Color.darkGray);
g.drawRect(mouseRect.x, mouseRect.y,
mouseRect.width, mouseRect.height);
}
}
In the example, selecting is a boolean value that controls whether a new rectangle is beng drawn or an existing selection is being dragged to a new location.
As all rendering must occur on the EDT, I doubt that you need (or want) a new thread.
I have been looking for 10 hours (literally) and I'm done, I need to ask. Thing is I'm learning How use LibGdx to program Java games. I'm doing a Horizontal Space Ship Game. So, my worst problem here is that I do not know how do scroll (I think draw will explain better). I want to draw a huge background (Space) and make my OrthographicCamera move right like with my SpaceShip, so it will create a Scroll effect with the Space Background. No enemies and nothing but the ship on the screen.
I'm trying this:
public void moveCamera(float x,float y){
cam.position.set(x, y, 0);
}
Then I use that method in my WorldRender render() method:
public void render(float delta){
ship.Move(delta);
moveCamera(ship.getPosition().x,ship.getPosition().y);
cam.update();
System.out.println(""+cam.position);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
I actually move the camera position (I can see that thanks to the println), but It isn't moving in the game, so SpaceShip just disappears by the edge of the window.
I also tried this before spriteBatch.end()
spriteBatch.setProjectionMatrix(camera.combined);
but when I do that windows only shows a black screen, no ship, no nothing.
As I said, I'm desperate, I see lot of examples (scroll with mouse, paralexscrolling etc) but all are to advanced or just nothing to do with my code.
This is how I draw stuff. Background and ship are textures inside WorldRender. I draw background image very wide, so my intention is do some scrolling over as I said. That's the code
private void loadTextures(){
shipTexture=new Texture(Gdx.files.internal("nave.png"));
background=new Texture(Gdx.files.internal("fondo.jpg"));
}
public void drawShip(){
spriteBatch.draw(shipTexture,ship.getPosition().x*ppuX,ship.getPosition().y*ppuY, ship.WIDTH*ppuX,ship.HEIGHT*ppuY);
}
public void drawBackground(){
spriteBatch.draw(background, -10*ppuX,0*ppuY, Gdx.graphics.getWidth()*10,Gdx.graphics.getHeight());
}
Here you can download the code if someone want to help in hardcore mode
My code (not working)
I FINALLY SOLVED IT!
That's the code I used in a class name WorldRenderer, which have methods that are called within GameScreen for render, resize etc
public WorldRenderer(World world) {
// TODO Auto-generated constructor stub
this.world=world;
this.ship=world.getShip();
this.cam = new OrthographicCamera(CAMERA_WIDTH,CAMERA_HEIGHT);
this.cam.setToOrtho(false,CAMERA_WIDTH,CAMERA_HEIGHT);
this.cam.position.set(ship.getPosition().x,CAMERA_HEIGHT/2,0);
this.cam.update();//actualizamos la camara
spriteBatch=new SpriteBatch();
loadTextures();
}
private void loadTextures(){
shipTexture=new Texture(Gdx.files.internal("nave.png"));
background=new Texture(Gdx.files.internal("fondo.jpg"));
}
public void drawShip(){
spriteBatch.draw(shipTexture,ship.getPosition().x,ship.getPosition().y,10,10);
}
public void drawBackground(){
spriteBatch.draw(background, 0,0, 500,50);
}
public void render(float delta){
ship.Move(delta);
moveCamera(ship.getPosition().x);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
public void moveCemara(float x){
cam.position.set(x+20,cam.position.y, 0);
cam.update();
}
Inside the Ship I have this method which I call within render in WorldRenderer to move It
public void Move(float delta){
if(Gdx.input.isKeyPressed(Keys.LEFT)) this.position.x -=velocity *delta;
if(Gdx.input.isKeyPressed(Keys.RIGHT)) this.position.x +=velocity *delta;
if(Gdx.input.isKeyPressed(Keys.UP)) this.position.y +=velocity *delta;
if(Gdx.input.isKeyPressed(Keys.DOWN)) this.position.y -=velocity *delta;
}
Also I want to thanks very much to the people who helped me. I'm marking first answer as the good one, but, mix both was what gave me the real solution.
I leave here some tutorials I followed which are pretty good for noobs
That's a good everything-from-scratching-tutorial
LiGdxForNoobs
A simple platform game
platformGame
A very simple game
bucketGame
I can't tell if this is your only mistake, but this is ONE mistake. If this is what you say you were doing:
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.end();
You wont see anything. When setProjectionMatrix is called inside a begin()/end() block. the current batch is flushed to the gpu. So, you are actually not drawing anything with the camera matrix. You should do this instead:
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
EDIT:
If you don't call that line, spriteBatch uses its own default camera (which wont notice your camera.update() modifications, so that's not what you want).
You should now pay more attention to the coordinates you are using. I'm not quite sure you really need the ppu conversion thing. To begin with, define everything in imaginary world coordinates, note that you'll see some stretching in your world.
public void drawShip(){
spriteBatch.draw(shipTexture,ship.getPosition().x,ship.getPosition().y, 10, 10);
}//your ship is 10 units wide and tall!
public void drawBackground(){
spriteBatch.draw(background, -10,0, 500, 100);
} //your background is 500 units wide, and 100 units tall
//camera setup
camera = new OrthographicCamera(50, 50);
//your camera will print to screen 50 units of your world
If you get to see a stretched world, try to understand how it's working (if you can't see anything, there is something wrong somewhere).
EDIT 2
I took a look at your code. First remove ppu's, as it obscures your code. You were setting your cam position to the ship.postion, while drawing at ship.position * ppu. Also your background was way too big (that's why you see it pixelated). You should see something reasonable with this. (someday you'll have to initialize your camera in another way to deal with stretching, but forget it until you understand how all works).
this.cam = new OrthographicCamera(CAMERA_WIDTH,CAMERA_HEIGHT);
public void drawShip(){
spriteBatch.draw(shipTexture, ship.getPosition().x ,ship.getPosition().y, 10, 10);
}
public void drawBackground(){
spriteBatch.draw(background, -CAMERA_WIDTH/2, -CAMERA_HEIGHT/2, 100, 100); //let bg begin where camera starts. (0,0)
}
public void render(float delta){
ship.Move(delta);
moverCamara(ship.getPosition().x, ship.getPosition().y);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
Its not clear how your drawing? I'm not sure if your doing this approach correctly.. Can you provide details of your background and ship? Can you provide details on you background image, is it a huge image that your scrolling around or is it a repeated image you want to repeat as you scroll?
--EDIT--
ok i think i have an idea what might be up. I would normally apply the camera to the current context.
Place the following in your resize
public void resize(int width, int height) {
cam = new OrthographicCamera(width, height);
cam.translate(width / 2, height / 2, 0);
}
Place the following in the start of your render()
cam.position.set(posX,posY,0);
cam.update();
cam.apply(Gdx.gl10);
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // #14
This will make you have a clear screen with the origin set at the bottom left of the window. You should then draw your background first
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
spriteBatch.draw(background,0,0,sizeX,sizeY);
spriteBatch.end()
see how that looks as you move your camera position posX and posY. Then add your ship to the mix
-- MORE EDITS ---
you can then calculate the posX and posY as
posX = defaultOffsetX+shipX
and so on..
Anyhow hope this helps
I'm still only learning myself so this might not be the best method.. but it seems to work.
I've edited your code. Have a look at the following:
public class WorldRenderer {
private World world;
private Ship ship;
private Texture shipTexture,background;
private SpriteBatch spriteBatch;
private OrthographicCamera cam;
float screenSizeX = 100;
float screenSizeY = 100;
float shipSizeX = 10;
float shipSizeY = 10;
public void setSize (int w, int h) {
cam = new OrthographicCamera(screenSizeX,screenSizeY);
}
public WorldRenderer(World world) {
this.world=world;
this.ship=world.getShip();
spriteBatch=new SpriteBatch();
loadTextures();
}
private void loadTextures(){
shipTexture=new Texture(Gdx.files.internal("nave.png"));
background=new Texture(Gdx.files.internal("fondo2.jpg"));
}
public void drawShip(){
spriteBatch.draw(shipTexture, ship.getPosition().x,ship.getPosition().y, shipSizeX,shipSizeY);
}
public void drawBackground(){
spriteBatch.draw(background, 0,0);
}
public void render(float delta){
ship.Move(delta);
moverCamara(ship.getPosition().x,ship.getPosition().y);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.end();
}
public void moverCamara(float x,float y){
cam.position.set(x, y, 0);
cam.update();
}
}
This way, your ship is always in the middle of the screen and the background moves. Hope this helps.