Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Double Buffering for Sprites without using Graphics class

Options
  • 07-03-2014 2:49pm
    #1
    Registered Users Posts: 5,540 ✭✭✭


    Hi,

    Im creating an app with a number of movable bitmaps on a canvas. Problem with it is that the Sprites do not all display in one go. More annoyingly, those that do appear flicker/blink constantly.

    After a chat with a mate, there is a known approach to this called double buffering. However, by the looks of this, i would have to use the Graphics class. I'm not sure whether this is particularly interchangeable with what i use for code. See bwlow anyways.



    package x.y.z;
    
    import java.io.ByteArrayOutputStream;
    import java.util.Random;
    
    import android.annotation.SuppressLint;
    import android.graphics.Bitmap;
    import android.graphics.Color;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    
    import android.graphics.Canvas;
    
    import android.graphics.Rect;
    
     
    
    public class Sprite {
    
           // direction = 0 up, 1 left, 2 down, 3 right,
    
           // animation = 3 back, 1 left, 0 front, 2 right
    
           int[] DIRECTION_TO_ANIMATION_MAP = { 3, 1, 0, 2};
    
           private static final int BMP_ROWS = 4;
    
           private static final int BMP_COLUMNS = 3;
    
           private static final int MAX_SPEED = 100;
    
           private GameView gameView;
    
           private Bitmap bmp;
    
           private int x = 0;
    
           private int y = 0;
    
           private int xSpeed;
    
           private int ySpeed;
    
           private int currentFrame = 0;
    
           private int width;
    
           private int height;
    
     
    
           public Sprite(GameView gameView, Bitmap bmp) {
        	   ByteArrayOutputStream out = new ByteArrayOutputStream();
        	   	bmp.compress(Bitmap.CompressFormat.JPEG, 100, out);
    
                 this.width = bmp.getWidth() / BMP_COLUMNS * 4;
    
                 this.height = bmp.getHeight() / BMP_ROWS * 6;
    
                 this.gameView = gameView;
    
                 this.bmp = bmp;
    
     
    
                 Random rnd = new Random();
    
                 x = rnd.nextInt(gameView.getWidth() - width);
    
                 y = rnd.nextInt(gameView.getHeight() - height);
    
                 xSpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
    
                 ySpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
    
           }
    
     
    
           private void update() {
    
                 if (x >= gameView.getWidth() - width - xSpeed || x + xSpeed <= 0) {
    
                        xSpeed = -xSpeed;
    
                 }
    
                 x = x + xSpeed;
    
                 if (y >= gameView.getHeight() - height - ySpeed || y + ySpeed <= 0) {
    
                        ySpeed = -ySpeed;
    
                 }
    
                 y = y + ySpeed;
    
                 currentFrame = ++currentFrame % BMP_COLUMNS;
    
           }
    
     
    
    	public void onDraw(Canvas canvas) {
    
                 update();
                 
                 int width = bmp.getWidth();
                 int height = bmp.getHeight(); 
    
                 int newWidth = width / 2;
                 int newHeight = height / 2;
                 float scaleWidth = ((float) newWidth) / width;
                 float scaleHeight = ((float) newHeight) / height;
                 Matrix matrix = new Matrix();
                 matrix.postScale(scaleWidth, scaleHeight);
                 Bitmap resizedBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true); 
                 
                 int srcX = currentFrame * width;
    
                 int srcY = getAnimationRow() * height;
    
                 Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
    
                 Rect dst = new Rect(x, y, x + width, y + height);
                 
                 canvas.drawBitmap(resizedBitmap, src, dst, null);
                 
     
           }
    
     
    
           private int getAnimationRow() {
    
                 double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
    
                 int direction = (int) Math.round(dirDouble) % BMP_ROWS;
    
                 return DIRECTION_TO_ANIMATION_MAP[direction];
    
           }
    
     
    
           public boolean isCollision(float x2, float y2) {
    
                 return x2 > x && x2 < x + width && y2 > y && y2 < y + height; 
    
           }
    
    }
    


