Several Changes and Updates.

This commit is contained in:
Aaron Helton
2017-07-18 00:22:39 -04:00
parent 8d56f8aae2
commit e5ec00c8a9
14 changed files with 487 additions and 168 deletions

View File

@@ -6,7 +6,7 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="1.8 (1)" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="docs" level="project" />
<orderEntry type="module-library">

9
.idea/codeStyleSettings.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value />
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -1,12 +1,10 @@
package com.aargonian.com.aargonian.tile;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.pcollections.HashPMap;
import org.pcollections.HashTreePMap;
import java.util.Map;
/**
* Created by aargonian on 7/4/17.
*/
@@ -19,106 +17,141 @@ public class TileImpl
public static final String PROPERTY_IMG = "ImageRef";
public static final String VALUE_TRUE = "True";
public static final String VALUE_FALSE = "False";
private final HashPMap<String, String> properties;
private final HashPMap<String, Object> resources;
private int hash = 0;
public TileImpl(Map<String, String> startingProperties, Map<String, Object> startingResources)
{
if(startingProperties != null && startingProperties.size() > 0)
{
this.properties = HashTreePMap.from(startingProperties);
else
this.properties = null;
if(startingResources != null && startingResources.size() > 0)
this.resources = HashTreePMap.from(startingResources);
else
this.resources = null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TileImpl tile = (TileImpl) o;
if (properties != null ? !properties.equals(tile.properties) : tile.properties != null) return false;
return resources != null ? resources.equals(tile.resources) : tile.resources == null;
}
@Override
public int hashCode() {
int result = hash;
if(result == 0) {
result = properties != null ? properties.hashCode() : 0;
result = 31 * result + (resources != null ? resources.hashCode() : 0);
hash = result;
}
return result;
else
{
this.properties = null;
}
if(startingResources != null && startingResources.size() > 0)
{
this.resources = HashTreePMap.from(startingResources);
}
else
{
this.resources = null;
}
}
private TileImpl(HashPMap<String, String> implProperties, HashPMap<String, Object> implResources)
{
this.properties = implProperties;
this.resources = implResources;
}
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(o == null || getClass() != o.getClass())
{
return false;
}
TileImpl tile = (TileImpl) o;
if(properties != null ? !properties.equals(tile.properties) : tile.properties != null)
{
return false;
}
return resources != null ? resources.equals(tile.resources) : tile.resources == null;
}
@Override
public int hashCode()
{
if(hash == 0)
{
int result = properties != null ? properties.hashCode() : 0;
result = 31 * result + (resources != null ? resources.hashCode() : 0);
hash = result;
}
return hash;
}
public TileImpl removeProperty(String property)
{
if(properties == null)
{
return this;
}
return new TileImpl(properties.minus(property), resources);
}
public String getProperty(String property)
{
if(properties == null)
{
return null;
}
return properties.get(property);
}
public TileImpl setProperty(String property, String value)
{
if(properties == null)
{
return new TileImpl(HashTreePMap.singleton(property, value), resources);
}
return new TileImpl(properties.plus(property, value), resources);
}
public boolean hasProperty(String property)
{
if(properties == null)
{
return false;
}
return properties.containsKey(property) && properties.get(property) != null;
}
public TileImpl removeResource(String resource)
{
if(resources == null)
{
return this;
}
return new TileImpl(properties, resources.minus(resource));
}
public Object getResource(String resource)
{
if(resources == null)
{
return null;
}
return resources.get(resource);
}
public TileImpl setResource(String resourceKey, Object resource)
{
if(resources == null)
{
return new TileImpl(properties, HashTreePMap.singleton(resourceKey, resource));
}
return new TileImpl(properties, resources.plus(resourceKey, resource));
}
public boolean hasResource(String resourceKey)
{
if(resources == null)
{
return false;
}
return resources.containsKey(resourceKey) && resources.get(resourceKey) != null;
}
}

View File

