Home > Enterprise >  Draw a battery like bullet counter with java fillRect
Draw a battery like bullet counter with java fillRect

Time:10-04

I'm working in a game and now i'm stuck in a dumb part of the gui i can't realize the right way to do it

here is my logic of the bullet counter:

        g.setColor(Color.black);
        g.fillRect(600,20,120,40);
        g.setColor(Color.white);
        g.fillRect(605,25,110,30);


        for(int i=0;i < player.ammo;i  ){
            g.setColor(Color.black);
            g.fillRect(610 (i*5),30,20,20);

        }
        bs.show();

This is actually working fine, the problem is that the bullet counter grow as a single bar, and i want it to grow in individual rectangles like this: ▐▐▐▐▐▐▐▐ just like a camera battery level indicator, i've tried everything i could possibly think.

Obs.: If possible i would like to do it only using the methods of image.getGraphics()(idk if that last sentence make sense)

Thanks in advance

CodePudding user response:

Let's start with a simple, isolated example...

Bar Progress

What you need to know is:

  • The width of each bar
  • The amount of space between each bar
  • The number of bars which make up entire progress bar (ie, how many bars represent 100%)

From there you can render the progress bar based on the current progress by simply calculating the number of bars you need to display and then offsetting each from last by the bar width and the bar gap

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

public class Test {
    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                JPanel content = new JPanel(new BorderLayout());
                content.setBorder(new EmptyBorder(50, 50, 50, 50));
                frame.setContentPane(content);

                BulletProgress bulletProgress = new BulletProgress();
                Timer timer = new Timer(1000, new ActionListener() {

                    private double progress = 0;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        progress  = 0.1;
                        bulletProgress.setProgress(progress);

                        if (progress >= 1.0) {
                            progress = 0;
                        }
                    }
                });
                timer.setInitialDelay(1000);
                timer.start();

                frame.add(bulletProgress);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BulletProgress extends JPanel {

        private int bulletWidth = 10;
        private int bulletHeight = 20;
        private int bulletGap = 5;

        private double progress;

        public BulletProgress() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension((getBulletWidth() * 10)   (getBulletGap() * 9), bulletHeight);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int barCount = (int)Math.round(10 * progress);
            int xPos = 0;

            int bulletWidth = getBulletWidth();
            int bulletHeight = getBulletHeight();
            int bulletGap = getBulletGap();
            for (int bar = 0; bar < barCount; bar  ) {
                g2d.fillRect(xPos, 0, getBulletWidth(), getBulletHeight());
                xPos  = bulletWidth   bulletGap;
            }
            g2d.dispose();
        }

        public int getBulletWidth() {
            return bulletWidth;
        }

        public int getBulletHeight() {
            return bulletHeight;
        }

        public int getBulletGap() {
            return bulletGap;
        }

        public double getProgress() {
            return progress;
        }

        public void setProgress(double progress) {
            this.progress = progress;
            repaint();
        }



    }
}

Since, however, you're probably not needing a fully fledged component, I would consider using some kind of "painted" concept to further decouple (and re-use) the concept, for example...

public class BarProgressPainter {
    private int bulletWidth = 10;
    private int bulletHeight = 20;
    private int bulletGap = 5;

    public void paint(Graphics2D graphics, double progress) {
        Graphics2D g2d = (Graphics2D) graphics.create();
        int barCount = (int)Math.round(10 * progress);
        int xPos = 0;

        int bulletWidth = getBulletWidth();
        int bulletHeight = getBulletHeight();
        int bulletGap = getBulletGap();
        for (int bar = 0; bar < barCount; bar  ) {
            g2d.fillRect(xPos, 0, getBulletWidth(), getBulletHeight());
            xPos  = bulletWidth   bulletGap;
        }
        g2d.dispose();
    }

    public int getBulletWidth() {
        return bulletWidth;
    }

    public int getBulletHeight() {
        return bulletHeight;
    }

    public int getBulletGap() {
        return bulletGap;
    }
}

For me, the progress should come from some kind of model which could be suitably abstracted, allowing the rendering process to be decoupled (I have a paintable and I have model, I mash ;))

Obs.: If possible i would like to do it only using the methods of image.getGraphics()(idk if that last sentence make sense)

This would generally complicate the process, but, assuming you're willing to clear the image (or the area used by the progress bar) before repainting it, it should be easily doable with the above

CodePudding user response:

Here is a self contained version that counts down. Most of this is boiler plate. It uses a timer to decrement the bullet count.

The details are in the BulletCounter class.

  • it maintains the initial value for reset purposes.
  • counts down from right to left.
  • provides a method for seeing if any bullets are remaining.
  • provides a decrement method.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class BulletCounterDemo extends JPanel {
    
    public static void main(String[] args) {
        SwingUtilities
                .invokeLater(() -> new BulletCounterDemo().start());
    }
    
    public void start() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        BulletCounter bc = new BulletCounter(10);
        add(bc);
        f.setVisible(true);
        
        Timer timer = new Timer(1000, (ae) -> {
            bc.decrement();
            if (bc.expired())
                bc.reset();
        });
        timer.start();
    }
    
    public Dimension getPreferredSize() {
        return new Dimension(200, 40);
    }
}

class BulletCounter extends JComponent {
    private static int BULLET_WIDTH = 5;
    private static int BULLET_HEIGHT = 30;
    private int nBullets = 0;
    private int fixed = 0;
    
    public BulletCounter(int nBullets) {
        this.nBullets = nBullets;
        this.fixed = nBullets;
    }
    
    public void decrement() {
        if (nBullets >= 0) {
            nBullets--;
        }
        repaint();
    }
    
    public void reset() {
        nBullets = fixed;
        repaint();
    }
    
    public boolean expired() {
        return nBullets < 0;
    }
    
    public Dimension getPreferredSize() {
        return new Dimension(nBullets * 2 * BULLET_WIDTH,
                BULLET_HEIGHT);
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g = g.create();
        g.setColor(Color.BLACK);
        int x = 0;
        for (int i = 0; i <= nBullets; i  ) {
            g.fillRect(x, 1, BULLET_WIDTH, BULLET_HEIGHT);
            x = (i * 2) * BULLET_WIDTH;
        }
        if(nBullets <= 0) {
            g.setColor(getBackground());
            g.fillRect(0,0,getWidth(), getHeight());
        }
        
        
        g.dispose();
    }
    
}

Of course this is a bar bones version. You can add other methods as you require. For example:

  • to set background color
  • to set the dimensions and color of the bullets
  • Related