Related
//Generator class
public class Generator {
double jump;
double sizeModifier;
int iterationRate,range;
ComplexNumber c;
public Generator(double jump) {
this.jump=jump;
this.sizeModifier=40;
this.iterationRate=10;
this.range=100;
c=new ComplexNumber();
}
public void generateSet(){
DrawSet ds = new DrawSet();
int ticker=0;
for(double i=-2*range;i<=range;i+=jump){
for(double j=-2*range;j<=range;j+=jump){
c= new ComplexNumber((i/range),(j/range));
double fz=c.square().mod()+c.mod();
//System.out.println("c mod is: "+c.mod());
//System.out.println("fz is: "+fz);
if (fz < 2) {
for(int k=0;k<=iterationRate;k++) {
//System.out.println("nc:"+nc);
ticker++;
//System.out.println("ticker:"+ticker);
if(ticker==iterationRate) {
ds.addPoint(i + 450, j + 450);
}
if(fz>=2){
break;
}
else {
fz = Math.pow(fz, 2) + 1;
}
}
}
ticker=0;
}
}
}
//Drawset class
public class DrawSet extends JPanel {
private ArrayList<Point> Points;
private ArrayList<Point> nPoints;
GraphicWindow gw;
public DrawSet(){
this.Points=new ArrayList<>();
this.nPoints=new ArrayList<>();
gw = new GraphicWindow(1000,1000);
gw.add(this);
}
public void addPoint(double x,double y){
int ix=(int)x;
int iy=(int)y;
//int iwidth=(int)width*sizeModifier;
//int iheight=(int)height*sizeModifier;
Point a=new Point(ix,iy);
Points.add(a);
//System.out.println(Points.size());
}
public void paintComponent(Graphics g) {
int pointSize = 1;
super.paintComponents(g);
System.out.println(Points.size());
for (int i = 0; i < Points.size(); i++) {
g.setColor(Color.BLACK);
g.drawOval((int) Points.get(i).getX(), (int) Points.get(i).getY(), pointSize, pointSize);
}
}
The basic problem is that fz is never <2 after just 10 iterations, so no points are drawn. Why is this? What equation should I be implementing?
I am using a complex number to generate the value. The class which I use can be seen here:
https://github.com/abdulfatir/jcomplexnumber/
(or on the stack overflow forum Does Java have a class for complex numbers? by Mr Abdul Fatir)
Okay, observationally
Generator should not be creating a new instance of DrawSet
DrawSet should not be creating a new instance of GraphicWindow
These are the responsibilities of these classes or methods. This is highly coupling your code and generating side effects.
Instead, generate should pass back the points it creates and these should then be applied in what ever way you want, Generator shouldn't care.
Because I don't have access to your full code, I've just hacked together a random series of points instead to illustrate the point.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DrawSet drawSet = new DrawSet();
Generator generator = new Generator(100);
drawSet.setPoints(generator.generateSet());
JFrame frame = new JFrame();
frame.add(drawSet);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawSet extends JPanel {
private ArrayList<Point> points;
private ArrayList<Point> nPoints;
public DrawSet() {
this.points = new ArrayList<>();
this.nPoints = new ArrayList<>();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public void setPoints(ArrayList<Point> points) {
this.points = points;
repaint();
}
// public void addPoint(double x, double y) {
// int ix = (int) x;
// int iy = (int) y;
// //int iwidth=(int)width*sizeModifier;
// //int iheight=(int)height*sizeModifier;
// Point a = new Point(ix, iy);
// Points.add(a);
// //System.out.println(Points.size());
// }
#Override
protected void paintComponent(Graphics g) {
int pointSize = 5;
super.paintComponents(g);
for (int i = 0; i < points.size(); i++) {
g.setColor(Color.BLACK);
g.drawOval((int) points.get(i).getX(), (int) points.get(i).getY(), pointSize, pointSize);
}
}
}
public class Generator {
double jump;
double sizeModifier;
int iterationRate, range;
//ComplexNumber c;
public Generator(double jump) {
this.jump = jump;
this.sizeModifier = 40;
this.iterationRate = 10;
this.range = 100;
//c = new ComplexNumber();
}
public ArrayList<Point> generateSet() {
Random rnd = new Random();
ArrayList<Point> points = new ArrayList<>(range);
for (int index = 0; index < range; index++) {
int x = (int)(490 * rnd.nextDouble());
int y = (int)(490 * rnd.nextDouble());
points.add(new Point(x, y));
}
return points;
// DrawSet ds = new DrawSet();
// int ticker = 0;
// for (double i = -2 * range; i <= range; i += jump) {
// for (double j = -2 * range; j <= range; j += jump) {
// c = new ComplexNumber((i / range), (j / range));
// double fz = c.square().mod() + c.mod();
// //System.out.println("c mod is: "+c.mod());
// //System.out.println("fz is: "+fz);
// if (fz < 2) {
// for (int k = 0; k <= iterationRate; k++) {
// //System.out.println("nc:"+nc);
// ticker++;
// //System.out.println("ticker:"+ticker);
// if (ticker == iterationRate) {
// ds.addPoint(i + 450, j + 450);
//
// }
// if (fz >= 2) {
// break;
// } else {
// fz = Math.pow(fz, 2) + 1;
// }
// }
// }
// ticker = 0;
// }
// }
}
}
}
I've also made the pointSize bigger, so you can actually see the results, although I'd consider filling the points.
If the Generator is takes a long time to perform its calculations, you might consider using a SwingWorker to perform the operation. This will allow to offload the operation to seperate thread and not block the main UI thread. You can then use the SwingWorker to either feed back each individual point as it's calculated or all the points when the whole generation is done, back to the main UI thread in a safe manner.
See Worker Threads and SwingWorker for more details
Why is this?
Swing is lazy. It won't make repaints or updates to the UI unless it thinks it needs to. So, if you change some state the UI is depending on, you need to nudge Swing to encourage it to make a new paint pass. In the simplest terms, this means calling repaint on the component which is has changed
I am trying to have each brick in my game have a random color, however when I try to do this the whole set of bricks become the same color. How do I make each individual brick a random color? Any help is appreciated.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Game extends JoeApplet implements KeyListener
{
String status;
int ballx = 294; // ball spawn x coordinate
int bally = 640; // ball spawn y coordinate
int batx = 294;
int baty = 654;
int brickx = 32;
int bricky = 50;
double movex = -16; // x speed of ball
double movey = -16; //y speed of ball
int count = 0;
int currentLevel=0;
int score=0; //starts score at 0
int lives=3; //lives start at 3
static boolean right = false;
static boolean left = false;
boolean ballFallDown = false;
boolean bricksOver = false;
Rectangle Ball = new Rectangle(ballx, bally, 14, 14); //creates ball
Rectangle Bat = new Rectangle(batx, baty, 100, 12); //creates bat(paddle)
Rectangle[] Brick = new Rectangle[49]; //creates desired number of bricks
public void paint(Graphics art)
{
switch(currentLevel)
{
case 0:
menuScreen(art);
break;
case 1:
game(art);
break;
}
}
public void menuScreen(Graphics art)
{
setSize(700, 700);
art.setColor(Color.BLACK);
art.fillRect(0, 0, 698, 698);
Color ballcolor=new Color(0,0,66);
art.setColor(ballcolor);
art.fillOval(Ball.x, Ball.y, Ball.width, Ball.height);
Color batcolor=new Color(0,0,66);
art.setColor(batcolor);
art.fill3DRect(Bat.x, Bat.y, Bat.width, Bat.height, true);
art.setColor(Color.green);
art.drawRect(0, 0, 698, 698);
art.setColor(Color.yellow);
Font menu = new Font("Arial", Font.BOLD, 20);
art.setFont(menu);
art.drawString("Brick Breaker", 100,400);
art.drawString("Press P to Play", 100,425);
art.drawString("Press Q to Quit game", 100,450);
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
Color mycolor=new Color(100,0,0);
art.setColor(mycolor);
art.fill3DRect(Brick[i].x, Brick[i].y, Brick[i].width,
Brick[i].height, true);
}
}
art.setColor(Color.YELLOW);
if (ballFallDown || bricksOver)
{
Font f = new Font("Arial", Font.BOLD, 20);
art.setFont(f);
art.drawString(status, 294, 349);
ballFallDown = false;
bricksOver = false;
}
}
public void game(Graphics art)
{
setSize(700, 700);
art.setColor(Color.BLACK);
art.fillRect(0, 0, 698, 698);
Color ballcolor=new Color(0,0,225);
art.setColor(ballcolor);
art.fillOval(Ball.x, Ball.y, Ball.width, Ball.height);
Color batcolor=new Color(0,0,139);
art.setColor(batcolor);
art.fill3DRect(Bat.x, Bat.y, Bat.width, Bat.height, true);
art.setColor(Color.green);
art.drawRect(0, 0, 698, 698);
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
Color mycolor=new Color(200,0,0);
art.setColor(mycolor);
art.fill3DRect(Brick[i].x, Brick[i].y, Brick[i].width,
Brick[i].height, true);
}
}
if (ballFallDown || bricksOver)
{
Font f = new Font("Arial", Font.BOLD, 20);
art.setFont(f);
art.drawString(status, 100,425);
ballFallDown = false;
bricksOver = false;
}
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
if (Brick[i].intersects(Ball))
{
score=score+10;
Brick[i] = null;
movey = -movey;
count++;
}
}
}
if (count == Brick.length)
{
bricksOver = true;
movex=0;
movey=0;
art.setColor(Color.green);
status = "YOU BEAT THE LEVEL!!";
art.drawString("Press E to Exit", 100,450);
art.drawString("Press N for Next Level", 100,475);
repaint();
}
repaint();
Font f = new Font("Arial", Font.BOLD, 20);
art.setFont(f);
art.setColor(Color.white);
art.drawString("Score:"+score, 600, 684);
Ball.x += movex;
Ball.y += movey;
if (left == true)
{
Bat.x -= 18;
right = false;
}
if (right == true)
{
Bat.x += 18;
left = false;
}
if (Bat.x <= 4)
{
Bat.x = 4;
}
else if (Bat.x >= 586)
{
Bat.x = 596;
}
if (Ball.intersects(Bat))
{
movey = -movey-.1;
}
if (Ball.x <= 0 || Ball.x + Ball.height >= 698)
{
movex = -movex;
}
if (Ball.y <= 0)
{
movey = -movey;
}
Font f1 = new Font("Arial", Font.BOLD, 20);
art.setFont(f1);
art.setColor(Color.white);
art.drawString("Lives:"+ lives, 5, 684);
if (Ball.y >= 698 && (bricksOver==false) && lives>0)
{
ballFallDown = true;
art.setColor(Color.red);
status = "";
art.drawString("", 100,450);
lives=lives-1;
ballx = 294;
bally = 640;
Ball = new Rectangle(ballx, bally, 14, 14);
movex = -16;
movey = -16;
repaint();
}
if(lives==0 && Ball.y >= 698)
{
art.setColor(Color.red);
art.drawString("You lost!!", 100,425);
art.drawString("Press E to Exit", 100,450);
}
}
public void init()
{
addKeyListener(this);
for (int i = 0; i < Brick.length; i++) //creates bricks
{
Brick[i] = new Rectangle(brickx, bricky, 40, 20);
if (i == 12) //1st row of bricks
{
brickx = 32;
bricky = 84;
}
if (i == 23) //2nd row of bricks
{
brickx = 82;
bricky = 118;
}
if (i == 32) //3rd row of bricks
{
brickx = 132;
bricky = 152;
}
if (i == 39) //4th row of bricks
{
brickx = 182;
bricky = 186;
}
if (i == 44) //5th row of bricks
{
brickx = 232;
bricky = 220;
}
if (i == 47) //6th row of bricks
{
brickx = 282;
bricky = 254;
}
if (i == 48) //7th row of bricks
{
brickx = 144;
bricky = 132;
}
brickx += 50; //spacing between each brick
}
}
public void restart()
{
ballx = 294;
bally = 640;
batx = 294;
baty = 654;
brickx = 32;
bricky = 50;
Ball = new Rectangle(ballx, bally, 14, 14);
Bat = new Rectangle(batx, baty, 100, 12);
movex = -16;
movey = -16;
ballFallDown = false;
bricksOver = false;
count = 0;
status = null;
for (int i = 0; i < Brick.length; i++) //recreates bricks
{
Brick[i] = new Rectangle(brickx, bricky, 40, 20);
if (i == 12)
{
brickx = 32;
bricky = 84;
}
if (i == 23)
{
brickx = 82;
bricky = 118;
}
if (i == 32)
{
brickx = 132;
bricky = 152;
}
if (i == 39)
{
brickx = 182;
bricky = 186;
}
if (i == 44)
{
brickx = 232;
bricky = 220;
}
if (i == 47)
{
brickx = 282;
bricky = 254;
}
if (i == 48)
{
brickx = 144;
bricky = 132;
}
brickx += 50;
}
repaint();
}
#Override
public void keyPressed(KeyEvent e) //allows each key to do desired action
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT)
{
left = true;
}
if (keyCode == KeyEvent.VK_RIGHT)
{
right = true;
}
if (keyCode == e.VK_P && currentLevel == 0)
{
currentLevel = 1;
}
else if (keyCode == e.VK_E && currentLevel == 1)
{
currentLevel = 0;
score=0;
lives=3;
restart();
}
else if(keyCode == e.VK_Q)
{
System.exit(0);
}
}
#Override
public void keyReleased(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT)
{
left = false;
}
if (keyCode == KeyEvent.VK_RIGHT)
{
right = false;
}
}
#Override
public void keyTyped(KeyEvent e)
{
}
public static void main(String[] args)
{
Game prog = new Game();
prog.init();
}
}
I'd throw that code out and start over as you've got both program logic and repaints within your painting methods, neither of which will help you, and your code appears to be one big huge "God" class, all of which will leave you with code that's a horrific nightmare to debug. Recommendations:
Create at least two separate JPanels to display your program with, a GamePanel and a MenuPanel.
Swap these JPanels using a CardLayout.
Do all graphics within a JPanel's paintComponent method and not within a JFrame's or JApplet's paint method.
Don't forget to call the super's painting method, the same method as your override within your override. This is to clean up any dirty pixels.
Separate your program logic from your GUI
This means that you should have a logical non-GUI representation of a single Brick class as well as a collection of these non-GUI bricks.
You can always give your Brick class a Color field, one that the view or gui uses to paint it with.
Create a game-loop, one that you can control, one that doesn't involve calling repaint() within a painting method, since this leads to a completely uncontrollable loop.
Favor use of Key Bindings over KeyListeners.
Try to avoid use of "magic" numbers, such as hard-coding your brick width and spacing in the class itself. Better to use constants as this too makes debugging and enhancing much easier.
For example, some code that's just to demonstrate showing random colors:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class BrickBreak {
private static void createAndShowGui() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("Brick Break");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
// JPanel that draws the game
class GamePanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Color BACK_GRND = Color.BLACK;
private int prefW;
private int prefH;
private Bricks bricks = new Bricks();
public GamePanel() {
// wide enough to hold the complete top-row of Bricks
// using constants, so GUI automatically resizes if any sizes change
prefW = (Brick.WIDTH + Bricks.X_SPACING) * Bricks.ROW_COUNTS[0] + Bricks.X_SPACING;
prefH = prefW;
setBackground(BACK_GRND);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Brick brick : bricks) {
brick.draw(g2);
}
}
}
// non-GUI class that represents a logical Brick
class Brick {
public static final int WIDTH = 40;
public static final int HEIGHT = 20;
private int x;
private int y;
private Color color;
private Rectangle boundingRectangle;
public Brick(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
boundingRectangle = new Rectangle(x, y, WIDTH, HEIGHT);
}
// yeah, I'm mixing some view with model here.
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.fill3DRect(x, y, WIDTH, HEIGHT, true);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
// use this to test for collisions
public boolean contains(Point p) {
return boundingRectangle.contains(p);
}
#Override
public String toString() {
return "Brick [x=" + x + ", y=" + y + ", color=" + color + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Brick other = (Brick) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
// logical class that holds all Bricks
// Have class implement Iterable<Brick> so we can easily iterate through its containing
// Brick objects in a for-each loop
class Bricks implements Iterable<Brick> {
public static final int X_SPACING = 10;
public static final int Y_SPACING = X_SPACING;
public static final int[] ROW_COUNTS = {13, 11, 9, 7, 5, 3, 1};
private static final float MIN_SAT = 0.8f;
private List<Brick> brickList;
private Random random = new Random();
public Bricks() {
init(); // safe to call since it's final
}
public final void init() {
// recreate the brickList ArrayList
brickList = new ArrayList<>();
int y = Y_SPACING;
// for each row of bricks
for (int row = 0; row < ROW_COUNTS.length; row++) {
int x = X_SPACING + ((ROW_COUNTS[0] - ROW_COUNTS[row]) / 2) * (X_SPACING + Brick.WIDTH);
// for each column
for (int j = 0; j < ROW_COUNTS[row]; j++) {
// create a random color
float hue = random.nextFloat();
float saturation = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
float brightness = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
Color color = Color.getHSBColor(hue, saturation, brightness);
Brick brick = new Brick(x, y, color); // create a new Brick with this Color
brickList.add(brick);
x += X_SPACING + Brick.WIDTH;
}
y += Y_SPACING + Brick.HEIGHT;
}
}
// returns null if no collision
public Brick collision(Point p) {
for (Brick brick : brickList) {
if (brick.contains(p)) {
return brick;
}
}
return null;
}
#Override
public Iterator<Brick> iterator() {
return brickList.iterator();
}
public boolean remove(Brick brick) {
// because Brick implements equals and hashCode, we can do this
return brickList.remove(brick);
}
}
Note that I like using Color's static getHSBColor(float h, float s, float b) method for creating random Colors as this helps me to avoid creating dull Colors, since I can guarantee that the saturation and brightness are above minimum values. All three parameters must be float values between 0f and 1.0f
float hue = random.nextFloat();
float saturation = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
float brightness = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
Color color = Color.getHSBColor(hue, saturation, brightness);
Your code has quite a lot of issues, which #HovercaftFullOfEels answer already points out.
As for why your code doesn't work:
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
Color mycolor=new Color(100,0,0);
art.setColor(mycolor);
art.fill3DRect(Brick[i].x, Brick[i].y, Brick[i].width,
Brick[i].height, true);
}
}
This is the part that renders the bricks. You never create a random-number, but use the same Color for each brick (new Color(100, 0, 0);). Instead introduce a new variable into Brick that specifies the color of each brick and is initialized once with a random color.
The Brick-class would afterwards look like this:
public class Brick{
public int x;
public int y;
...
public Color color;
...
}
The ... are just placeholders for other code that may be content of the class. Regarding public access of Class-variables: Encapsulation is a fundamental concept of OOP and should be used (on encapsulation). E.g. instead of giving direct access to Brick.x consider introducing a method Brick#getX().
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.
I am working on a project where I have to draw 20 circles with random starting points and random sizes. Then I have to determine if any of the circles intersect. If a circle intersects with another, I have to color that circle green. And if the circle does not intersect with another, the color needs to be red. I have all of the code... I think... but when I run it, I still get some circles that should be green, but are red instead. Here is my code. Any help will be greatly appreciated.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.JFrame;
import java.awt.*;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
setPreferredSize(new Dimension(1300, 800)); // set window size
Random random = new Random();
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(800) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i < h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.GREEN);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
}
In the inside for loop, you are only comparing circles of i index with circles with h index, but only those with i < h, because of the condition:
for (int h = 0; h < 20; h++)
{
if(i < h)
{
...
So, instead you should compare every i circle with every h circle, except if they are the same. You want instead:
for (int h = 0; h < 20; h++)
{
if(i != h) //note the change here
{
...
I am having some serious problems with my Asteroid game. I'm trying to call my Game.java run() method in my main method in Asteroid.java but I keep getting the same error:
Exception in thread "main" java.lang.NullPointerException
at asteroids.Asteroids.main(Asteroids.java:15)
Java Result: 1
Can someone help me figure out why this is happening?
here is my code:
Asteroids.java
package asteroids;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.io.IOException;
#SuppressWarnings("serial")
public class Asteroids {
Game game = null;
public static void main(String[] args){
new Asteroids ().game.run ();
}
}
//NEW Game.java//
package asteroids;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
//#SuppressWarnings("serial")
public class Game extends Applet implements Runnable, KeyListener {
//timing variables
Thread thread;
long startTime, endTime, framePeriod;
//graphics variables
Image img;
Dimension dim;
int width, height;
Graphics g;
//text items
int level, lives, score;
SpaceShip ship;
boolean shipCollision, shipExplode;
//ArrayList to hold asteroids
ArrayList<Asteroid> asteroids = new ArrayList<>();
int numOfAsteroids = 1;
//ArrayList to hold the lasers
ArrayList<Laser> lasers = new ArrayList<>();
final double rateOfFire = 10; //limits rate of fire
double rateOfFireRemaining; //decrements rate of fire
//ArrayList to hold explosion particles
ArrayList<AsteroidExplosion> explodingLines = new ArrayList<>();
//ArrayList to hold ship explosions
ArrayList<ShipExplosion> shipExplosion = new ArrayList<>();
public void Game ()
{
init();
}
public void init() {
resize(900,700); //set size of the applet
dim = getSize(); //get dimension of the applet
width = dim.width;
height = dim.height;
framePeriod = 25; //set refresh rate
addKeyListener(this); //to get commands from keyboard
setFocusable(true);
ship = new SpaceShip(width/2, height/2, 0, .15, .5, .15, .98); //add ship to game
shipCollision = false;
shipExplode = false;
level = numOfAsteroids;
lives = 3;
addAsteroids();
img = createImage(width, height); //create an off-screen image for double-buffering
g = img.getGraphics(); //assign the off-screen image
thread = new Thread(this);
thread.start();
}
#Override
public void paint(Graphics gfx) {
Graphics2D g2d = (Graphics2D) g;
//give the graphics smooth edges
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(rh);
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height); //add a black background
//add text for lives, score, and level
g2d.setColor(Color.WHITE);
g2d.drawString("Level : " + level, 10, 690);
g2d.drawString("Lives : " + lives, 110, 690);
g2d.drawString("Score : " + score, 210, 690);
for(Asteroid a: asteroids) { //draw asteroids
a.draw(g2d);
}
for(Laser l : lasers) { //draw lasers
l.draw(g2d);
}
for(AsteroidExplosion e : explodingLines) {
e.draw(g2d);
}
for(ShipExplosion ex : shipExplosion)
ex.draw(g2d);
ship.draw(g2d); //draw ship
if(shipCollision) {
shipExplosion.add(new ShipExplosion(ship.getX(), ship.getY(), 10, 10));
ship.setX(width/2);
ship.setY(height/2);
shipCollision = false;
lives--;
}
gfx.drawImage(img, 0, 0, this); //draw the off-screen image (double-buffering) onto the applet
}
#Override
public void update(Graphics gfx) {
paint(gfx); //gets rid of white flickering
}
#Override
public void run(){
for( ; ; ) {
startTime = System.currentTimeMillis(); //timestamp
ship.move(width, height); //ship movement
for(Asteroid a : asteroids) { //asteroid movement
a.move(width, height);
}
for(Laser l : lasers) { //laser movement
l.move(width, height);
}
for(int i = 0 ; i<lasers.size() ; i++) { //laser removal
if(!lasers.get(i).getActive())
lasers.remove(i);
}
for(AsteroidExplosion e : explodingLines) { //asteroid explosion floating lines movement
e.move();
}
for(int i = 0 ; i<explodingLines.size(); i++) { //asteroid explosion floating lines removal
if(explodingLines.get(i).getLifeLeft() <= 0)
explodingLines.remove(i);
}
for(ShipExplosion ex : shipExplosion){ //ship explosion expansion
ex.expand();
}
for(int i = 0 ; i<shipExplosion.size() ; i++) {
if(shipExplosion.get(i).getLifeLeft() <= 0)
shipExplosion.remove(i);
}
rateOfFireRemaining--;
collisionCheck();
if(asteroids.isEmpty()) {
numOfAsteroids++;
addAsteroids();
level = numOfAsteroids;
}
repaint();
try {
endTime = System.currentTimeMillis(); //new timestamp
if(framePeriod - (endTime-startTime) > 0) //if there is time left over after repaint, then sleep
Thread.sleep(framePeriod - (endTime - startTime)); //for whatever is remaining in framePeriod
} catch(InterruptedException e) {}
}
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//fires laser
if(key == KeyEvent.VK_SPACE) {
if(rateOfFireRemaining <= 0 ) {
lasers.add(ship.fire());
rateOfFireRemaining = rateOfFire;
}
}
if(key == KeyEvent.VK_UP)
ship.setAccelerating(true);
if(key == KeyEvent.VK_RIGHT)
ship.setTurningRight(true);
if(key == KeyEvent.VK_LEFT)
ship.setTurningLeft(true);
if(key == KeyEvent.VK_DOWN)
ship.setDecelerating(true);
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_UP)
ship.setAccelerating(false);
if(key == KeyEvent.VK_RIGHT)
ship.setTurningRight(false);
if(key == KeyEvent.VK_LEFT)
ship.setTurningLeft(false);
if(key == KeyEvent.VK_DOWN)
ship.setDecelerating(false);
}
#Override
public void keyTyped(KeyEvent e) {
}
public void addAsteroids() {
int numAsteroidsLeft = numOfAsteroids;
int size;
for(int i=0 ; i<numOfAsteroids ; i++) { //add asteroids to game
//randomize starting position
int asteroidX = (int)(Math.random() * width) + 1;
int asteroidY = (int)(Math.random() * height) + 1;
//randomize speed and direction
double xVelocity = Math.random() + 1; //horizontal velocity
double yVelocity = Math.random() + 1; //vertical velocity
//used starting direction
int xDirection = (int)(Math.random() * 2);
int yDirection = (int)(Math.random() * 2);
//randomize horizontal direction
if (xDirection == 1)
xVelocity *= (-1);
//randomize vertical direction
if (yDirection == 1)
yVelocity *= (-1);
//if there are more then four asteroids, any new ones are MEGA asteroids
if(numAsteroidsLeft > 4) {
size = 2;
} else { size = 1;
}
asteroids.add(new Asteroid(size, asteroidX, asteroidY, 0, .1, xVelocity, yVelocity));
numAsteroidsLeft--;
//Make sure that no asteroids can appear right on top of the ship
//get center of recently created asteroid and ship and check the distance between them
Point2D asteroidCenter = asteroids.get(i).getCenter();
Point2D shipCenter = ship.getCenter();
double distanceBetween = asteroidCenter.distance(shipCenter);
//if asteroid center is within 80 pixels of ship's center, remove it from the ArrayList and rebuild it
if(distanceBetween <= 80) {
asteroids.remove(i);
i--;
numAsteroidsLeft++;
}
}
}
public void collisionCheck() {
//cycle through active asteroids checking for collisions
for(int i = 0 ; i < asteroids.size() ; i++) {
Asteroid a = asteroids.get(i);
Point2D aCenter = a.getCenter();
//check for collisions between lasers and asteroids
for(int j = 0 ; j < lasers.size() ; j++) {
Laser l = lasers.get(j);
Point2D lCenter = l.getCenter();
double distanceBetween = aCenter.distance(lCenter);
if(distanceBetween <= (a.getRadius() + l.getRadius())) {
//split larger asteroids into smaller ones, remove smaller asteroids from screen
if(a.getRadius() >= 60) {
for(int k = 0 ; k < 3 ; k++)
explodingLines.add(a.explode());
split(i);
score += 200;
} else if(a.getRadius() >= 30){
for(int k = 0 ; k < 3 ; k++)
explodingLines.add(a.explode());
split(i);
score += 100;
} else {
for(int k = 0 ; k < 3 ; k++)
explodingLines.add(a.explode());
asteroids.remove(i);
score += 50;
}
lasers.remove(j); //remove laser from screen
}
}
//check for collisions between ship and asteroid
Point2D sCenter = ship.getCenter();
double distanceBetween = aCenter.distance(sCenter);
if(distanceBetween <= (a.getRadius() + ship.getRadius())) {
shipCollision = true;
shipExplode = true;
}
}
}
public void split(int i) {
Asteroid a = asteroids.get(i);
double bigAsteroidX = a.getX();
double bigAsteroidY = a.getY();
int size = (a.getSize() / 2);
asteroids.remove(i);
for(int j = 0 ; j<2 ; j++) {
//randomize speed and direction
double xVelocity = Math.random() + 1; //horizontal velocity
double yVelocity = Math.random() + 1; //vertical velocity
//used randomize starting direction
int xDirection = (int)(Math.random() * 2);
int yDirection = (int)(Math.random() * 2);
//randomize horizontal direction
if (xDirection == 1)
xVelocity *= (-1);
//randomize vertical direction
if (yDirection == 1)
yVelocity *= (-1);
asteroids.add(new Asteroid(size, bigAsteroidX, bigAsteroidY, 0, .1, xVelocity, yVelocity));
}
}
}
//Edit Update//
Okay I tried a lot of stuff and discovered that even though the game works when I debug Game.java and it doesn't work when I run it through Asteroids.java. I found that img = createIimg = createImage(width, height); and g = img.getGraphics(); are returning null and that GraphicsEnvironment.isHeadless() is returning true. How should I change my to fix this issue?
Error
Exception in thread "main" java.lang.NullPointerException
at asteroids.Game.init(Game.java:67)
at asteroids.Game.Game(Game.java:45)
at asteroids.Asteroids.main(Asteroids.java:15)
Java Result: 1
You have the var "game" null, and you tried to call the method "run" on this var (game.run); obviously if "game" is null, you can't get the method, and throws nullpointer exception.
Game game=new Game();
that's all you need. Your final code is:
Game game = new Game();//<----- here is the change
public static void main(String[] args){
new Asteroids ().game.run ();
}
This thing is null.
new Asteroids ().game
That's why you get this NullPointerException when you call run on it.
Game game = null;
public static void main(String[] args){
new Asteroids ().game.run ();
}
The prgram is running from the main method. game is null.
Maybe you should have
Game game = new Game(); // instead of null
Try it may be help
Game game = null;
public static void main(String[] args){
If( Asteroids ().game != null ){
new Asteroids ().game.run ();
}
}