@@ -7,12 +7,11 @@ import java.util.ArrayList;
*/
public class TileMap
{
private int rows;
private int columns;
private final ArrayList<TileImpl> tilesImplementations;
private final Tile[] tiles;
private int rows;
private int columns;
public TileMap(int columns, int rows)
{
this.columns = columns;
@@ -26,24 +25,27 @@ public class TileMap
tiles[i] = new Tile(tilesImplementations.get(0));
}
}
public void addTileImplementation(TileImpl impl)
{
tilesImplementations.add(impl);
}
public ArrayList<TileImpl> getTileImplementations()
{
return tilesImplementations;
}
public int getRows() {
public int getRows()
{
return rows;
}
public int getColumns() {
public int getColumns()
{
return columns;
}
private final void setTileImplementation(Tile tile, TileImpl newImpl)
{
for(TileImpl implementation : tilesImplementations)
@@ -62,63 +64,71 @@ public class TileMap
tilesImplementations.add(newImpl);
tile.setTileImplementation(newImpl);
}
public String getTilePropertyAt(String property, int x, int y)
{
return tiles[(y * columns) + x].getTileImplementation().getProperty(property);
}
public void setTilePropertyAt(String property, String value, int x, int y)
{
Tile tile = tiles[(y*columns) + x];
Tile tile = tiles[(y * columns) + x];
TileImpl newImpl = tile.getTileImplementation().setProperty(property, value);
setTileImplementation(tile, newImpl);
}
public Object getTileResourceAt(String resource, int x, int y)
{
return tiles[(y*columns) + x].getTileImplementation().getResource(resource);
return tiles[(y * columns) + x].getTileImplementation().getResource(resource);
}
public void setTileResourceAt(String resourceKey, Object resource, int x, int y)
{
Tile tile = tiles[(y*columns)+x];
Tile tile = tiles[(y * columns) + x];
TileImpl newImpl = tile.getTileImplementation().setResource(resourceKey, resource);
setTileImplementation(tile, newImpl);
}
private final class Tile
{
private TileImpl implementation;
public Tile(TileImpl impl)
{
this.implementation = impl;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(o == null || getClass() != o.getClass())
{
return false;
}
Tile tile = (Tile) o;
return implementation.equals(tile.implementation);
}
@Override
public int hashCode() {
public int hashCode()
{
return implementation.hashCode();
}
public void setTileImplementation(TileImpl impl)
{
this.implementation = impl;
}
public TileImpl getTileImplementation()
{
return this.implementation;
}
public void setTileImplementation(TileImpl impl)
{
this.implementation = impl;
}
}
}

View File

@@ -0,0 +1,36 @@
package com.aargonian.com.aargonian.util;
/**
* Created by aargonian on 7/17/17.
*/
public class Pair<K, T>
{
private K first;
private T second;
public Pair(K first, T second)
{
this.first = first;
this.second = second;
}
public K getFirst()
{
return this.first;
}
public T getSecond()
{
return this.second;
}
public void setFirst(K first)
{
this.first = first;
}
public void setSecond(T second)
{
this.second = second;
}
}

View File

@@ -6,22 +6,23 @@ import java.util.List;
/**
* Created by aargonian on 7/13/17.
*
* The EditableTileSheet Class is an implementation for a collection of Tiles arranged within a Sheet, as used by the editing
* <p>
* The EditableTileSheet Class is an implementation for a collection of Tiles arranged within a Sheet, as used by the
* editing
* program. Although this can be thought of in the traditional TileSheet sense (and in fact, a TileSheet can be
* constructed from a TileSheetReader from an actual TileSheet image), the EditableTileSheet is mutable, and doesn't
* keep each tile instance as a subimage within a larger sheet, unless written out by a TileSheetWriter. Instead,
* individual tile images can be added or removed from the set at will.
*
*/
public class EditableTileSheet
{
/*
* An EditableTileSheet is the backing model for the TileSheets dock of the editor, and as such implements the Observer
* An EditableTileSheet is the backing model for the TileSheets dock of the editor, and as such implements the
* Observer
* pattern for the sake of a cleaner MVC implementation.
*/
private final List<Image> tileImages;
/**
* Creates an empty EditableTileSheet.
*/
@@ -29,7 +30,7 @@ public class EditableTileSheet
{
tileImages = new ArrayList<Image>();
}
public EditableTileSheet(List<Image> tileImages)
{
this.tileImages = tileImages;

View File

@@ -0,0 +1,45 @@
package com.aargonian.editor;
import java.awt.event.*;
/**
* Created by aargonian on 7/16/17.
*
* An EditorTool is an implementation of a Controller for the main EditableTileMap. EditorTools can be thought of very
* similarly to the "Tools" used by graphics editing programs. Each EditorTool gets access to the underlying TileMap
* model, and receives input events from the TileMapDisplay. It is the job of the EditorTool to translate these input
* events into corresponding actions on the underlying TileMap or in the TileMapDisplay.
*/
public class EditorTool implements MouseListener, MouseMotionListener, KeyListener
{
private final TileMapDisplay display;
public EditorTool(TileMapDisplay display)
{
if(display == null)
throw new NullPointerException("Given TileMapDisplay was Null!");
this.display = display;
}
protected TileMapDisplay getCurrentDisplay() { return this.display; }
@Override
public void keyTyped(KeyEvent e) { }
@Override
public void keyPressed(KeyEvent e) { }
@Override
public void keyReleased(KeyEvent e) { }
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseClicked(MouseEvent e) { }
@Override
public void mouseReleased(MouseEvent e) { }
@Override
public void mouseEntered(MouseEvent e) { }
@Override
public void mouseExited(MouseEvent e) { }
@Override
public void mouseDragged(MouseEvent e) { }
@Override
public void mouseMoved(MouseEvent e) { }
}

View File

@@ -1,53 +1,62 @@
package com.aargonian.editor;
import com.aargonian.com.aargonian.tile.TileImpl;
import com.aargonian.com.aargonian.tile.TileMap;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Created by aargonian on 7/8/17.
*/
public class GameFrame {
public class GameFrame
{
public static final String PROG_TITLE = "TileEditor 0.1.0";
public static void main(String[] args) {
public static void main(String[] args)
{
EventQueue.invokeLater(() ->
{
GameFrame.setupUI();
}
);
{
GameFrame.setupUI();
});
}
//TODO: Add an Icon Image
private static final JFrame setupFrame()
{
JFrame frame = new JFrame(PROG_TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
if(screenSize.width <= 1024 || screenSize.height <= 800) {
if(screenSize.width <= 1024 || screenSize.height <= 800)
{
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //maximize by default if the screen is really small
} else {
frame.setSize((int)Math.round(screenSize.width * 0.8), (int)Math.round(screenSize.height * 0.8));
}
else
{
frame.setSize((int) Math.round(screenSize.width * 0.8), (int) Math.round(screenSize.height * 0.8));
frame.setLocationRelativeTo(null); //Centers the frame
}
return frame;
}
/**
* Creates the pane that holds the different tile implementations the user may choose to put into the editor.
*
* @return The Tile Pane Component, Fully Constructed
*/
private static final JComponent setupTilesPanel()
{
throw new UnsupportedOperationException("Not Supported Yet.");
}
public static final void setupUI()
{
JFrame frame = setupFrame();
/*
TileMap map = new TileMap(10, 10);
map.setTileResourceAt(TileImpl.PROPERTY_IMG, ImageReader.readImage("res/Water.png"), 2, 2);
@@ -57,27 +66,19 @@ public class GameFrame {
.displaySize(640, 480)
.borderColor(Color.black);
TileMapDisplay currentTileMapDisplay = new TileMapDisplay(displayOptions);
currentTileMapDisplay.setCurrentTileMap(map);
currentTileMapDisplay.setCurrentActiveTool(new TileSelectTool(currentTileMapDisplay));
System.out.println("TILE MAP DISPLAY WIDTH: " + currentTileMapDisplay.getPreferredSize().getWidth());
System.out.println("TILE MAP DISPLAY HEIGHT: " + currentTileMapDisplay.getPreferredSize().getHeight());
frame.add(currentTileMapDisplay);
*/
ArrayList<Image> images = new ArrayList<>(6);
for(int i = 0; i < 20; i++)
{
images.add(ImageReader.readImage("res/Water.png"));
}
TilesetDisplay display = new TilesetDisplay(32, images);
frame.add(display);
frame.add(BorderLayout.CENTER, currentTileMapDisplay);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
/*
currentTileMapDisplay.repaint();
*/
}
}

View File

@@ -12,12 +12,6 @@ public class ImageReader
{
public static final BufferedImage readImage(String imagePath)
{
try {
BufferedImage img = ImageIO.read(new File(imagePath));
return img;
} catch(IOException ex) {
System.err.println("Exception Occurred: " + ex);
}
return null;
return ResourceLoader.loadImage(imagePath);
}
}

View File

@@ -0,0 +1,46 @@
package com.aargonian.editor;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Created by aargonian on 7/17/17.
*
* A utility class for loading and caching common resources used by the editor. Primarily used to load images and sound
* files.
*/
public final class ResourceLoader
{
private static final Map<String, Object> resourceCache = new HashMap<>(100);
public static final BufferedImage loadImage(String imagePath)
{
if(imagePath == null || imagePath.isEmpty())
return null;
if(resourceCache.containsKey(imagePath) && resourceCache.get(imagePath) != null)
return (BufferedImage)resourceCache.get(imagePath);
else
{
try
{
BufferedImage image = ImageIO.read(new File(imagePath));
resourceCache.put(imagePath, image);
return image;
}
catch(IOException ex)
{
System.err.println("Unable to load resource: " + imagePath);
System.err.println(ex);
for(StackTraceElement element : ex.getStackTrace())
{
System.err.println("\tat " + element);
}
return null;
}
}
}
}

View File

@@ -2,66 +2,127 @@ package com.aargonian.editor;
import com.aargonian.com.aargonian.tile.TileImpl;
import com.aargonian.com.aargonian.tile.TileMap;
import com.aargonian.com.aargonian.util.Pair;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;
/**
* Created by aargonian on 7/8/17.
*/
public class TileMapDisplay extends JComponent
{
private TileMap tileMap;
private final OptionsBuilder options;
private static final OptionsBuilder DEFAULT_OPTIONS =
new OptionsBuilder().borderColor(Color.black).displaySize(640, 480).tileSize(32, 32);
private final OptionsBuilder options;
private TileMap tileMap;
private EditorTool currentActiveTool;
private List<Pair<Integer, Integer>> selectedTiles;
public TileMapDisplay()
{
this.options = DEFAULT_OPTIONS;
}
public TileMapDisplay(OptionsBuilder options)
{
this.options = options;
this.setPreferredSize(new Dimension(options.displayWidth(), options.displayHeight()));
}
public OptionsBuilder getOptions()
{
return options;
}
public void setCurrentTileMap(TileMap map)
{
this.tileMap = map;
}
public TileMap getCurrentTileMap()
{
return this.tileMap;
}
public void paint(Graphics g)
public void setCurrentTileMap(TileMap map)
{
Graphics2D g2 = (Graphics2D)g;
this.tileMap = map;
}
public void setSelectedTiles(List<Pair<Integer, Integer>> tiles)
{
this.selectedTiles = tiles;
this.repaint();
}
public List<Pair<Integer, Integer>> getSelectedTiles()
{
return this.selectedTiles;
}
public EditorTool getCurrentActiveTool()
{
return this.currentActiveTool;
}
public void setCurrentActiveTool(EditorTool tool)
{
if(this.currentActiveTool != null)
{
this.removeMouseListener(currentActiveTool);
this.removeMouseMotionListener(currentActiveTool);
this.removeKeyListener(currentActiveTool);
}
this.currentActiveTool = tool;
this.addMouseListener(tool);
this.addMouseMotionListener(tool);
this.addKeyListener(tool);
}
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(options.borderColor());
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
for(int x = 0; x < tileMap.getColumns(); x++)
{
for(int y = 0; y < tileMap.getRows(); y++)
{
Image img = (Image)tileMap.getTileResourceAt(TileImpl.PROPERTY_IMG, x, y);
final int tileXLoc = x * options.tileWidth();
final int tileYLoc = y * options.tileHeight();
Image img = (Image) tileMap.getTileResourceAt(TileImpl.PROPERTY_IMG, x, y);
if(img != null)
g2.drawImage(img,
x*options.tileWidth(), y*options.tileHeight(), options.tileWidth(), options.tileHeight(),
null);
{
g2.drawImage(img, tileXLoc, tileYLoc, options.tileWidth(), options.tileHeight(), null);
}
else
{
GradientPaint defPaint = new GradientPaint(x*options.tileWidth(), y*options.tileHeight(),
Color.white, (x+1)*options.tileWidth(), (y+1)*options.tileHeight, Color.black);
g2.setPaint(defPaint);
g2.fillRect(x*options.tileWidth(), y*options.tileHeight(), options.tileWidth(), options.tileHeight());
final int HALF_WIDTH = options.tileWidth() / 2;
final int HALF_HEIGHT = options.tileHeight() / 2;
g2.setColor(Color.lightGray);
g2.fillRect(tileXLoc, tileYLoc, HALF_WIDTH, HALF_HEIGHT);
g2.fillRect(tileXLoc + HALF_WIDTH, tileYLoc + HALF_HEIGHT, HALF_WIDTH, HALF_HEIGHT);
g2.setColor(Color.gray);
g2.fillRect(tileXLoc, tileYLoc + HALF_HEIGHT, HALF_WIDTH, HALF_HEIGHT);
g2.fillRect(tileXLoc + HALF_WIDTH, tileYLoc, HALF_WIDTH, HALF_HEIGHT);
}
if(selectedTiles != null)
{
for(Pair<Integer, Integer> selectedTile : selectedTiles)
{
if(selectedTile.getFirst() == x && selectedTile.getSecond() == y)
{
g2.setColor(Color.YELLOW);
g2.fillRect(tileXLoc, tileYLoc, options.tileWidth(), options.tileHeight());
g2.setColor(Color.YELLOW.brighter());
g2.fillRect(tileXLoc + 2, tileYLoc + 2, options.tileWidth() - 2, options.tileHeight() - 2);
}
}
}
}
}
@@ -75,58 +136,81 @@ public class TileMapDisplay extends JComponent
private int displayHeight = 480;
private Color borderColor = Color.black;
private boolean fullscreen = false;
public OptionsBuilder tileWidth(int width)
{
this.tileWidth = width <= 0 ? 0 : width;
return this;
}
public OptionsBuilder tileHeight(int height)
{
this.tileHeight = height <= 0 ? 0 : height;
return this;
}
public OptionsBuilder tileSize(int width, int height)
{
return this.tileWidth(width).tileHeight(height);
}
public OptionsBuilder borderColor(Color c)
{
this.borderColor = c;
return this;
}
public OptionsBuilder displayWidth(int width)
{
this.displayWidth = width <= 0 ? 0 : width;
return this;
}
public OptionsBuilder displayHeight(int height)
{
this.displayHeight = height <= 0 ? 0 : height;
return this;
}
public OptionsBuilder displaySize(int width, int height)
{
return this.displayWidth(width).displayHeight(height);
}
public OptionsBuilder fullscreen(boolean value)
{
this.fullscreen = value;
return this;
}
public int tileWidth() { return tileWidth; }
public int tileHeight() { return tileHeight; }
public int displayWidth() { return displayWidth; }
public int displayHeight() { return displayHeight; }
public Color borderColor() { return borderColor; }
public boolean fulllscreen() { return fullscreen; }
public int tileWidth()
{
return tileWidth;
}
public int tileHeight()
{
return tileHeight;
}
public int displayWidth()
{
return displayWidth;
}
public int displayHeight()
{
return displayHeight;
}
public Color borderColor()
{
return borderColor;
}
public boolean fulllscreen()
{
return fullscreen;
}
}
}

View File

@@ -0,0 +1,44 @@
package com.aargonian.editor;
import com.aargonian.com.aargonian.tile.TileImpl;
import com.aargonian.com.aargonian.util.Pair;
import java.awt.event.MouseEvent;
import java.util.Arrays;
/**
* Created by aargonian on 7/16/17.
*/
public class TileSelectTool extends EditorTool
{
private int currentTileX = 0;
private int currentTileY = 0;
public TileSelectTool(TileMapDisplay display)
{
super(display);
}
@Override
public void mouseClicked(MouseEvent e)
{
int tileX = e.getX()/super.getCurrentDisplay().getOptions().tileWidth();
int tileY = e.getY()/super.getCurrentDisplay().getOptions().tileHeight();
//getCurrentDisplay().setSelectedTiles(Arrays.asList(new Pair<Integer, Integer>(tileX, tileY)));
getCurrentDisplay().getCurrentTileMap().setTileResourceAt(TileImpl.PROPERTY_IMG, ImageReader.readImage("res/Water.png"), tileX, tileY);
getCurrentDisplay().repaint();
}
@Override
public void mouseMoved(MouseEvent e)
{
int tileX = e.getX()/super.getCurrentDisplay().getOptions().tileWidth();
int tileY = e.getY()/super.getCurrentDisplay().getOptions().tileHeight();
if(tileX != currentTileX || tileY != currentTileY)
{
currentTileX = tileX;
currentTileY = tileY;
}
}
}

View File

@@ -6,43 +6,53 @@ import java.util.ArrayList;
/**
* Created by aargonian on 7/9/17.
*
* <p>
* This class implements a display for a set of tiles.
*/
public final class TilesetDisplay extends JComponent
{
private final ArrayList<Image> images;
private int tileSize;
public TilesetDisplay(int tileSize, ArrayList<Image> tileImages)
{
if(tileImages == null)
{
throw new NullPointerException("Passed Image Set is Null.");
}
this.images = tileImages;
this.tileSize = tileSize;
//TODO: Remove this later?
int squareSize = ((int) (Math.sqrt(tileImages.size()))) * tileSize;
this.setPreferredSize(new Dimension(squareSize, squareSize));
}
public void addImageToDisplay(Image img)
{
images.add(img);
this.repaint();
}
public void removeImageFromDisplay(Image img)
{
images.remove(img);
this.repaint();
}
//Todo: Update this to use a scrollpane and avoid divide by zero.
@Override
public void paintComponent(Graphics g)
{
g.setColor(Color.gray);
g.fillRect(0,0, getWidth(), getHeight());
int columns = (int)(getWidth()/tileSize);
if(columns != 0) { // Avoid divide by zero and simply display nothing.
for (int i = 0; i < images.size(); i++) {
g.drawImage(images.get(i),
(i % columns) * tileSize, ((int) (i / columns)) * tileSize, tileSize, tileSize, null);
g.fillRect(0, 0, getWidth(), getHeight());
int columns = (int) (getWidth() / tileSize);
if(columns != 0) // Avoid divide by zero and simply display nothing.
{
for(int i = 0; i < images.size(); i++)
{
g.drawImage(images.get(i), (i % columns) * tileSize, ((int) (i / columns)) * tileSize, tileSize,
tileSize, null);
}
}
}