Comments

  • Closed Accounts Posts: 8,016 ✭✭✭CreepingDeath


    I haven't written any Android code but have experience with a lot of Graphics programming in general and in Java have wrote a bit of Swing graphics components.
    Bitmap resizedBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true);
    

    You don't want to create a new bitmap every time you want to draw something on the screen.

    Ideally you only want to create the one bitmap/canvas, and reuse it.

    This is some old code I had, which created a Swing component which implemented double buffering.

    So "m_VirtScreen" is an invisible bitmap/buffer, that I write too, and only when everything is drawn on this buffer do I draw the entire image to the screen.

    So elsewhere I call Graphics2D getVirtualGraphics() to get the buffer. I write to it, and the component draws the buffer automatically on a paint event.

    package gravity.view;
    
    import java.awt.Color;
    import java.awt.event.ComponentListener; // Resize event listener
    import java.awt.event.ComponentEvent; // Resize event info
    
    import javax.swing.JComponent;
    import java.awt.Image;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Dimension;
    
    
    public abstract class JGraphicsPanel extends JComponent implements ComponentListener
    {
        private static final long serialVersionUID = 1L;
    
        protected Dimension   m_ClientRect;
        protected int         m_width, m_height;
        protected Image       m_VirtScreen   = null;
        protected Graphics2D  m_VirtGraphics = null;
    
        protected int m_MidX = 0;
        protected int m_MidY = 0;
    
        public JGraphicsPanel ( )
        {
            super();
            initialise();
        }
    
        public JGraphicsPanel ( int initHeight, int initWidth )
        {
            super();
            setSize(initHeight, initWidth);
            initialise();
        }
    
    
     
        private void initialise()
        {
            this.setAutoscrolls(false);
            this.setLayout(null);
            this.setToolTipText("");
            this.setMinimumSize(new Dimension(50, 50));
            this.setDoubleBuffered(false);
            this.setBackground(Color.BLACK);
            this.setOpaque(true);
            
            m_ClientRect = getSize();
            m_width = m_ClientRect.width;
            m_height = m_ClientRect.height;
    
            try
            {
                m_VirtScreen = createImage(m_width, m_height);
                m_VirtGraphics = (Graphics2D)m_VirtScreen.getGraphics();
            }
            catch (Exception e)
            {
                // problem creating off-screen memory image of the panel
                m_VirtScreen = null;
                m_VirtGraphics = null;
            }
    
            addComponentListener(this); // resize our memory image with the panel
        }
    
        public abstract void onResize();
    
        public void componentResized(ComponentEvent resizeEvent)
        {
            m_ClientRect = getSize();
    
            // avoid attempts to resize to the current size
            if ((m_width != m_ClientRect.width) || (m_height != m_ClientRect.height))
            {
                m_width = m_ClientRect.width;
                m_height = m_ClientRect.height;
    
                try
                {
                    if (m_VirtScreen != null)
                        m_VirtScreen.flush(); // free allocated memory
    
                    m_VirtScreen = createImage(m_width, m_height);
                    m_VirtGraphics = (Graphics2D)m_VirtScreen.getGraphics();
                }
                catch (Exception e)
                {
                    m_VirtScreen = null;
                    m_VirtGraphics = null;
                }
            }
            
            m_MidX = m_width >> 1;
            m_MidY = m_height >> 1;
            
            onResize();
        }
    
    
        public abstract void onHide();
    
        public void componentHidden(ComponentEvent e)
        {
            onHide();
        }
    
        
        public abstract void onMove();
    
        public void componentMoved(ComponentEvent e)
        {
            onMove();
        }
    
        
        public abstract void onShow();
    
        public void componentShown(ComponentEvent e)
        {
            onShow();
        }
    
    
        public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
        {
            return (true);
        }
    
        public Graphics2D getVirtualGraphics()
        {
            if (m_VirtGraphics != null)
                return (m_VirtGraphics);
            else
                return ((Graphics2D)getGraphics());
        }
        
        public void paint(Graphics g)
        {
            g.drawImage(m_VirtScreen, 0, 0, this);
        }
    
    }
    


Advertisement