How to output text with a justify alignment - java

I am trying to create a component for libgdx which can output text in a manner equal to what html would do with a <p align=”justify”> ... </p>.
My idea was to add some custom component which can achieve this by adjusting the relative x and y coordinations of the components.
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
import com.badlogic.gdx.utils.Align;
public class Paragraph extends WidgetGroup {
private Label space;
public Paragraph(String text, float width, LabelStyle style) {
super();
setWidth(width);
this.space = new Label(" ", style);
this.space.pack();
String[] words = text.split(" ");
for (String word : words) {
Label label = new Label(word, style);
label.pack();
addActor(label);
}
}
public void layout () {
float size = 0;
List<Actor> elements = new ArrayList<Actor>();
float x = getX(Align.topLeft);
float y = getY(Align.topLeft);
for (Actor actor : this.getChildren().items) {
if (actor != null) {
if (elements.isEmpty()) {
elements.add(actor);
size = actor.getWidth();
} else {
if (size + space.getWidth() + actor.getWidth() <= this.getWidth()) {
elements.add(actor);
size += (space.getWidth() + actor.getWidth());
} else {
float spacing = space.getWidth() + ((getWidth() - size) / elements.size());
Actor element = elements.get(0);
element.setPosition(x, y, Align.topLeft);
x += element.getWidth();
for (int i = 1; i < elements.size(); i++) {
element = elements.get(i);
element.setPosition(x + spacing, y, Align.topLeft);
x += (spacing + element.getWidth());
}
// new line
elements.clear();
x = getX(Align.topLeft);
y += (this.space.getHeight() * 1.5);
elements.add(actor);
size = actor.getWidth();
}
}
}
}
if (elements.isEmpty() == false) {
float spacing = space.getWidth();
Actor element = elements.get(0);
element.setPosition(x, y, Align.topLeft);
x += element.getWidth();
for (int i = 1; i < elements.size(); i++) {
element = elements.get(i);
element.setPosition(x + spacing, y, Align.topLeft);
x += (spacing + element.getWidth());
}
}
}
}
My problem is that the x and y coordinate I retrieve with getX(Align.topLeft) & getY(Align.topLeft) always returns (0,0)
instead of the real coordinates on the stage.
Component structure looks like this:
Stage
+ Container
+ Table
+ ScrollPane
+ Table
+ Table
+ Paragraph
+ Paragraph
+ Paragraph
+ Paragraph
+ Image
So the end result is that all the text contained in the different paragraphs is drawn on top of each other. Not on position (0,0), but on the same position inside of the surrounding table.

I figured it out myself.
Seems it was a bad idea to override the layout method for that.
I now call a different method from the constructor.
Also I messed up with the x and y coordinates, so I had to rewrite that method.
Ps.:
I adjusted the question as well, as I figured out the solution, it was
not really about the x and y coodinates of the widget group.
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
import com.badlogic.gdx.utils.Align;
public class Paragraph extends WidgetGroup {
private static final class RowData {
final List<Actor> elements;
final float size;
final boolean lastRow;
RowData(List<Actor> elements, float size, boolean lastRow) {
this.elements = elements;
this.size = size;
this.lastRow = lastRow;
}
static RowData createNewRow(List<Actor> elements, float size) {
return new RowData(elements, size, false);
}
static RowData createLastRow(List<Actor> elements, float size) {
return new RowData(elements, size, true);
}
}
private Label space;
public Paragraph(String text, float width, LabelStyle style) {
super();
setWidth(width);
this.space = new Label(" ", style);
this.space.pack();
String[] words = text.split(" ");
for (String word : words) {
Label label = new Label(word, style);
label.pack();
addActor(label);
}
arrangeActors();
}
private void arrangeActors() {
float size = 0;
float height = space.getHeight();
List<RowData> rows = new ArrayList<RowData>();
List<Actor> elements = new ArrayList<Actor>();
Actor[] actors = this.getChildren().begin();
for (Actor actor : actors) {
if (actor != null) {
if (elements.isEmpty()) {
elements.add(actor);
size = actor.getWidth();
} else if (size + space.getWidth() + actor.getWidth() <= this.getWidth()) {
elements.add(actor);
size += (space.getWidth() + actor.getWidth());
} else {
rows.add(RowData.createNewRow(elements, size));
elements = new ArrayList<Actor>();
height += space.getHeight();
elements.add(actor);
size = actor.getWidth();
}
}
}
this.getChildren().end();
rows.add(RowData.createLastRow(elements, size));
height += space.getHeight();
setHeight(height);
float y = height;
for (RowData data : rows) {
float spacing = space.getWidth();
if (data.lastRow == false) {
spacing += ((getWidth() - data.size) / data.elements.size());
}
Actor element = data.elements.get(0);
element.setPosition(0, y, Align.topLeft);
float x = element.getWidth();
for (int i = 1; i < data.elements.size(); i++) {
element = data.elements.get(i);
element.setPosition(x + spacing, y, Align.topLeft);
x += (spacing + element.getWidth());
}
y -= this.space.getHeight();
}
}
#Override
public float getPrefWidth () {
return getWidth();
}
#Override
public float getPrefHeight () {
return getHeight();
}
}

