How do I apply different textures to multiple polygons in LWJGL? - java

I am drawing a grid of hexagon tiles. I have six different images that I want to use as the fill for these tiles. I use my hexagon class to loop through each point in the tile. The textures are stored in an array list which is then shuffled into a random order. The problem with my script right now is that the same texture is applied to each tile. What am I doing wrong?
public class LWJGLHelloWorld {
public static int SCREEN_WIDTH;
public static int SCREEN_HEIGHT;
public static int WINDOW_WIDTH;
public static int WINDOW_HEIGHT;
public double WIDTH;
public double HEIGHT;
public ArrayList<Hexagon> hexagons = new ArrayList<Hexagon>();
public ArrayList<String> resources = new ArrayList<String>();
public Texture brick;
public Texture stone;
public Texture lumber;
public Texture wool;
public Texture wheat;
public Texture wasteland;
private static enum State {
INTRO, MAIN_MENU, GAME;
}
private State state = State.INTRO;
public LWJGLHelloWorld(){
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double SCREEN_WIDTH = screenSize.getWidth();
double SCREEN_HEIGHT = screenSize.getHeight();
double WIDTH = SCREEN_WIDTH * .85;
double HEIGHT = SCREEN_HEIGHT * .85;
try {
Display.setDisplayMode(new DisplayMode((int)WIDTH, (int)HEIGHT));
Display.setTitle("Hello, LWJGL!");;
Display.create();
} catch (LWJGLException e){
e.printStackTrace();
}
resetResources();
brick = loadTexture("brick");
stone = loadTexture("stone");
lumber = loadTexture("lumber");
//Texture wheat = loadTexture("wheat");
wool = loadTexture("wool");
wasteland = loadTexture("wasteland");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
int originX = (int)(Display.getDisplayMode().getWidth() / 2);
int originY = (int)(Display.getDisplayMode().getHeight() / 2);
int radius = (int)(HEIGHT * .1);
int padding = (int)(HEIGHT * .005);
findHexCoords(originX, originY, 5, radius, padding);
while(!Display.isCloseRequested()){
glClear(GL_COLOR_BUFFER_BIT);
for(int h = 0; h < hexagons.size(); h++){
String rsrc = resources.get(h);
bindTexture(rsrc);
glBegin(GL_POLYGON);
Hexagon hex = hexagons.get(h);
for(int p = 0; p < hex.points.length; p++){
Point point = hex.points[p];
glTexCoord2f(point.x, point.y);
glVertex2f(point.x, point.y);
}
glEnd();
}
Display.update();
Display.sync(60);
}
Display.destroy();
}
private void bindTexture(String rsrc){
switch(rsrc){
case "brick":
brick.bind();
break;
case "stone":
stone.bind();
break;
case "lumber":
lumber.bind();
break;
case "wheat":
//wheat.bind();
break;
case "wool":
wool.bind();
break;
case "wasteland":
wasteland.bind();
break;
}
}
private void findHexCoords(int x, int y, int size, int radius, int padding) {
Point origin = new Point(x, y);
double ang30 = Math.toRadians(30);
double xOff = Math.cos(ang30) * (radius + padding);
double yOff = Math.sin(ang30) * (radius + padding);
int half = size / 2;
int i = 0;
for (int row = 0; row < size; row++) {
int cols = size - Math.abs(row - half);
for (int col = 0; col < cols; col++) {
int xLbl = row < half ? col - row : col - half;
int yLbl = row - half;
int centerX = (int) (origin.x + xOff * (col * 2 + 1 - cols));
int centerY = (int) (origin.y + yOff * (row - half) * 3);
Hexagon hex = new Hexagon(centerX, centerY, radius);
System.out.println(centerX+","+centerY);
hexagons.add(hex);
i++;
}
}
}
private Texture loadTexture(String key){
try {
return TextureLoader.getTexture("PNG", new FileInputStream(new File("img/" + key + ".png")));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
new LWJGLHelloWorld();
}
public void resetResources(){
resources.clear();
resources.add("Brick");
resources.add("Brick");
resources.add("Brick");
resources.add("Wool");
resources.add("Wool");
resources.add("Wool");
resources.add("Wool");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Stone");
resources.add("Stone");
resources.add("Stone");
resources.add("Wheat");
resources.add("Wheat");
resources.add("Wheat");
resources.add("Wheat");
long seed = System.nanoTime();
Collections.shuffle(resources, new Random(seed));
int randomIndex = ThreadLocalRandom.current().nextInt(0, 19);
resources.add(randomIndex, "Wasteland");
for(int r = 0; r < resources.size(); r++){
System.out.println(resources.get(r));
}
}

The first letter of the strings that you are adding in resources is uppercase (e.g. Brick).
In the bindTexture switch you are searching strings from resources that have a lowercase first letter (e.g. brick). Therefore the switch should always fail and not able to bind the correct texture.
Either fix the switch or the resources array accordingly.

Related

Problem with keypressed when drawing a square

I am trying to add a square to the canvas when a mouse key is pressed and i want it to remain on the canvas when the mouse key is released, but it disappears when is released the key. Can anybody help me, what am i doing wrong?
int squareSize = 6;
final float DIFF_SIZE = 1;
final int MIN_COLOUR = 1;
final int MAX_COLOUR = 10;
final float INIT_RED = 100, INIT_GREEN = 50, INIT_BLUE = 80;
final float FINAL_RED = 255, FINAL_GREEN = 200, FINAL_BLUE = 250;
final float MAX_SIZE = 40;
final float X_SPACING = 10;
final float Y_SPACING = 10;
float squareX, squareY;
void setup() {
size(600, 600);
}
void draw() {
squareX = mouseX - squareSize / 2;
squareY = mouseY - squareSize / 2;
background(255);
drawRowsOfBlocks();
}
void drawOneBlock() {
rect(squareX, squareY, squareSize, squareSize);
for (int i = MIN_COLOUR; mousePressed && i <= MAX_COLOUR / 10; i++)
{
float redValue = INIT_RED + (i - MIN_COLOUR) / (MAX_COLOUR - MIN_COLOUR)(FINAL_RED - INIT_RED);
float greenValue = INIT_GREEN + (i - MIN_COLOUR) / (MAX_COLOUR - MIN_COLOUR)(FINAL_GREEN - INIT_GREEN);
float blueValue = INIT_BLUE + (i - MIN_COLOUR) / (MAX_COLOUR - MIN_COLOUR) * (FINAL_BLUE - INIT_BLUE);
fill(redValue, greenValue, blueValue);
rect(squareX, squareY, squareSize, squareSize);
squareSize += DIFF_SIZE;
}
if (squareSize > MAX_SIZE) {
squareSize = 6;
}
}
void drawRowsOfBlocks() {
drawOneBlock();
for (int i = 1; keyPressed && i <= 2; i++) {
drawOneBlock();
float squareY2;
squareY2 = squareY + squareSize + Y_SPACING;
squareY = squareY2;
}
}
Create a class which can handle a rectangle. The calls needs a method to draw the rectangle (Draw()) and a method to update the position and size of the rectangle (Update()):
final int DIFF_SIZE = 1;
final int MIN_SIZE = 6;
final int MAX_SIZE = 40;
final float INIT_RED = 100, INIT_GREEN = 50, INIT_BLUE = 80;
final float FINAL_RED = 255, FINAL_GREEN = 200, FINAL_BLUE = 250;
class Rectangle {
int pos_x, pos_y, size;
color col;
Rectangle(int px, int py, int s, color c) {
col = c;
pos_x = px; pos_y = py;
size = s;
}
void Update(int px, int py, int inc_size) {
pos_x = px; pos_y = py;
size += inc_size;
if (size > MAX_SIZE)
size = MIN_SIZE;
float w = float(size - MIN_SIZE) / float(MAX_SIZE - MIN_SIZE);
float redValue = INIT_RED + w * (FINAL_RED - INIT_RED);
float greenValue = INIT_GREEN + w * (FINAL_GREEN - INIT_GREEN);
float blueValue = INIT_BLUE + w * (FINAL_BLUE - INIT_BLUE);
col = color(int(redValue), int(greenValue), int(blueValue));
}
void Draw() {
fill(col);
rect(pos_x-size/2, pos_y-size/2, size, size);
}
}
Use ArrayList to store all the drawn rectangles:
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
Add a global, boolean state (drawingRect) which indicates if the mouse button is currently pressed. Set the state and add new rectangle at the end of the list when the mousePressed() event occurs. rest the state when the mouseReleased() event occurs
boolean drawingRect = false;
void mousePressed() {
drawingRect = true;
color col = color(int(INIT_RED), int(INIT_GREEN), int(INIT_BLUE));
rectangles.add(new Rectangle(mouseX, mouseY, MIN_SIZE, col));
}
void mouseReleased() {
drawingRect = false;
}
Use the method .Update(), to change the location and size of the last rectangle in the list as long as the state drawingRect indicates that a mouse button is pressed.
Continuously draw all te rectangles in a loop:
void setup() {
size(600, 600);
}
void draw() {
if (drawingRect && rectangles.size() > 0) {
Rectangle lastRect = rectangles.get(rectangles.size()-1);
lastRect.Update(mouseX, mouseY, DIFF_SIZE);
}
background(255);
for (int i = 0; i < rectangles.size(); i++) {
Rectangle rect = rectangles.get(i);
rect.Draw();
}
}

How to add click events to a 2D array of tiles objects in Java

I am creating a 2D turn-based Star Wars game where the player has to move from tile to tile in a grid system, all the while avoiding enemies (I know, exciting stuff right!!). The grid is a 2D Array of Tiles, which are objects that I created using Slick and Light-Weight Java Game Library (lwjgl) so that I could add texture to them. I'm pretty new to all of this, and I'm trying to add click listeners to my tiles (or TileGrid?) so that when I click on a tile the player will move there, but I'm having no luck thus far. If any one could help in this matter they will receive my heartfelt thank you and 50% of the game rights when I sell the game to LucasArts!
Getters and Setters omitted
Tile Class
public class Tile {
private float x, y, width, height;
private Texture texture;
private TileType type;
public Tile(float x, float y, float width, float height, TileType type) {
setX(x);
setY(y);
setWidth(width);
setHeight(height);
setType(type);
setTexture(quickLoad(type.textureName));
}
public void draw() {
drawQuadTex(texture, x, y, width, height);
}
}
TileGrid Class
public class TileGrid extends JFrame {
public Tile[][] map;
public TileGrid() {
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
map = new Tile[width][height];
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
map[i][j] = new Tile(i * 64, j * 64, 64, 64, TileType.Space1);
}
}
}
public static int[][] randomGridGenerator() {
Random random = new Random();
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
int[][] map = new int[width][height];
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
int randInt = random.nextInt(20) + 1;
map[i][j] = randInt;
}
}
return map;
}
public TileGrid(int[][] newMap) {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
System.out.println(x + ", " + y);
}
});
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
map = new Tile[width][height];
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
switch (newMap[i][j]) {
case 1:
map[i][j] = new Tile(i * 64, j * 64, 64, 64, TileType.Space1);
break;
case 2:
map[i][j] = new Tile(i * 64, j * 64, 64, 64, TileType.Space2);
break;
}
}
}
}
public void setTile(int xCoord, int yCoord, TileType type) {
map[xCoord][yCoord] = new Tile(xCoord * 64, yCoord * 64, 64, 64, type);
}
public Tile getRandomTile() {
Random rand = new Random();
int width = Artist.getGridWidth();
int height = Artist.getGridHeight();
int x = rand.nextInt(width) ;
int y = rand.nextInt(height);
return map[x][y];
}
public Tile getTile(int xCoord, int yCoord) {
return map[xCoord][yCoord];
}
public void draw() {
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[i].length; j++) {
Tile t = map[i][j];
drawQuadTex(t.getTexture(), t.getX(), t.getY(), t.getWidth(), t.getHeight());
}
}
}
TileType Class
public enum TileType {
Space1("space64-1"), Space2("space64-2"), Space3("space64-3"), Space4("space64-4"), Space5("space64-5"),
Space6("space64-6"), Space7("space64-7"), Space8("space64-8"), Space9("space64-9"), Space10("space64-10"),
Space11("space64-11"), Space12("space64-12"), Space13("space64-13"), Space14("space64-14"), Space15("space64-15"),
Space16("space64-16"), Space17("space64-17"), Space18("space64-18"), Space19("space64-19"), Space20("space64-20");
String textureName;
TileType(String textureName) {
this.textureName = textureName;
}
}
Player Class
public class Player extends SpaceShip {
private TileGrid grid;
private int width, height, health;
float x, y;
private Texture texture;
private Tile locationTile;
/*
public Player(Texture texture, Tile startTile, int width, int height) {
setTexture(texture);
setX(startTile.getX());
setY(startTile.getY());
setWidth(width);
setHeight(height);
}
*/
public Player(Texture texture, TileGrid grid, int width, int height) {
setTexture(texture);
Tile tile = grid.getRandomTile();
setLocationTile(tile);
setX(tile.getX());
setY(tile.getY());
setWidth(width);
setHeight(height);
setGrid(grid);
}
public void movePlayer() {
int height = Artist.getHeight();
Tile newLocation = grid.getTile((int) Math.floor(Mouse.getX() / 64), (int) Math.floor((height - Mouse.getY() - 1)/ 64));
setLocationTile(newLocation);
setX(newLocation.getX());
setY(newLocation.getY());
}
public void draw() {
drawQuadTex(texture, x, y, width, height);
}
Entry Point
public class Boot {
public Boot() {
beginSession();
int[][] map = randomGridGenerator();
TileGrid grid = new TileGrid(map);
// Player p = new Player(quickLoad("x-wing"), grid.getTile(10, 10), 64, 64);
Player p = new Player(quickLoad("x-wing"), grid, 64, 64);
while(!Display.isCloseRequested()) {
grid.draw();
p.draw();
//p.movePlayer();
Display.update();
Display.sync(60);
}
Display.destroy();
}
public static void main(String[] args) {
new Boot();
}
}
}
Artist Class (for rendering etc.)
public class Artist {
public static final int WIDTH = 1280, HEIGHT = 960;
public static final int GRID_WIDTH = 20, GRID_HEIGHT = 15;
public static void beginSession() {
Display.setTitle("Star Wars");
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
public static void drawQuad(float x, float y, float width, float height) {
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x + width, y);
glVertex2f(x + width, y + height);
glVertex2f(x, y + height);
glEnd();
}
public static void drawQuadTex(Texture tex, float x, float y, float width, float height) {
tex.bind();
glTranslatef(x, y, 0);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(width, 0);
glTexCoord2f(1, 1);
glVertex2f(width, height);
glTexCoord2f(0, 1);
glVertex2f(0, height);
glEnd();
glLoadIdentity();
}
public static Texture loadTexture(String path, String fileType) {
Texture tex = null;
InputStream in = ResourceLoader.getResourceAsStream(path);
try {
tex = TextureLoader.getTexture(fileType, in);
} catch (IOException e) {
e.printStackTrace();
}
return tex;
}
public static Texture quickLoad(String name) {
Texture tex = null;
tex = loadTexture("resources/" + name + ".png", "PNG");
return tex;
}
In my attempt above the event should just return the coordinates when I click on it. My intention is to complete the player move logic once I've set up the event listener. All help appreciated.

How to more realistically simulate light on a sphere?

I am attempting to simulate a sphere, and shade it realistically given an origin vector for the light, and the sphere being centered around the origin. Moreover, the light's vector is the normal vector on a larger invisible sphere at a chosen point. The sphere looks off.
https://imgur.com/a/IDIwQQF
The problem, is that it is very difficult to bug fix this kind of program. Especially considering that I know how I want it to look in my head, but when looking at the numbers in my program there is very little meaning attached to them.
Since I don't know where the issue is, I'm forced to paste all of it here.
public class SphereDrawing extends JPanel {
private static final long serialVersionUID = 1L;
private static final int ADJ = 320;
private static final double LIGHT_SPHERE_RADIUS = 5;
private static final double LIGHT_X = 3;
private static final double LIGHT_Y = 4;
private static final double LIGHT_Z = 0;
private static final double DRAWN_SPHERE_RADIUS = 1;
private static final int POINT_COUNT = 1000000;
private static Coord[] points;
private static final double SCALE = 200;
public SphereDrawing() {
setPreferredSize(new Dimension(640, 640));
setBackground(Color.white);
points = new Coord[POINT_COUNT];
initializePoints();
for (int i = 0; i < points.length; i++) {
points[i].scale();
}
new Timer(17, (ActionEvent e) -> {
repaint();
}).start();
}
public void initializePoints() { //finding the points on the surface of the sphere (hopefully somewhat equidistant)
double random = Math.random() * (double)POINT_COUNT;
double offset = 2/(double)POINT_COUNT;
double increment = Math.PI * (3 - Math.sqrt(5));
for (int i = 0; i < POINT_COUNT; i++) {
double y = ((i * offset) - 1) + (offset / 2);
double r = Math.sqrt(1 - Math.pow(y, 2));
double phi = ((i + random) % (double)POINT_COUNT) * increment;
double x = Math.cos(phi) * r;
double z = Math.sin(phi) * r;
points[i] = new Coord(x, y, z);
}
}
public void drawSphere(Graphics2D g) {
g.translate(ADJ, ADJ); //shifting from origin for drawing purposes
Arrays.sort(points); //sorting points by their z coordinates
double iHat = -2 * LIGHT_X;
double jHat = -2 * LIGHT_Y; //Light vector
double kHat = -2 * LIGHT_Z;
double angL1 = 0;
if (Math.abs(iHat) != 0.0)
angL1 = Math.atan(jHat / iHat); //converting light vector to spherical coordinates
else
angL1 = Math.PI/2;
double angL2 = Math.atan(Math.sqrt(Math.pow(iHat, 2) + Math.pow(jHat, 2))/ kHat);
double maxArcLength = LIGHT_SPHERE_RADIUS * Math.PI; // maximum arc length
for (int i = 0; i < points.length; i++) {
if(points[i].checkValid()) {
double siHat = -2 * points[i].x;
double sjHat = -2 * points[i].y; //finding normal vector for the given point on the sphere
double skHat = -2 * points[i].z;
double angSF1 = -1 * Math.abs(Math.atan(sjHat / siHat)); // converting vector to spherical coordinates
double angSF2 = Math.atan(Math.sqrt(Math.pow(siHat, 2) + Math.pow(sjHat, 2))/ skHat);
double actArcLength = LIGHT_SPHERE_RADIUS * Math.acos(Math.cos(angL1) * Math.cos(angSF1) + Math.sin(angL1) * Math.sin(angSF1) * Math.cos(angL2 - angSF2)); //calculating arc length at this point
double comp = actArcLength / maxArcLength; // comparing the maximum arc length to the calculated arc length for this vector
int col = (int)(comp * 255);
col = Math.abs(col);
g.setColor(new Color(col, col, col));
double ovalDim = (4 * Math.PI * Math.pow(DRAWN_SPHERE_RADIUS, 2))/POINT_COUNT; //using surface area to determine how large size of each point should be drawn
if (ovalDim < 1) // if it too small, make less small
ovalDim = 2;
g.fillOval((int)points[i].x, (int)points[i].y, (int)ovalDim, (int)ovalDim); //draw this oval
}
}
}
#Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawSphere(g);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Sphere");
f.setResizable(false);
f.add(new SphereDrawing(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
#SuppressWarnings("rawtypes")
private class Coord implements Comparable {
public double x;
public double y;
public double z;
public Coord(double x2, double y2, double z2) {
x = x2;
y = y2;
z = z2;
}
public void scale() {
x *= SCALE;
y *= SCALE; //drawing purposes
z *= SCALE;
}
public String toString() {
return x + " " + y + " " + z;
}
public int compareTo(Object c) {
double diff = this.z - ((Coord)c).z;
if (diff < 0)
return -1;
else if (diff > 0) //for sorting the array of points
return 1;
else
return 0;
}
public boolean checkValid() {
return (z > 0); //checks if need to draw this point
}
}
}
I was hoping to at least draw a realistic looking sphere, even if not completely accurate, and I couldn't tell you what exactly is off with mine

Java OpenCV Layer small image onto larger image with transparency

I am trying to write a function that overlays an image at a rectangle with transparency over top of another image, However it doesn't layer the images it just erases the section that I overlay and the transparency cuts through the entire image. Here is my code.
public static void overlayImage(String imagePath, String overlayPath, int x, int y, int width, int height) {
Mat overlay = Imgcodecs.imread(overlayPath, Imgcodecs.IMREAD_UNCHANGED);
Mat image = Imgcodecs.imread(imagePath, Imgcodecs.IMREAD_UNCHANGED);
Rectangle rect = new Rectangle(x, y, width, height);
Imgproc.resize(overlay, overlay, rect.size());
Mat submat = image.submat(new Rect(rect.x, rect.y, overlay.cols(), overlay.rows()));
overlay.copyTo(submat);
Imgcodecs.imwrite(imagePath, image);
}
EDIT: Here are some example pictures:
Before:
After:
Found this function that does exactly what I needed.
public static void overlayImage(Mat background,Mat foreground,Mat output, Point location){
background.copyTo(output);
for(int y = (int) Math.max(location.y , 0); y < background.rows(); ++y){
int fY = (int) (y - location.y);
if(fY >= foreground.rows())
break;
for(int x = (int) Math.max(location.x, 0); x < background.cols(); ++x){
int fX = (int) (x - location.x);
if(fX >= foreground.cols()){
break;
}
double opacity;
double[] finalPixelValue = new double[4];
opacity = foreground.get(fY , fX)[3];
finalPixelValue[0] = background.get(y, x)[0];
finalPixelValue[1] = background.get(y, x)[1];
finalPixelValue[2] = background.get(y, x)[2];
finalPixelValue[3] = background.get(y, x)[3];
for(int c = 0; c < output.channels(); ++c){
if(opacity > 0){
double foregroundPx = foreground.get(fY, fX)[c];
double backgroundPx = background.get(y, x)[c];
float fOpacity = (float) (opacity / 255);
finalPixelValue[c] = ((backgroundPx * ( 1.0 - fOpacity)) + (foregroundPx * fOpacity));
if(c==3){
finalPixelValue[c] = foreground.get(fY,fX)[3];
}
}
}
output.put(y, x,finalPixelValue);
}
}
}

How to add an image into a hexagon in a hexagonal grid?

I have a problem with a hexagonal grid. I found this code you can see below on Internet, so it's not mine. There are two public classes: hexgame which generates the grid and hexmech which draws and fills every single hexagon. What I'd like to do is basically insert an image into a specific hexagon, but I don't know how to code this and in which part of the classes I should put it. Am I thinking the wrong way?
Thank you very much for your help!
Hexgame
package hex;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class hexgame
{
private hexgame() {
initGame();
createAndShowGUI();
}
final static Color COLOURBACK = Color.WHITE;
final static Color COLOURCELL = Color.WHITE;
final static Color COLOURGRID = Color.BLACK;
final static Color COLOURONE = new Color(255,255,255,200);
final static Color COLOURONETXT = Color.BLUE;
final static Color COLOURTWO = new Color(0,0,0,200);
final static Color COLOURTWOTXT = new Color(255,100,255);
final static Color COLOURSAFE = Color.WHITE;
final static Color COLOURDANGEROUS = Color.LIGHT_GRAY;
final static int EMPTY = 0;
final static int UNKNOWN = -1;
final static int SAFE = 1;
final static int DANGEROUS = 2;
final static int CLICKED = 3;
final static int COLUMN_SIZE = 23;
final static int ROW_SIZE = 14;
final static int HEXSIZE = 45;
final static int BORDERS = 15;
int[][] board = new int[COLUMN_SIZE][ROW_SIZE];
void initGame(){
hexmech.setXYasVertex(false);
hexmech.setHeight(HEXSIZE);
hexmech.setBorders(BORDERS);
for (int i=0;i<COLUMN_SIZE;i++) {
for (int j=0;j<ROW_SIZE;j++) {
board[i][j]=EMPTY;
}
}
board[5][5] = SAFE;
board[5][6] = SAFE;
board[5][7] = SAFE;
board[6][5] = SAFE;
board [6][6] = SAFE;
board[4][4] = UNKNOWN;
}
private void createAndShowGUI()
{
DrawingPanel panel = new DrawingPanel();
JFrame frame = new JFrame("Hex Testing 4");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Container content = frame.getContentPane();
content.add(panel);
frame.setSize(825, 630);
frame.setResizable(true);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
class DrawingPanel extends JPanel
{
public DrawingPanel()
{
setBackground(COLOURBACK);
MyMouseListener ml = new MyMouseListener();
addMouseListener(ml);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setFont(new Font("TimesRoman", Font.PLAIN, 15));
super.paintComponent(g2);
for (int i=0;i<COLUMN_SIZE;i++) {
for (int j=0;j<ROW_SIZE;j++) {
if (board[i][j] != UNKNOWN)
hexmech.drawHex(i,j,g2);
}
}
for (int i=0;i<COLUMN_SIZE;i++) {
for (int j=0;j<ROW_SIZE;j++) {
if (board[i][j] != UNKNOWN)
hexmech.fillHex(i,j,board[i][j],g2);
}
}
}
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Point p = new Point( hexmech.pxtoHex(e.getX(),e.getY()) );
if (p.x < 0 || p.y < 0 || p.x >= COLUMN_SIZE || p.y >= ROW_SIZE) return;
board[p.x][p.y] = CLICKED;
repaint();
}
}
}
}
Hexmech
package hex;
import java.awt.*;
import javax.swing.*;
public class hexmech
{
#define HEXEAST 0
#define HEXSOUTHEAST 1
#define HEXSOUTHWEST 2
#define HEXWEST 3
#define HEXNORTHWEST 4
#define HEXNORTHEAST 5
public final static boolean orFLAT= true;
public final static boolean orPOINT= false;
public static boolean ORIENT= orFLAT;
public static boolean XYVertex=true;
private static int BORDERS=50
private static int s=0; // length of one side
private static int t=0; // short side of 30o triangle outside of each hex
private static int r=0; // radius of inscribed circle (centre to middle of each side). r= h/2
private static int h=0; // height. Distance between centres of two adjacent hexes. Distance between two opposite sides in a hex.
public static void setXYasVertex(boolean b) {
XYVertex=b;
}
public static void setBorders(int b){
BORDERS=b;
}
public static void setSide(int side) {
s=side;
t = (int) (s / 2); //t = s sin(30) = (int) CalculateH(s);
r = (int) (s * 0.8660254037844);
h=2*r;
}
public static void setHeight(int height) {
h = height;
r = h/2; // r = radius of inscribed circle
s = (int) (h / 1.73205); // s = (h/2)/cos(30)= (h/2) / (sqrt(3)/2) = h / sqrt(3)
t = (int) (r / 1.73205); // t = (h/2) tan30 = (h/2) 1/sqrt(3) = h / (2 sqrt(3)) = r / sqrt(3)
}
public static Polygon hex (int x0, int y0) {
int y = y0 + BORDERS;
int x = x0 + BORDERS;
if (s == 0 || h == 0) {
System.out.println("ERROR: size of hex has not been set");
return new Polygon();
}
int[] cx,cy;
if (XYVertex)
cx = new int[] {x,x+s,x+s+t,x+s,x,x-t}; //this is for the top left vertex being at x,y. Which means that some of the hex is cutoff.
else
cx = new int[] {x+t,x+s+t,x+s+t+t,x+s+t,x+t,x}; //this is for the whole hexagon to be below and to the right of this point
cy = new int[] {y,y,y+r,y+r+r,y+r+r,y+r};
return new Polygon(cx,cy,6);
}
public static void drawHex(int i, int j, Graphics2D g2) {
int x = i * (s+t);
int y = j * h + (i%2) * h/2;
Polygon poly = hex(x,y);
g2.setColor(hexgame.COLOURCELL);
//g2.fillPolygon(hexmech.hex(x,y));
g2.fillPolygon(poly);
g2.setColor(hexgame.COLOURGRID);
g2.drawString(String.format("%c;%d", 'A'+i, j+1), x+20, y+40);
g2.drawPolygon(poly);
}
public static void fillHex(int i, int j, int n, Graphics2D g2) {
char c='o';
int x = i * (s+t);
int y = j * h + (i%2) * h/2;
/*if (n < 0) {
g2.setColor(hexgame.COLOURONE);
g2.fillPolygon(hex(x,y));
g2.setColor(hexgame.COLOURONETXT);
c = (char)(-n);
g2.drawString(""+c, x+r+BORDERS, y+r+BORDERS+4); //FIXME: handle XYVertex
//g2.drawString(x+","+y, x+r+BORDERS, y+r+BORDERS+4);
}
if (n > 0) {
g2.setColor(hexgame.COLOURTWO);
g2.fillPolygon(hex(x,y));
g2.setColor(hexgame.COLOURTWOTXT);
c = (char)n;
if (n==3) {
g2.setColor(hexgame.COLOURTWO);
g2.fillPolygon(hex(x,y));
g2.setColor(hexgame.COLOURTWOTXT);
}
}
public static Point pxtoHex(int mx, int my) {
Point p = new Point(-1,-1);
//correction for BORDERS and XYVertex
mx -= BORDERS;
my -= BORDERS;
if (XYVertex) mx += t;
int x = (int) (mx / (s+t));
int y = (int) ((my - (x%2)*r)/h);
int dx = mx - x*(s+t);
int dy = my - y*h;
if (my - (x%2)*r < 0) return p; // prevent clicking in the open halfhexes at the top of the screen
//System.out.println("dx=" + dx + " dy=" + dy + " > " + dx*r/t + " <");
//even columns
if (x%2==0) {
if (dy > r) { //bottom half of hexes
if (dx * r /t < dy - r) {
x--;
}
}
if (dy < r) { //top half of hexes
if ((t - dx)*r/t > dy ) {
x--;
y--;
}
}
} else { // odd columns
if (dy > h) { //bottom half of hexes
if (dx * r/t < dy - h) {
x--;
y++;
}
}
if (dy < h) { //top half of hexes
//System.out.println("" + (t- dx)*r/t + " " + (dy - r));
if ((t - dx)*r/t > dy - r) {
x--;
}
}
}
p.x=x;
p.y=y;
return p;
}
In your implementation of paintComponent(), invoke setClip() with a suitable Shape, such as Polygon. You can size and translate the Polygon to match the destination hexagon using the createTransformedShape() method of AffineTransform. Use the coordinates of the polygon's boundary as the basis for the coordinates used in your call to drawImage(). A related example using Ellipse2D is shown here.

Categories