0

I am making a tile based Game, i generate a random map using perlin's noise. When my map is 100 * 100 tiles it works fine but when my map is 1000 * 1000 tiles i get performance issues, I solved most of these by checking if my tiles were in the camera's view than drawing them but it is still buggy. Here is some of my code :

Loading

void loadMap(int size)
{
    blocks.clear();
    float[][] seed1 =  Perlin.GenerateWhiteNoise(size, size);
    float[][] seed = Perlin.GenerateSmoothNoise(seed1, 3);
    for (int i = 0; i < seed.length; i++)
    {
        for ( int j = 0; j < seed[i].length; j++)
        {
            if(seed[i][j] < 0.5)
            {
                blocks.add(new Block(i * Block.blockSize, j * Block.blockSize, eBlockType.WATER));
            }

            else if(seed[i][j] > 0.8)
            {
                blocks.add(new Block(i * Block.blockSize, j * Block.blockSize, eBlockType.GRASS));
            }

            else
            {
                blocks.add(new Block(i * Block.blockSize, j * Block.blockSize, eBlockType.SAND));
            }
        }
    }
}

Drawing

public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    cameraX = -player.getX() + getWidth()/2;
    cameraY = -player.getY() + getHeight()/2;
    g.translate(cameraX, cameraY);
    for(Block block : blocks)
    {
        //System.out.println(block.getX() + " " + cameraX);
        Rectangle cameraView = new Rectangle(-(cameraX+cameraPadding), -(cameraY+cameraPadding), this.getWidth()+cameraPadding , this.getHeight()+cameraPadding);
        if(cameraView.contains(block.getX(), block.getY()))
        {
            block.draw(g2);
        }

        else if(block.getX() > cameraView.getMaxX() && block.getY() > cameraView.getMaxY())
        {
            break;
        }
    }

    player.draw(g2);
}

Block Class

package com.ymail.sanchixx.game;

import java.awt.Graphics;
import java.awt.Rectangle;

public class Block
{

    enum eBlockType
    {
        NULL(-1), STONE(0), STONEBRICK(1), // these are collision
        COLLISION_BLOCKS(2), // PlaceHolder
        GRASS(3), PLANK(4), WATER(5), SAND(6); // these are non-collision

        private int code;

        eBlockType(int c) 
        {
            code = c;
        }

        public int getCode() 
        {
            return code;
        }
    };

    eBlockType m_type = eBlockType.NULL;
    int m_x;
    int m_y;
    static int blockSize = 16;

    Block(int x, int y, eBlockType type)
    {
        m_x = x;
        m_y = y;
        m_type = type;
    }

    boolean isNonCollisionBlock()
    {
        if(m_type.getCode() > eBlockType.COLLISION_BLOCKS.getCode())
        {
            return true;
        }

        return false;
    }

    static boolean collisionDown(Entity e, int v)
    {
        Rectangle player = new Rectangle(e.getX(), e.getY() + v, e.getWidth(), e.getHeight());
        for(Block i : Game.blocks)
        {
            if(!i.isNonCollisionBlock())
            {
                int blockWidth = blockSize;
                int blockHeight = blockSize;
                Rectangle block = new Rectangle(i.getX(), i.getY(), blockWidth, blockHeight);
                if (player.intersects(block))
                {
                    e.setY(e.getY() - (e.getY() - (i.getY() - e.getHeight())));
                    return true;
                }
            }
        }
        return false;
    }

    static boolean collisionUp(Entity e, int v)
    {
        Rectangle player = new Rectangle(e.getX(), e.getY() -v, e.getWidth(), e.getHeight());
        for(Block i : Game.blocks)
        {
            if(!i.isNonCollisionBlock())
            {
                int blockWidth = blockSize;
                int blockHeight = blockSize;
                Rectangle block = new Rectangle(i.getX(), i.getY(), blockWidth, blockHeight);
                if (player.intersects(block))
                {
                    e.setY(e.getY() - (e.getY() - (i.getY())) + blockHeight);
                    return true;
                }
            }
        }
        return false;
    }

    static boolean collisionRight(Entity e, int v)
    {
        Rectangle player = new Rectangle(e.getX() + v, e.getY(), e.getWidth(), e.getHeight());
        for(Block i : Game.blocks)
        {
            if(!i.isNonCollisionBlock())
            {
                int blockWidth = blockSize;
                int blockHeight = blockSize;
                Rectangle block = new Rectangle(i.getX(), i.getY(), blockWidth, blockHeight);
                if (player.intersects(block))
                {
                    e.setX(e.getX() - (e.getX() - (i.getX() - e.getWidth())));
                    return true;
                }
            }
        }
        return false;
    }

    static boolean collisionLeft(Entity e, int v)
    {
        Rectangle player = new Rectangle(e.getX() - v, e.getY(), e.getWidth(), e.getHeight());
        for(Block i : Game.blocks)
        {
            if(!i.isNonCollisionBlock())
            {
                int blockWidth = blockSize;
                int blockHeight = blockSize;
                Rectangle block = new Rectangle(i.getX(), i.getY(), blockWidth, blockHeight);
                if (player.intersects(block))
                {
                    e.setX(e.getX() - (e.getX() - (i.getX())) + e.getWidth());
                    return true;
                }
            }
        }
        return false;
    }

    static Boolean swimmingInBlock(Entity e, eBlockType type)
    {
        Rectangle player = new Rectangle(e.getX(), e.getY() + e.getHeight()/2, e.getWidth(), e.getHeight()/2);
        for(Block i : Game.blocks)
        {
            if(i.isNonCollisionBlock())
            {
                int blockWidth = blockSize;
                int blockHeight = blockSize;
                Rectangle block = new Rectangle(i.getX(), i.getY(), blockWidth, blockHeight);
                if (player.intersects(block))
                {
                    if(i.getType() != type)
                    {
                        return false;
                    }
                }
            }
        }

        return true;
    }

    eBlockType getType()
    {
        return m_type;
    }

    int getX()
    {
        return m_x;
    }

    int getY()
    {
        return m_y;
    }

    void draw(Graphics g)
    {
        switch(m_type)
        {
        case GRASS:
            g.drawImage(Game.blockImg[0], m_x, m_y, null);
            break;
        case WATER:
            g.drawImage(Game.blockImg[4], m_x, m_y, null);
            break;
        case SAND:
            g.drawImage(Game.blockImg[6], m_x, m_y, null);
            break;
        case STONE:
            g.drawImage(Game.blockImg[1], m_x, m_y, null);
            break;

        default:
            break;
        }
    }
}

Thank you

sanchixx
  • 275
  • 2
  • 5
  • 12

1 Answers1

1

You're still visiting N2 tiles to test for visibility, even if you choose to render only certain tiles. Instead, use the flyweight pattern to render only visible tiles, where visibility can be determined solely by panel/tile geometry. The approach, outlined here, is used to optimize JTable.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045