Related

How to update the position of snakes and ladders in an 2D array code?

public class ChutesAndLadders2d {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] numbersOnBoard = new int [6][6];
boardSetUpA (numbersOnBoard);
printTwoD(numbersOnBoard);
}
public static void boardSetUpA (int[][]twoD) {
//Square with even size
//even rows
for (int row = 0;row<twoD.length; row ++) {
if (row %2 ==0) {
int num = twoD.length*(twoD.length-row);
for (int col = 0; col<twoD[row].length; col ++ ) {
twoD[row][col] = num;
num--;
}
}//
else {
int num = twoD.length*(twoD.length-(row + 1))+ 1;
for (int col = 0; col<twoD[row].length; col ++ ) {
twoD[row][col] = num;
num++;
}
}
}//for row
}//
public static void printTwoD(int [][] array){
for (int row = 0; row < array.length; row++){
for (int column = 0; column < array[row].length; column++){
System.out.print(array[row][column] + "\t");
}
System.out.println();
}
}
public static void boardDetails(String[][]board) {
for (int row = 0;row<board.length; row++){
for (int col = 0;col<board[row].length; col++){
if( col+2 == row||col+1 == row*2 ){
board[row][col] = "Lad"; // Append value
}
else if (col*2 == row|| row*2 == col){
board[row][col] = "Cht";// Append value
}
else {
board[row][col] = " ";
}
}
board[board.length-1][0] = "Start";
if (board.length%2 ==0) {
board[0][0] = "End";}
else {
board[0][board.length-1]="End";
}
}
}
public static void printBoard (int[][]twoD, String[][]strTwoD) {
//Printing
for (int row = 0;row<twoD.length;row++) {
for (int col = 0;col<twoD[row].length;col++) {
System.out.print(twoD[row][col] + " "+strTwoD[row][col]+"\t\t");
}
System.out.println("\n");
}
}
}
This is the starter code I have for setting up the snakes and ladders game. I also tried to set the chutes/snakes and ladders on the board but it is not printing. How should I fix it and how do I develop this code to have three methods: update the moves of a player once he reaches a snake, a ladder, and once he rolls his die, from one place to another?
Is it possible to implement a Shutes & Ladders game using a 2D Array? For sure! Does that make sense in an object-oriented language such as Java? I dont know ....
What do you need for that?
A square board with e.g. 36 playing fields.
Connections between two playing fields. (shutes and ladders)
Pawns and a dice.
A renderer that outputs the playing field (as text or graphics).
A program that allows input and connects everything to a functioning game.
Here is an example that works with a List instead of an Array. That can certainly be changed if it is necessary for your purposes.
I hope this is of some help to you.
P.S .: After the start, the board is displayed with field numbers. Shutes are shown as red lines. Ladders as green lines. Keys 1-6 on the keyboard simulate rolling the dice..
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.*;
public class ChutesAndLadders2d {
public static void main(String[] args) {
JFrame frame = new JFrame("Chutes and Ladders 2D");
Game game = new ChutesAndLadders2d().new Game();
game.setPreferredSize(new Dimension(400, 400));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setContentPane(game);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
#SuppressWarnings("serial")
class Game extends JPanel{
private final Font defaultFont = new Font("Arial", Font.PLAIN, 16);
private final BasicStroke stroke = new BasicStroke(4f);
private static final int SCALE = 64;
// board and pawns
private final Board board = new Board(6);
private final List<Pawn> pawns = new ArrayList<>();
public Game(){
setFocusable(true); // receive Keyboard-Events
addKeyListener(new KeyAdapter(){
#Override
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if(c >= '1' && c <= '6'){
int steps = Integer.parseInt(Character.toString(c));
Pawn pawn = pawns.get(0);
pawn.move(steps);
Field field = board.get(pawn.fieldIndex);
if(field.targetKind() != Kind.NONE){
pawn.move(field.getTarget().index - field.index);
}
repaint();
}
}
});
board.connect(5, 12); // Ladder 5 -> 12
board.connect(8, 4); // Shute 8 -> 4
board.connect(15, 32); // Ladder 15 -> 32
board.connect(35, 17); // Shute 35 -> 17
board.connect(23, 30); // Ladder 23 -> 30
pawns.add(new Pawn(Color.BLUE, board.size() - 1));
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
setFont(defaultFont);
for(Field field : board){
Point p = field.getLocation();
g2d.drawRect(p.x * SCALE, p.y * SCALE, SCALE, SCALE);
g2d.drawString(field.text, p.x * SCALE + 24, p.y * SCALE + 40);
}
for(Field field : board){
if(field.targetKind() != Kind.NONE){
g2d.setColor(field.targetKind() == Kind.LADDER ? Color.GREEN : Color.RED);
g2d.setStroke(stroke);
Point source = field.getLocation();
Point target = field.getTarget().getLocation();
g2d.drawLine(source.x * SCALE + 40, source.y * SCALE + 24, target.x * SCALE + 40, target.y * SCALE + 24);
}
}
for(Pawn pawn : pawns){
Point loc = board.get(pawn.fieldIndex).getLocation();
g2d.setColor(pawn.color);
g2d.fillOval(loc.x * SCALE + 32, loc.y * SCALE + 32, 16, 16);
}
}
}
class Board implements Iterable<Field>{
private final List<Field> fields = new ArrayList<>();
public Board(int size){
for(int index = 0; index < size * size; index++)
fields.add(new Field(index, size));
}
public Field get(int index){
return fields.get(index);
}
public void connect(int startFieldnumber, int targetFieldnumber){
get(startFieldnumber - 1).setTarget(get(targetFieldnumber - 1));
}
#Override
public Iterator<Field> iterator() {
return fields.iterator();
}
public int size(){
return fields.size();
}
}
class Field{
final int index;
final String text;
final int size;
private Field target;
public Field(int index, int size){
this.index = index;
this.size = size;
text = "" + (index + 1);
}
public void setTarget(Field target){
if(target == this) return;
this.target = target;
}
public Field getTarget(){
return target;
}
public Kind targetKind(){
if(target == null) return Kind.NONE;
return index < target.index ? Kind.LADDER : Kind.SHUTE;
}
public Point getLocation(){
int x = index % size;
int y = index / size;
if(y % 2 != 0) x = size - x - 1;
return new Point(x, size - y - 1);
}
}
class Pawn{
int fieldIndex = 0;
int maxIndex;
Color color;
public Pawn(Color color, int maxIndex){
this.color = color;
this.maxIndex = maxIndex;
}
public void move(int steps){
fieldIndex += steps;
if(fieldIndex < 0) fieldIndex = 0;
if(fieldIndex > maxIndex) fieldIndex = maxIndex;
}
}
enum Kind{
NONE, SHUTE, LADDER
}
}

Java equivalent to (p5.js) p5.Font.textToPoints() function

Is there a way in java to get the vertices of a font so they can be displayed as particles in java?
like so:
Yes, there's a way. It's not trivial. I wrote this class as part of a marquee GUI.
Pay particular attention to the getTextPixels method.
package com.ggl.marquee.model;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class MarqueeFont {
private static final boolean DEBUG = false;
private int fontHeight;
private Font font;
public MarqueeFont(Font font) {
this.font = font;
FontRenderContext frc = new FontRenderContext(null, true, true);
Rectangle2D r2D = font.getStringBounds("HgH", frc);
this.fontHeight = (int) Math.round(r2D.getHeight());
if (DEBUG) {
System.out.println(font.getFamily() + " " + fontHeight + " pixels");
}
}
public boolean[][] getTextPixels(String s) {
FontRenderContext frc = new FontRenderContext(null, true, true);
Rectangle2D r2D = font.getStringBounds(s, frc);
int rWidth = (int) Math.round(r2D.getWidth());
int rHeight = (int) Math.round(r2D.getHeight());
int rX = (int) Math.round(r2D.getX());
int rY = (int) Math.round(r2D.getY());
if (DEBUG) {
System.out.print(s);
System.out.print(", rWidth = " + rWidth);
System.out.print(", rHeight = " + rHeight);
System.out.println(", rX = " + rX + ", rY = " + rY);
}
BufferedImage bi = generateCharacterImage(rX, -rY, rWidth, rHeight, s);
int[][] pixels = convertTo2D(bi);
if (DEBUG) {
displayPixels(pixels);
}
return createTextPixels(pixels);
}
private BufferedImage generateCharacterImage(int x, int y, int width,
int height, String string) {
BufferedImage bi = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
g.setFont(font);
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.BLACK);
g.drawString(string, x, y);
return bi;
}
private int[][] convertTo2D(BufferedImage image) {
final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer())
.getData();
final int width = image.getWidth();
final int height = image.getHeight();
int[][] result = new int[height][width];
int row = 0;
int col = 0;
for (int pixel = 0; pixel < pixels.length; pixel++) {
result[row][col] = pixels[pixel];
col++;
if (col == width) {
col = 0;
row++;
}
}
return result;
}
private void displayPixels(int[][] pixels) {
for (int i = 0; i < pixels.length; i++) {
String s = String.format("%03d", (i + 1));
System.out.print(s + ". ");
for (int j = 0; j < pixels[i].length; j++) {
if (pixels[i][j] == -1) {
System.out.print(" ");
} else {
System.out.print("X ");
}
}
System.out.println("");
}
}
private boolean[][] createTextPixels(int[][] pixels) {
// The int array pixels is in column, row order.
// We have to flip the array and produce the output
// in row, column order.
if (DEBUG) {
System.out.println(pixels[0].length + "x" + pixels.length);
}
boolean[][] textPixels = new boolean[pixels[0].length][pixels.length];
for (int i = 0; i < pixels.length; i++) {
for (int j = 0; j < pixels[i].length; j++) {
if (pixels[i][j] == -1) {
textPixels[j][i] = false;
} else {
textPixels[j][i] = true;
}
}
}
return textPixels;
}
public Font getFont() {
return font;
}
public int getFontHeight() {
return fontHeight;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(font.getFamily());
builder.append(", ");
builder.append(getStyleText());
builder.append(", ");
builder.append(font.getSize());
builder.append(" pixels");
return builder.toString();
}
private StringBuilder getStyleText() {
StringBuilder builder = new StringBuilder();
int style = font.getStyle();
if (style == Font.PLAIN) {
builder.append("normal");
} else if (style == Font.BOLD) {
builder.append("bold");
} else if (style == Font.ITALIC) {
builder.append("italic");
} else if (style == (Font.BOLD + Font.ITALIC)) {
builder.append("bold italic");
} else {
builder.append("unknown style");
}
return builder;
}
}

honeycomb layout in javafx (with flowpane?)

I'm trying to make a honeycomb flow with buttons in JavaFX with so far a FlowPane
So far I got it half working by using a negative VGap on my FlowPane, but as soon as I resize it and make the 3-4 row go to 3-3-1 it obviously goes wrong
I'm trying to find a solution that will keep the honeycomb layout with variable amounts of buttons, but so far I havent had much success. So I was wondering if anyone knows a solution for this.
edit: here is the basic code I have at the moment
FlowPane root = new FlowPane();
root.setHgap(3.0); root.setVgap(-23.0);
root.setAlignment(Pos.CENTER);
Button[] array = new Button[7];
for(int i = 0; i <= 6; i++){
Button button = new Button();
button.setShape(polygon); (made a polygon in the same of a hexagon)
array[i] = button;
}
root.getChildren().addAll(array);
Predetermined columns/ rows
This is a bit more convenient than using a FlowPane to place the fields.
You can observe that using column spans you can place the Buttons in a GridPane: Every field fills 2 columns of sqrt(3/4) times the field height; the odd/even rows start at column 0/1 respectively. Every field fills 3 rows and the size of the column constraints alternate between one quarter and one half of the field height.
Example
public static GridPane createHoneyComb(int rows, int columns, double size) {
double[] points = new double[12];
for (int i = 0; i < 12; i += 2) {
double angle = Math.PI * (0.5 + i / 6d);
points[i] = Math.cos(angle);
points[i + 1] = Math.sin(angle);
}
Polygon polygon = new Polygon(points);
GridPane result = new GridPane();
RowConstraints rc1 = new RowConstraints(size / 4);
rc1.setFillHeight(true);
RowConstraints rc2 = new RowConstraints(size / 2);
rc2.setFillHeight(true);
double width = Math.sqrt(0.75) * size;
ColumnConstraints cc = new ColumnConstraints(width/2);
cc.setFillWidth(true);
for (int i = 0; i < columns; i++) {
result.getColumnConstraints().addAll(cc, cc);
}
for (int r = 0; r < rows; r++) {
result.getRowConstraints().addAll(rc1, rc2);
int offset = r % 2;
int count = columns - offset;
for (int c = 0; c < count; c++) {
Button b = new Button();
b.setPrefSize(width, size);
b.setShape(polygon);
result.add(b, 2 * c + offset, 2 * r, 2, 3);
}
}
result.getRowConstraints().add(rc1);
return result;
}
FlowPane-like behavior
Making the x position depend on the row the child is added is not a good idea in a FlowPane. Instead I recommend extending Pane and overriding layoutChildren method place the children at custom positions.
In your case the following class could be used:
public class OffsetPane extends Pane {
public interface PositionFunction {
public Point2D getNextPosition(int index, double x, double y, double width, double height);
}
private static final PositionFunction DEFAULT_FUNCTION = new PositionFunction() {
#Override
public Point2D getNextPosition(int index, double x, double y, double width, double height) {
return new Point2D(x, y);
}
};
private final ObjectProperty<PositionFunction> hPositionFunction;
private final ObjectProperty<PositionFunction> vPositionFunction;
private ObjectProperty<PositionFunction> createPosProperty(String name) {
return new SimpleObjectProperty<PositionFunction>(this, name, DEFAULT_FUNCTION) {
#Override
public void set(PositionFunction newValue) {
if (newValue == null) {
throw new IllegalArgumentException();
} else if (get() != newValue) {
super.set(newValue);
requestLayout();
}
}
};
}
public OffsetPane() {
this.hPositionFunction = createPosProperty("hPositionFunction");
this.vPositionFunction = createPosProperty("vPositionFunction");
}
#Override
protected void layoutChildren() {
super.layoutChildren();
double width = getWidth();
List<Node> children = getManagedChildren();
final int childSize = children.size();
if (childSize > 0) {
int row = 0;
Node lastRowStart = children.get(0);
Node lastNode = lastRowStart;
lastRowStart.relocate(0, 0);
PositionFunction hFunc = getHPositionFunction();
PositionFunction vFunc = getVPositionFunction();
int index = 1;
int columnIndex = 0;
while (index < childSize) {
Node child = children.get(index);
Bounds lastBounds = lastNode.getLayoutBounds();
Bounds bounds = child.getLayoutBounds();
Point2D pt = hFunc.getNextPosition(columnIndex, lastNode.getLayoutX(), lastNode.getLayoutY(), lastBounds.getWidth(), lastBounds.getHeight());
if (pt.getX() + bounds.getWidth() > width) {
// break row
lastBounds = lastRowStart.getLayoutBounds();
pt = vFunc.getNextPosition(row, lastRowStart.getLayoutX(), lastRowStart.getLayoutY(), lastBounds.getWidth(), lastBounds.getHeight());
child.relocate(pt.getX(), pt.getY());
lastRowStart = child;
row++;
columnIndex = 0;
} else {
child.relocate(pt.getX(), pt.getY());
columnIndex++;
}
lastNode = child;
index++;
}
}
}
public final PositionFunction getHPositionFunction() {
return this.hPositionFunction.get();
}
public final void setHPositionFunction(PositionFunction value) {
this.hPositionFunction.set(value);
}
public final ObjectProperty<PositionFunction> hPositionFunctionProperty() {
return this.hPositionFunction;
}
public final PositionFunction getVPositionFunction() {
return this.vPositionFunction.get();
}
public final void setVPositionFunction(PositionFunction value) {
this.vPositionFunction.set(value);
}
public final ObjectProperty<PositionFunction> vPositionFunctionProperty() {
return this.vPositionFunction;
}
}
double[] points = new double[12];
for (int i = 0; i < 12; i += 2) {
double angle = Math.PI * (0.5 + i / 6d);
points[i] = Math.cos(angle);
points[i + 1] = Math.sin(angle);
}
Polygon polygon = new Polygon(points);
OffsetPane op = new OffsetPane();
double fieldHeight = 100;
double fieldWidth = Math.sqrt(0.75) * fieldHeight;
for (int i = 0; i < 23; i++) {
Button button = new Button();
button.setShape(polygon);
button.setPrefSize(fieldWidth, fieldHeight);
op.getChildren().add(button);
}
// horizontal placement just right of the last element
op.setHPositionFunction((int index, double x, double y, double width, double height) -> new Point2D(x + width, y));
// vertical position half the size left/right depending on index and
// 1/4 the node height above the bottom of the last node
op.setVPositionFunction((int index, double x, double y, double width, double height) -> new Point2D(x + (index % 2 == 0 ? width : -width) / 2, y + height * 0.75));

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.

Parabolas within bounds

I have a JPanel 200x200.
I trying to create a function that will generate random parabola's with the bounds of the JPanel, with a constraint that the height can't be lower than a 100 (middle of the screen), I basically want to move a shape around these parabolas
Here is some code I'm using to get started:
Random random = new Random(); int y; int x;
int size = random.nextInt(10);
int translation = random.nextInt(50);
int height = random.nextInt(100) - 200; //between 100 and 200
//Parabola functions : y = ((x/7 - 30))^2
// x and y are coordiates of where the shape is drawn
while(y != 200){
y = (float)Math.pow((float)xloc / size - translation ,2) + height;
x++;
}
I've been researching about FlatteningPathIterator but not too sure how to use them. my function
y = (float)Math.pow((float)xloc / size - translation ,2) + height;`
prints parabola's sometimes outside the bounds, how would i edit it to print parabola's inside the bounds?
There is a Java Swing shape generator for this called Quad2dCurve. The getPathIterator call gives you an enumerator for points on the curve.
Here is some example code:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.Random;
import javax.swing.*;
final class TestCanvas extends JComponent {
int size = 200;
int n = 10;
float[] ph = new float[n];
float[] pw = new float[n];
float[] px = new float[n];
Random gen = new Random();
TestCanvas() {
makeRandomParabolas();
setFocusable(true);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
makeRandomParabolas();
repaint();
float [] coords = new float [6];
for (int i = 0; i < n; i++) {
PathIterator pi = getQuadCurve(i).getPathIterator(null, 0.1);
System.out.print(i + ":");
while (!pi.isDone()) {
switch (pi.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
System.out.print(" move to");
break;
case PathIterator.SEG_LINETO:
System.out.print(" line to");
break;
default:
System.out.print(" unexpected");
break;
}
System.out.println(" (" + coords[0] + "," + coords[1]+")");
pi.next();
}
System.out.println();
}
}
});
}
QuadCurve2D.Float getQuadCurve(int i) {
return new QuadCurve2D.Float(px[i] - pw[i], size,
px[i], size - (2 * ph[i]),
px[i] + pw[i], size);
}
void makeRandomParabolas() {
for (int i = 0; i < n; i++) {
float x = 0.2f + 0.6f * gen.nextFloat();
px[i] = size * x;
pw[i] = size * (Math.min(x, 1 - x) * gen.nextFloat());
ph[i] = size * (0.5f + 0.5f * gen.nextFloat());
}
}
#Override
protected void paintComponent(Graphics g0) {
Graphics2D g = (Graphics2D) g0;
for (int i = 0; i < n; i++) {
g.draw(getQuadCurve(i));
}
}
}
public class Main extends JFrame {
public Main() {
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(new TestCanvas());
getContentPane().setPreferredSize(new Dimension(200, 200));
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main().setVisible(true);
}
});
}
}

Categories