Okay, so my friend and I are making are a game that requires some pixel analysis for the rectangles, and I wrote the code to analyze the rectangles, and It works swimmingly, However, when I try to draw the bufferedImage it doesn't show up. The main issue is that my java class has never taught us how to use Jframes, and I don't want to change my code to accommodate:
// Threaded Applet Template that works with Macs
// Import section
// Use this section to add additional libaries for use in your program.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.awt.image.BufferedImage;
import java.awt.Toolkit;
import javax.imageio.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
// This begins the class definition.
// Notice that this is a "world". You can tell since it extends Applet.
// It also implement Runnable which allows it to be and use threads.
public class PixelAnalyzetest extends Applet implements Runnable
{
//variable declaration section
// public datatype variablename
public int xTitle;
public int yTitle;
public Analyzer analyzer;
public BufferedImage test;
public Image itest;
public boolean analyzeonce=true;
//declare your Hero object here
//Sets up a Thread called thread
Thread thread;
// Method definition section
// init() is the first method an Applet runs when started
public void init()
{
//Initialize variables
xTitle=10;
yTitle=10;
BufferedImage test = new BufferedImage(1200,1200, BufferedImage.TYPE_INT_ARGB);
//test = getImage(getDocumentBase(),"test.png");
System.out.println("the width of the image is: "+test.getWidth(this));
try{
test = ImageIO.read(new File("test.png"));
} catch(IOException e) {};
//itest=test.getAsBufferedImage();
analyzer = new Analyzer(test, 5);
//construct objects
//construct your hero here!
//Set up the thread
//These should be the LAST lines in your init( ) method.
thread = new Thread(this); //constructs a new thread
thread.start(); //starts the thread
}//init()
// paint() is used to display things on the screen
public void paint(Graphics g)
{
setSize(1200,1200);
//Put the title on the screen.
/*for(int x=0;x<test.getWidth();x++)
{
for(int y=0;y<test.getHeight();y++)
{
BufferedImage.setRGB(x,y,analyzer.pictureRGB[x][y]);
}
}*/
g.drawImage(test,0,0,1200,1200,this);
//draw your hero's name here using g.drawString( )
}// paint()
// every thread needs a run method
// this is what the thread will do
public void run() {
// this thread loop forever and runs the paint method and then sleeps.
while(true)
{
//put what you want your program to do here.
//move your hero here by calling its move() method.
if(analyzeonce==true)
{
analyzer.analyzelines();
analyzeonce=false;
}
repaint(); // run the paint method.
//sleep
try {
thread.sleep(100);
}
catch (Exception e){ }
}//while
}// run()
}
Now my analyzer class:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.awt.image.BufferedImage;
import java.awt.Toolkit;
public class Analyzer
{
public int[][] pictureRGB;
//VARIABLE DECLARATION SECTION
//Here's where you state which variables you are going to use.
public String name; //use this format public datatype variablename;
public boolean isAlive;
public int health;
public int strength;
public String theGlove;
public int dx, dy;
public BufferedImage analyzing, bgrab;
public int imagewidth, imageheight;
public int linecounter = 0;
public int boxcounter = 0;
public boolean endline = false;
public Line lines[];
public Box boxes[];
public int totalboxes;
public boolean donean = false;
// METHOD DEFINITION SECTION
// Constructor Definition
// A constructor "builds" the object when called and give the variable initial values.
// This constructor build Heroes with all the same initial values.
public Analyzer(BufferedImage grab, int xtotalboxes)
{
//BufferedImage bgrab = (BufferedImage) grab;
//bgrab = new BufferedImage(1200,1200, BufferedImage.TYPE_INT_ARGB);
//bgrab.getGraphics().drawImage(grab,0,0,bgrab.getWidth(),bgrab.getHeight(),null);
analyzing = grab;
totalboxes = xtotalboxes;
imagewidth=analyzing.getWidth();
System.out.println(imagewidth+" Is the image's Width");
imageheight=analyzing.getHeight();
System.out.println(imagewidth+" Is the image's Height");
pictureRGB= new int[imagewidth] [imageheight];
lines = new Line[10];
boxes = new Box[20];
isAlive = true;
health = 200;
strength = 20;
for(int xpos = 1; xpos<imagewidth-1;xpos++)
{
for(int ypos = 1; ypos<imageheight-1; ypos++)
{
pictureRGB[xpos][ypos]=analyzing.getRGB(xpos,ypos);
//System.out.println(pictureRGB[xpos][ypos]);
}
}
}
public void analyzelines()
{
for(boxcounter=0; boxcounter<boxes.length; boxcounter++)
{
int tempx = 0;
int tempy = 0;
int tempw = 0;
int temph = 0;
//int pxpos = 0;
//int pypos = 0;
boolean startline=false;
boolean foundw = false;
boolean foundh = false;
if(donean==false)
{
for(int ypos = 1; ypos<imageheight-1; ypos++)
{
for(int xpos = 1; xpos<imagewidth-1;xpos++)
{
if(boxcounter>0)
{
if(pictureRGB[xpos][ypos]==-3584 && startline==false && boxes[boxcounter-1].rect.contains(new Point(xpos,ypos))==false && boxes[boxcounter-1].rect.intersects(new Rectangle(xpos-2,ypos-2,4,4))==false && isEqual(new Rectangle(xpos-2,ypos-2,4,4))==false)
{
System.out.println("--------------------------------START BOX --------------");
System.out.println("The top left corner of the box is: ("+xpos+","+ypos+")");
startline=true;
tempx=xpos;
tempy=ypos;
//System.out.println(tempx+"<<TEMPX TEMPY>>"+tempy);
}
if(startline==true && pictureRGB[xpos+1][ypos]!=pictureRGB[xpos][ypos] && foundw==false && foundh==false && boxes[boxcounter-1].rect.contains(new Point(xpos,ypos))==false && isEqual(new Rectangle(xpos-2,ypos-2,4,4))==false)
{
tempw=xpos-tempx;
System.out.println("XPOS EQ = "+xpos+" - "+tempx+" = "+ tempw);
foundw = true;
//System.out.println(tempw+"<<TEMPw TEMPx>>"+tempx+"<<<<XPOS>>>>>>>>>>>>>"+xpos);
}
if(startline==true && pictureRGB[xpos][ypos+1]!=pictureRGB[xpos][ypos] && foundh==false && foundw==true && boxes[boxcounter-1].rect.contains(new Point(xpos,ypos))==false && pictureRGB[xpos-1][ypos]==pictureRGB[xpos][ypos] && pictureRGB[xpos+1][ypos]!=pictureRGB[xpos][ypos] && isEqual(new Rectangle(xpos-2,ypos-2,4,4))==false)
{
temph=ypos-tempy;
System.out.println("YPOS EQ = "+ypos+" - "+tempy+" = "+ temph);
foundh=true;
System.out.println("The Width is: "+tempw+" The height is: "+temph+" boxcounter="+boxcounter);
boxes[boxcounter]= new Box(tempx, tempy, tempw, temph);
System.out.println("--------------------------------NEXT BOX ---------------");
//System.out.println("BOX WIDTH"+boxes[boxcounter].width + "BOX COUNTER=="+boxcounter);
}
}
if(boxcounter==0)
{
if(pictureRGB[xpos][ypos]==-3584 && startline==false)
{
System.out.println("The top left corner of the box is: ("+xpos+","+ypos+")");
startline=true;
tempx=xpos;
tempy=ypos;
}
if(startline==true && pictureRGB[xpos+1][ypos]!=pictureRGB[xpos][ypos] && foundw==false && foundh==false)
{
tempw=xpos-tempx;
foundw = true;
}
if(startline==true && pictureRGB[xpos][ypos+1]!=pictureRGB[xpos][ypos] && foundh==false && foundw==true)
{
temph=ypos-tempy;
foundh=true;
System.out.println("The Width is: "+tempw+" The height is: "+temph+" boxcounter="+boxcounter);
boxes[boxcounter]= new Box(tempx, tempy, tempw, temph);
//System.out.println("BOX WIDTH"+boxes[boxcounter].width);
}
}
}
}
if(boxcounter>=(totalboxes))
{
donean=true;
}
}
//System.out.println("The black lines width is: "+(lines[linecounter].endx-lines[linecounter].startx));
}
}
public boolean isEqual(Rectangle c1)
{
boolean returned = false;
for(int i = 0; i<boxcounter; i++)
{
if(c1.intersects(boxes[i].rect) || boxes[i].rect.contains(new Point(c1.x, c1.y)))
{
returned=true;
}
}
return(returned);
}
/*
public static BufferedImage toBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
// Create a buffered image with transparency
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
*/
public void move()
{
}
//Other methods
//You can define what this type of object can do here.
}
my line and box classes are very straight forward just some classes i made with xposes and yposes, width's and heights
Related
I don't really understand why this program draws three pawns instead of one and two of which seem to have a random(probably not so random) positions. enter image description here
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GamePanel extends JPanel implements MouseListener {
static final int SCREEN_EDGE = 800;
static final int GAME_UNITS = 64;
static final int UNIT_SIZE = 100;
final int[] x = new int[GAME_UNITS];
final int[] y = new int[GAME_UNITS];
boolean running = false;
public GamePanel() {
this.setPreferredSize(new Dimension(SCREEN_EDGE, SCREEN_EDGE));
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
int[] position = {0,0};
int[] position1 = {1, 0};
new Pawn(position,-1);
}
private void startGame() {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g){
int counter = 1;
for (int y = 0; y < SCREEN_EDGE/UNIT_SIZE; y++) {
// 1 == "white" 2 == "black"
int color = (y % 2 == 0) ? 1 : 2;
for (int x = 0; x < SCREEN_EDGE/UNIT_SIZE; x++) {
g.setColor(color == 1 ? new Color(239,217, 181) : new Color(180, 136,98));
g.fillRect(x*UNIT_SIZE, y*UNIT_SIZE, UNIT_SIZE, UNIT_SIZE);
color = color == 1 ? 2 : 1;
}
}
for (int i = 0; i < Figure.figures.length; i++) {
JLabel figureSprite = new JLabel(Figure.figures[i].image, JLabel.CENTER);
figureSprite.setSize(90,90);
figureSprite.setLocation(Figure.figures[i].position[0] + 5,Figure.figures[i].position[1] + 5);
this.add(figureSprite);
}
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
public class MyKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
}
}
}
import javax.swing.*;
public abstract class Figure{
protected int value;
protected ImageIcon image;
protected int[][] possibleMoves;
public int[] position;
// white = -1 black = 1
protected int whiteOrBlack;
protected static int figureCount = 1;
// int[figureCount][0 = x][1 = y][2 = color]
public static Figure[] figures = new Figure[figureCount];
public Figure(int value, int[] position, int[][] possibleMoves , int whiteOrBlack) {
this.value = value;
this.position = position;
this.possibleMoves = possibleMoves;
this.whiteOrBlack = whiteOrBlack;
Figure[] oldFigures = figures;
figures = new Figure[figureCount];
for (int i = 0; i < oldFigures.length; i++) {
figures[i] = oldFigures[i];
}
figures[figureCount - 1] = this;
figureCount++;
}
public abstract void move(int[] coordinates);
}
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class Pawn extends Figure{
public Pawn(int[] position, int whiteOrBlack) {
super(1, position, new int[3][2], whiteOrBlack);
super.image = new ImageIcon(getClass().getClassLoader().getResource("graphics/" + (whiteOrBlack == -1 ? "whitePawn.png" : "blackPawn.png")));
Image newImage = super.image.getImage().getScaledInstance(90,90, Image.SCALE_AREA_AVERAGING);
super.image = new ImageIcon(newImage);
}
public void checkMoves(){
for (int i = 0; i < figures.length; i++) {
if((position[0] - 1) == figures[i].position[0] && (position[1] + this.whiteOrBlack) == figures[i].position[1] && figures[i].whiteOrBlack != this.whiteOrBlack) {
possibleMoves[0][0] = position[0] - 1;
possibleMoves[0][1] = position[1] + this.whiteOrBlack;
}else possibleMoves[0] = new int[2];
if((position[0]) != figures[i].position[0] && (position[1]) != figures[i].position[1]){
possibleMoves[1][0] = position[0];
possibleMoves[1][1] = position[1] + 1;
}else possibleMoves[1] = new int[2];
if((position[0] + 1) == figures[i].position[0] && (position[1] + this.whiteOrBlack) == figures[i].position[1] && figures[i].whiteOrBlack != this.whiteOrBlack) {
possibleMoves[2][0] = position[0] + 1;
possibleMoves[2][1] = position[1] + this.whiteOrBlack;
}else possibleMoves[2] = new int[2];
}
}
#Override
public void move(int[] coordinates) {
}
}
import javax.swing.*;
public class GameFrame extends JFrame {
public GameFrame(){
this.add(new GamePanel());
this.setTitle("Chess");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setResizable(false);
this.setVisible(true);
this.setLocationRelativeTo(null);
}
}
public class ChessGame {
public static void main(String[] args) {
new GameFrame();
}
}
I tried few thing like changing JLabel to BufferedImage but it would've generate other problems down the line like not being able to use MouseListener so i feel stuck. I would love to know why this code generates 3 textures too.
It looks like you are adding FigureSprites from within the drawComponent() method. The more often you draw the window, the more figures you have to draw.
Instead within drawComponent() just draw the current state but do not modify it. Adding figures has to come from somewhere else. For example, you could create the necessary pawns in the constructor. Or in extra methods that might get triggered based on user input.
In case you modify the GamePanel's state enough so that it should get painted freshly, just invoke repaint(). Swing will mark this component for repainting and decide on it's own when to run the paint() method, which in turn will run paintComponent().
I am currently working on Sorting Visualizer using Swing Components. First, here is the code to one of my chosen sorting algorithms:
package sortingAlgorithms;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.Timer;
import framework.sortingPanel.SortingPanel;
public class InsertionSort{
private Timer sortingTimer;
private int outerCtr, innerCtr;
private double[] bars;
private int iteration;
private double barWidth;
private int candidateBar, traversingBar;
private int delay;
private boolean proceedToOuter;
public InsertionSort(SortingPanel sortingPanel) {
sortingTimer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(proceedToOuter) {
innerCtr = outerCtr;
candidateBar = outerCtr;
}
if(outerCtr < bars.length) {
if(innerCtr > 0 && bars[innerCtr - 1] > bars[candidateBar]) {
sortingPanel.setNumOfIteration(++iteration);
traversingBar = innerCtr - 1;
if(bars[candidateBar] < bars[traversingBar]) {
double tempBar = bars[candidateBar];
bars[candidateBar] = bars[traversingBar];
bars[traversingBar] = tempBar;
int temp = candidateBar;
candidateBar = traversingBar;
traversingBar = temp;
}
sortingPanel.repaint();
innerCtr--;
proceedToOuter = false;
}else {
proceedToOuter = true;
outerCtr++;
}
}else {
sortingTimer.stop();
sortingPanel.sortingIsDone();
System.out.println("SORTED");
//everything else after the algorithm
}
}
});
}
public void initComponents(double[] bars, double barWidth, int delay) {
iteration = 0;
this.bars = bars;
this.barWidth = barWidth;
this.delay = delay;
setDelay(delay);
outerCtr = 1;
innerCtr = outerCtr;
candidateBar = outerCtr;
traversingBar = 0;
proceedToOuter = true;
}
public void draw(Graphics g) {
g.setColor(Color.WHITE);
Graphics2D g2d = (Graphics2D) g;
Rectangle2D r2d;
for(int i = 0; i < bars.length; i++) {
r2d = new Rectangle2D.Double(i*barWidth, 0, barWidth, bars[i]);
g2d.fill(r2d);
}
g.setColor(Color.RED);
r2d = new Rectangle2D.Double(traversingBar*barWidth, 0, barWidth, bars[traversingBar]);
g2d.fill(r2d);
g.setColor(Color.GREEN);
r2d = new Rectangle2D.Double(candidateBar*barWidth, 0, barWidth, bars[candidateBar]);
g2d.fill(r2d);
}
public void setDelay(int delay) { sortingTimer.setDelay(delay); }
public void playSort() { sortingTimer.start(); }
public void stopSort() { sortingTimer.stop(); }
public void continueSort() { sortingTimer.start(); }
}
I used a JPanel to display the double bars[] which are the bars to be sorted. I created an method initComponents() to initialize the variables needed in the algorithm (I did this since I designed the project in such a way that the user could shuffle and re-sort another bars[] using the same algorithm; plus, I don't know why I can't access the values passed during instantiation of InsertionSort class so I've decided to create a separate method to handle the issue).
I draw() method accepts a Graphics from the sortingPanel in which all the bars are being displayed. I have overriden the paintComponent in sortingPanel and pass its Graphics to this draw method.
I just need your opinion whether I'm right in implementing Swing Timer.
ADDED NOTE:
This code works perfectly but I want to hear some opinion especially in the technical side of the code structure.
I also know that Thread.Sleep() is a no go so I just want to see if this is correct or are there WAY BETTER solution than this.
I want to create a game similar to SpaceInvaders, but instead of getting to the bottom of the screen, the aliens shoot projectiles. One type of aliens I wanted to create(in the code below), turns
to 45 degree and back. I tried it with affine transform, but everytime they turn the game slows down to half of the speed. The player and the projectiles are moving at half the speed then. The code below is the class that creates a JPanel
and draws everything.
import javax.swing.Timer;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import java.util.*;
import javax.swing.JPanel;
import javax.imageio.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.io.IOException;
import javax.swing.*;
public class WELTZEICHNER2 extends JPanel implements ActionListener ,
KeyListener
{
Player p;
Timer t = new Timer (5, this);
ArrayList<ANGRIFF> ziele = new ArrayList<ANGRIFF>();
ArrayList<ANGRIFF> ziele2 = new ArrayList<ANGRIFF>();
ArrayList<ALIEN1> aliens1 = new ArrayList<ALIEN1>();
private boolean left,right,space;
private int lastshot = 100;
private int score =0;
BufferedImage image;
BufferedImage image2;
BufferedImage image3;
BufferedImage image4;
int count = 0;
int count2 = 0;
int d = 0;
public WELTZEICHNER2()
{
setDoubleBuffered(true);
p = new Player(500,900,100000);
t.start();
addKeyListener(this);
setFocusable(true);
URL resource = getClass().getResource("alien2.png");
URL resource2 = getClass().getResource("background.png");
URL resource3 = getClass().getResource("raumschifftest.png");
URL resource4 = getClass().getResource("kreislertest.png");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
e.printStackTrace();
}
try {
image2 = ImageIO.read(resource2);
} catch (IOException e) {
e.printStackTrace();
}
try {
image3 = ImageIO.read(resource3);
} catch (IOException e) {
e.printStackTrace();
}
try {
image4 = ImageIO.read(resource4);
} catch (IOException e) {
e.printStackTrace();
}
for (int i= 0;i < 20;i++)
{
for (int j =0;j <5;j++)
{
aliens1.add(new ALIEN1(70+i*90,80+j*70,1));
}
}
}
public void erzeugeANGRIFF()
{
ANGRIFF b = new ANGRIFF(p.getxN() + 11, p.getyN(),true);
ziele2.add(b);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.drawImage(image2,1,1,this); //background image
g.drawImage(image3,p.getxN(),p.getyN(),this); //player image
for (ANGRIFF b : ziele)
{
g2.setColor(Color.RED);
g2.fill( new Ellipse2D.Double(b.getxN(),b.getyN(),5,10)); //alien´s projectiles
}
for (ANGRIFF b : ziele2)
{
g2.setColor(Color.GREEN);
g2.fill( new Ellipse2D.Double(b.getxN(),b.getyN(),5,10)); // player´s projectiles
}
for (ALIEN1 i : aliens1) //draw alien images
{
if(count2 > 10000)
{
AffineTransform trans = new AffineTransform();
trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
BufferedImage rotated = new BufferedImage(image4.getWidth(),
image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g3 = rotated.createGraphics();
g3.drawImage(image4, trans, null);
g2.drawImage(rotated,i.getxN(),i.getyN(),null);
}
else
{
g.drawImage(image4,i.getxN(),i.getyN(),this);
}
}
g2.setColor(Color.RED);
g2.drawString("Score:"+ score,5,15);
g2.drawString("Health:"+ p.health,5,30);
g2.drawString("Count:"+ count,5,45);
if(p.health == 0) //Game Over screen
{
g2.setColor(Color.BLACK);
g2.fill(new Rectangle2D.Double(1,1,1920,1080));
g2.setColor(Color.RED);
String text = "Game Over";
Font endtext = new Font("TimesNewRoman",Font.PLAIN, 200 );
g2.setFont(endtext);
g2.drawString(text,450,540);
}
}
public void actionPerformed(ActionEvent e)
{
if ( right == true)
{
p.right();
}
if (left == true)
{
p.left();
}
if(space == true && lastshot < 0)
{
erzeugeANGRIFF();
lastshot = 100;
}
lastshot -=1;
int bulletCount =ziele.size();
int bulletCount2 =ziele2.size();
int Alien1Count = aliens1.size();
ArrayList<Integer> remANGRIFF= new ArrayList<Integer>();
ArrayList<Integer> remANGRIFF2= new ArrayList<Integer>();
ArrayList<Integer>remAlien1=new ArrayList<Integer>();
for( int i = 0; i < bulletCount2;i++)
{
ANGRIFF b = ziele2.get(i);
b.bewegeANGRIFF();
if (b.getyN() >1000 )
{
remANGRIFF2.add(i);
}
for (int j =0;j< Alien1Count;j++ )
{
ALIEN1 n = aliens1.get(j);
if (b.checkCollision(n) && b.player == true)
{
n.health -=1;
score +=50;
if (n.health <= 0)
{
remAlien1.add(j);
score +=100;
}
remANGRIFF2.add(i);
}
}
}
for( int i = 0; i < bulletCount;i++)
{
ANGRIFF b = ziele.get(i);
b.bewegeANGRIFF();
if (b.getyN() < -100 )
{
remANGRIFF.add(i);
}
if (b.checkCollision(p) && b.player == false)
{
p.health -=50;
if (p.health <= 0)
{
p.health = 0;
}
remANGRIFF.add(i);
}
}
for (ALIEN1 i : aliens1)
{
// i.Bewegungsmuster();
count2++;
if(count2 > 20000)
{
count2 = 0;
}
if (i.newANGRIFF())
{
ziele.add(new ANGRIFF(i.getxN()+50,i.getyN()+50,false));
}
}
for (int i: remANGRIFF)
{
if(i < ziele.size())
{
ziele.remove(i);
}
}
for (int i: remANGRIFF2)
{
if(i < ziele2.size())
{
ziele2.remove(i);
}
}
for (int i: remAlien1)
{
if (i<aliens1.size())
{
aliens1.remove(i);
}
}
repaint();
}
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_RIGHT)
{
right = true;
}
if ( code == KeyEvent.VK_LEFT)
{
left = true;
}
if ( code == KeyEvent.VK_SPACE)
{
space = true;
}
}
public void keyReleased(KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_RIGHT)
{
right = false;
}
if ( code == KeyEvent.VK_LEFT)
{
left = false;
}
if ( code == KeyEvent.VK_SPACE)
{
space = false;
lastshot =0;
}
}
public void keyTyped(KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_SPACE)
{
erzeugeANGRIFF();
}
}
}
This is the class that starts the game.
import javax.swing.*;
public class start
{
public static void main(String[] args)
{
//System.setProperty("sun.java2d.d3d", "true");
//System.setProperty("sun.java2d.noddraw", "false");
//-Dsun.java2d.noddraw=false;
JFrame f = new JFrame();
WELTZEICHNER2 d = new WELTZEICHNER2();
f.setSize(1920,1080);
f.setTitle("BlueJ Space Invader");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(d);
f.setVisible(true);
}
}
Any help is appreciated.
You're "core" problem is here...
if(count2 > 10000)
{
AffineTransform trans = new AffineTransform();
trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
BufferedImage rotated = new BufferedImage(image4.getWidth(),
image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g3 = rotated.createGraphics();
g3.drawImage(image4, trans, null);
g2.drawImage(rotated,i.getxN(),i.getyN(),null);
}
This is creating a number of short lived objects on every paint cycle, which is putting extra strain one the GC, slowing down your program - not to mention the time it takes to create a BufferedImage
A better solution is to simply rotate the current Graphics context. The problem with this is, it can become very complex very quickly.
So, basically what I would do, is I would use the AffineTransform to translate the origin point/offset to the position of the object you are painting. The rotation then becomes as simple as rotating about the centre point of the image and then painting the image at 0x0.
The trick is reseting the transform when you're finished. This is where creating another copy of the Graphics context before hand, applying the transform to it, painting the image and then disposing of the copy comes in very, very handy.
if (count2 > 10000) {
AffineTransform trans = new AffineTransform();
trans.translate(i.getxN(), i.getyN());
trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
//BufferedImage rotated = new BufferedImage(image4.getWidth(),
//image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g3 = (Graphics2D) g2.create();
g3.setTransform(trans);
//g3.drawImage(image4, trans, null);
g3.drawImage(image4, 0, 0, null);
g3.dispose();
}
When I was testing your code, I had witnessed an uneven frame rate. The ActionListener was been called at intervals in far greater values of 5 milliseconds. By the time it had performed 30, 000 cycles, it was already at an average of 75 milliseconds and slowly increasing, which suggest that you have some more issues to deal with.
Focus on the ArrayList and the creation/disposal of your objects and consider using "pools" of objects to further reduce the GC overhead where possible
You could have a look at Swing animation running extremely slow for an example.
PS # about 300, 000 cycles, the update cycle is up to an average of 200 milliseconds per update :P
My assignment is to create the game "FloodIt." You can play the game here if you need to understand it, but I don't think it's really necessary: http://unixpapa.com/floodit/
I have finished the actual game part of it, but now I need to make a graphical interface for it. I have three classes:
Board.java, which makes the board with random int values and contains several other methods to make the game work:
import java.awt.Color;
import java.util.Random;
/**The board class for the Flood-It game. This class implements a NxN board filled with numColors colors.
* The class implements several methods to allow the playing of the game.
*/
class Board {
//you will probably need to create some field variables
private int size;
private int numColors;
private int[][] board;
private int numOfMoves;
/**Constructs a new sizeXsize board filled where each element on the board is a random number between 0
* and numColors. Also initializes the number of moves to zero.
* #param size -- the size of the board
* #param numColors -- the number of possible entries on the board
*/
public Board(int size,int numColors) {
//TODO finish this constructor
this.size = size;
this.numColors = numColors;
numOfMoves = 0;
board = new int[size][size];
Random rand = new Random();
int randomNum = 0;
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
randomNum = rand.nextInt(this.numColors);
board[count][counter] = randomNum;
}
}
}
/**Updates the board to fill (from the top left corner) with a specified color.
* Filling stops when any other color is hit besides the one in the top left corner.
* Play the game at http://www.lemoda.net/javascript/flood-it/ or http://unixpapa.com/floodit/?sz=14&nc=4
* to get a better understanding of what this method should do.
* You will probably also want to take a look at the algorithm described
* at http://en.wikipedia.org/wiki/Flood_fill which describes what this method should do.
* I recommend the Stack-based recursive implementation. It is a recursive algorithm for
* flooding the board. It is one of the easier ones to implement.
* You are free to have this method call other methods. I would recommend creating a private method that
* this method calls and have that private method be the recursive method.
* A recursive method is one that calls itself.
* #param color -- the new color to flood the board with.
*/
public void move(int replacementColor) {
int targetColor = board[0][0];
recursiveMove(0,0,targetColor,replacementColor);
numOfMoves++;
}
private void recursiveMove(int xCoord, int yCoord, int targetColor, int replacementColor) {
if (targetColor == replacementColor) {
return;
}
if (board[xCoord][yCoord] != targetColor) {
return;
}
board[xCoord][yCoord] = replacementColor;
if (yCoord != size-1) {
recursiveMove(xCoord,yCoord+1,targetColor,replacementColor);
}
if (yCoord != 0) {
recursiveMove(xCoord,yCoord-1,targetColor,replacementColor);
}
if (xCoord != 0) {
recursiveMove(xCoord-1,yCoord,targetColor,replacementColor);
}
if (xCoord != size-1) {
recursiveMove(xCoord+1,yCoord,targetColor,replacementColor);
}
}
/**returns true if the board is not completely filled with a single color.
* Otherwise it returns false.
* #return true if board is all one color
*/
public boolean finished() {
//TODO finish this method
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
if (board[count][counter] != board[0][0]) {
return false;
}
}
}
return true;
}
/**returns how many times the move() method has been called.
* #return the number of times the move() method has been called.
*/
public int numMoves() {
//TODO finish this method
return numOfMoves;
}
/**Returns a string representation of the board. Use tabs between elements of the board.
* And have every row of the board be separated by a newline character.
* Example:
* "1\t0\t3\t\n2\t0\t2\t\n1\t0\t1\t\n"
* #return a String representation of the board
*/
public String toString() {
//TODO finish this method
String boardString = "";
for (int count = 0; count < board.length; count++) {
for (int counter = 0; counter < board.length; counter++) {
boardString += board[count][counter];
boardString += "\t";
}
boardString += "\n";
}
return boardString;
}
}
FloodIt.java, which contains the JFrame lines in order to load the graphical interface, as well as code to actually run the game (it's not entirely finished, as I got stuck):
import java.util.Scanner;
import javax.swing.JFrame;
/**This class is the main method for the Flood-It game as found on many web sites
* ( such as http://www.lemoda.net/javascript/flood-it/ or
http://unixpapa.com/floodit/?sz=14&nc=4 ).
* It prompts the user for the size of the board
* and the number of colors. The user is prompted for the next color until the board is flooded.
* After the game is over it prints how many turns the user took and then asks if they want to play again.
*/
class FloodIt {
private static final int FRAMESIZE = 1000;
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setSize(FRAMESIZE,FRAMESIZE);
frame.setTitle("Brennan's Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicalBoard component = new GraphicalBoard();
frame.add(component);
frame.setVisible(true);
String again="";
int size = 20;
int numColors = 7;
do {
Board board=new Board(size,numColors);
while(!board.finished()) {
//I will change the print statements below into graphical input boxes later
System.out.print("****************\n"+board+"\n****************\n");
System.out.print("What color do you choose? ");
int color=Integer.parseInt(scan.nextLine());
board.move(color);
}
System.out.println("Nice job, you finished in "+board.numMoves());
System.out.print("Would you like to play again (Y/N)? ");
again=scan.nextLine();
} while (again.equalsIgnoreCase("Y"));
scan.close();
}
}
And GraphicalBoard.java, which is supposed to take the values of the 2d array from Board.java and display the board in a graphical interface. Each number that could be in the 2d array corresponds with a color in the Colors array:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
public void paintComponent(Graphics g, int size, Board board) {
String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
Graphics2D g2 = (Graphics2D) g;
int xCoord = 0;
int yCoord = 0;
int colorNum = 0;
String colorOfSquare = "";
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
colorNum = board[count][counter];
colorOfSquare = colors[colorNum];
g2.setColor(Color.colorOfSquare);
Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
xCoord += 50;
}
yCoord += 50;
}
}
}
Two problems:
In GraphicalBoard.java, on the line "colorNum = board[count][counter];", I am getting the error: "The type of expression must be an array type but it resolved to Board."
I seem to be having a problem bring over the already initialized board from the Board.java class into the GraphicalBoard.java class.
In GraphicalBoard.java, on the line "g2.setColor(Color.colorOfSquare);", I am getting the error: "colorOfSquare cannot be resolved or it not a field."
I know the problem, it is supposed to be something like "g2.setColor(Color.BLACK);", but I am going to have the user input the color, so it kind of needs to be a variable and I was hoping to have something cleaner than just an if statement for every color.
Any suggestions? Thanks!
Your Board class contains a member variable int[][] board, but its scope is private. When you call the following:
colorNum = board[count][counter];
This is wrong because the board variable here is an object of Board class. It itself is not the two day array, but it encapsulates int[][] board inside it. So you need to provide a getter method in Board to expose its board member variable like this:
public int[][] getBoard() {
return board;
}
Then in the paintComponent method you can access it as: board.getBoard()[count][counter].
You already seem to have a user inputted color in the colorOfSquare variable. But Graphics2D's setColor method would only accept a variable of type java.awt.Color. Since you have the String representation of the color, you can get its corresponding java.awt.Color value using reflection as mentioned here. The following should work for you:
Color color;
try {
Field field = Color.class.getField(colorOfSquare);
color = (Color) field.get(null);
} catch (Exception e) {
color = null; // Not defined
}
Two answers:
paintComponent ONLY receives a Graphics object. See this link for a short tutorial. If you need to access other objects in this method, make them variables of GraphicalBoard and pass them om during construction.
1.5 You need to access the Board's board, as this is what you are using. So add a getBoard(int i, int j) in class Board. Something like the following (I also added a getSize() method) :
public int getBoard(int i, int j) {
return board[i][j] ;
}
public int getSize() {
return size;
}
Your color colorOfSquare is already defined as a color. The error arises because the Color class doesn't have such a constant. You should just pass the color directly.
Try this:
public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
private Board board;
private int size;
public GraphicalBoard() {
}
public void setBoard(Board board){
this.board = board;
}
public void paintComponent(Graphics g) {
super.paintComponent();
if(board == null) {
throw new RuntimeException("Board not set") ;
}
String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
Graphics2D g2 = (Graphics2D) g;
int xCoord = 0;
int yCoord = 0;
int colorNum = 0;
int size = board.getSize() ;
String colorOfSquare = "";
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
colorNum = board.getBoard(count, counter) ;
colorOfSquare = colors[colorNum];
g2.setColor(colorOfSquare);
Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
xCoord += 50;
}
yCoord += 50;
}
}
In very general terms,
your view, here the drawing JPanel, should contain a reference to the model object via a has-a or "composition" structure
The view should be notified of changes in the model, often via event listeners such as a PropertyChangeListener
The view then extracts the key information and uses that to help decide what to draw. So, if it has a reference to the current Board object, it can make getter method calls from within the paintComponent method.
Other issues in your code:
Make sure to call the super's paintComponent within your override, else you will not clean up "dirty" pixels
Don't mix linear code -- a Scanner based on System.in with GUI code. Make it all one or the other.
For example, in the code below, I use a model class, the class that holds the int[][] board variable and here called BoardModel, and I give it a SwingPropertyChangeSupport object.
class BoardModel {
// .....
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
This object will accept listeners, and will allow me to notify listeners of changes to the model.
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
Then when the model changes, I notify all listeners by calling the support object's firePropertyChange(...) method:
public void selectSquare(int x, int y) {
int replacementValue = board[y][x];
int targetValue = board[0][0];
if (targetValue == replacementValue) {
return;
} else {
recursiveMove(0, 0, targetValue, replacementValue);
numOfMoves++;
support.firePropertyChange(BOARD, null, board); // ***** here
setWin(checkForWin());
}
}
Then in the control, I can add listeners that notify the view of changes:
model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
view.repaint();
String moveCount = "" + model.getNumOfMoves();
controlPanel.setMoveCountFieldText(moveCount);
}
});
model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ((boolean) evt.getNewValue()) {
String message = "Move count: " + model.getNumOfMoves();
String title = "Game Over";
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(view, message, title, messageType);
}
}
});
A working example could look like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.SwingPropertyChangeSupport;
public class BoardFun {
private static final int NUM_COLORS = 6;
private static final int SIZE = 20;
#SuppressWarnings("serial")
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
int size = SIZE;
int numColors = NUM_COLORS;
final BoardModel model = new BoardModel(size , numColors );
final BoardPanel view = new BoardPanel();
final ControlPanel controlPanel = new ControlPanel();
view.setModel(model);
view.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mEvt) {
Point p = mEvt.getPoint();
int row = view.getRow(p);
int col = view.getColumn(p);
model.selectSquare(col, row);
}
});
model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
view.repaint();
String moveCount = "" + model.getNumOfMoves();
controlPanel.setMoveCountFieldText(moveCount);
}
});
model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ((boolean) evt.getNewValue()) {
String message = "Move count: " + model.getNumOfMoves();
String title = "Game Over";
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(view, message, title, messageType);
}
}
});
controlPanel.setResetAction(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
model.reset();
}
});
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(view);
frame.add(controlPanel, BorderLayout.PAGE_START);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class ControlPanel extends JPanel {
private JTextField moveCountField = new JTextField("0", 10);
private JButton resetButton = new JButton();
public ControlPanel() {
add(new JLabel("Move Count:"));
add(moveCountField);
add(resetButton);
}
public void setResetAction(Action action) {
resetButton.setAction(action);
}
public void setMoveCountFieldText(String text) {
moveCountField.setText(text);
}
}
#SuppressWarnings("serial")
class BoardPanel extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = PREF_W;
private BoardModel model;
private Color[] colors;
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
public void setModel(BoardModel model) {
this.model = model;
colors = new Color[model.getNumColors()];
// create colors.length Colors, all of different hue
for (int i = 0; i < colors.length; i++) {
float hue = (float) i / colors.length;
colors[i] = Color.getHSBColor(hue, 1f, 1f);
}
}
// translate point to logical square position
int getRow(Point p) {
return (p.y * model.getBoard().length) / getHeight();
}
int getColumn(Point p) {
return (p.x * model.getBoard()[0].length) / getWidth();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // always call the super's method
if (model == null) {
return;
}
int board[][] = model.getBoard();
int height = getHeight() / board.length;
int width = getWidth() / board[0].length;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
Color color = colors[board[i][j]];
g.setColor(color);
int x = (j * getWidth()) / board[0].length;
int y = (i * getHeight()) / board.length;
g.fillRect(x, y, width, height);
}
}
}
}
class BoardModel {
public static final String BOARD = "board";
public static final String WIN = "win";
private int[][] board;
private int numColors;
private Random random = new Random();
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
private int numOfMoves = 0;
private boolean win = false;
public BoardModel(int size, int numColors) {
board = new int[size][size];
this.numColors = numColors;
reset();
}
public void reset() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
board[i][j] = random.nextInt(numColors);
}
}
numOfMoves = 0;
support.firePropertyChange(BOARD, null, board);
setWin(false);
}
public int[][] getBoard() {
return board;
}
public int getNumOfMoves() {
return numOfMoves;
}
public int getNumColors() {
return numColors;
}
public void setWin(boolean win) {
boolean oldValue = this.win;
boolean newValue = win;
this.win = win;
support.firePropertyChange(WIN, oldValue, newValue);
}
public boolean isWin() {
return win;
}
public void selectSquare(int x, int y) {
int replacementValue = board[y][x];
int targetValue = board[0][0];
if (targetValue == replacementValue) {
return;
} else {
recursiveMove(0, 0, targetValue, replacementValue);
numOfMoves++;
support.firePropertyChange(BOARD, null, board);
setWin(checkForWin());
}
}
public boolean checkForWin() {
int value = board[0][0];
for (int[] row : board) {
for (int cell : row) {
if (cell != value) {
return false;
}
}
}
return true;
}
private void recursiveMove(int i, int j, int targetValue, int replacementValue) {
int currentValue = board[i][j];
if (currentValue != targetValue || currentValue == replacementValue) {
return;
}
board[i][j] = replacementValue;
int rowMin = Math.max(0, i - 1);
int rowMax = Math.min(board.length - 1, i + 1);
int colMin = Math.max(0, j - 1);
int colMax = Math.min(board[i].length - 1, j + 1);
for (int i2 = rowMin; i2 <= rowMax; i2++) {
if (i2 != i) {
recursiveMove(i2, j, targetValue, replacementValue);
}
}
for (int j2 = colMin; j2 <= colMax; j2++) {
if (j2 != j) {
recursiveMove(i, j2, targetValue, replacementValue);
}
}
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
}
I am making a game (see my previous threads) and have encountered a lot of problems on the way. All I know is that he code compiles, runs, but nothing appears in the window, it's just grey. At Andrew Thompson's suggestion, I am posting the entire compilable version here. Sorry for the length but it is ALL the code in the program. And a lot of things will probably not make sense (unused ActionPerformed to name one), partially because I implemented code in the event that I would need it but mostly because I have never done this before.
Also, so far I have no multithreading, because once again, I am new to this, so ideally I would like to keep it that way, if only for the sake of my sanity.
EDIT: Forgot to mention I have 4 PNGs in there representing the 4 different objects that appear. My code is flexible enough for you to supply your own. Here is the image I am using for ships and here is the one for bullets just make copies, put them the source file and name them "Enemy-ship" "ship2" "Ebullet" and "PBullet"
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.JFrame;
public class GameController extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = -3599196025204169130L;
private static GameView window;
private static Timer time;
public GameController()
{
setTitle("Space Shooter");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
//window = new GameView(800,600);
//window.setVisible(true);
//
}
//TODO spawn
/*public static void main(String args[])
{
//GameController c = new GameController();
window = new GameView(800,600);
window.setVisible(true);
time = new Timer(40, this);
time.schedule( new TimerTask(){
public void run(){GameState.update();
window.paintComponents(null);}
},0, 40);
}*/
public void display() {
add(new GameView(800,600));
pack();
setMinimumSize(getSize());// enforces the minimum size of both frame and component
setVisible(true);
}
public static void main(String[] args) {
GameController main = new GameController();
main.display();
time = new Timer(40, main);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e instanceof EndEvent)//TODO fix this
{
}
else
{
repaint();
}
}
}
package Game;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class GameView extends JComponent implements ActionListener{
/**
*
*/
private static final long serialVersionUID = -2869672245901003704L;
private static final Graphics Graphics = null;
private boolean liveGame;//used so that buttons cannot be clicked after game is complete
private GameState gs;
private Player p;
private int w, h;
public GameView(int width, int height)
{
liveGame = true;
gs = new GameState();
GameState.init(width, height);
p = new Player(width/2,(height*7)/8);
this.setBackground(Color.BLACK);
paintComponents(Graphics);
w = width;
h = height;
}
#Override
public Dimension getMinimumSize() {
return new Dimension(w, h);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.black);
GameState.update();
for(Bullet j : GameState.getEnBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Enemy j : GameState.getEnemies()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Bullet j : GameState.getPlayBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
public void paintComponents (Graphics g)
{
for(Bullet j : GameState.getEnBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Enemy j : GameState.getEnemies()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Bullet j : GameState.getPlayBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
this.paint(g);
}
public void refreshImage()
{
this.removeAll();
paintComponents(Graphics);
}
public void actionPerformed(ActionEvent e) {
}
}
package Game;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
public class GameState {
private static ArrayList<Bullet> playBullets;
public static ArrayList<Bullet> getPlayBullets() {
return playBullets;
}
public static ArrayList<Bullet> getEnBullets() {
return enBullets;
}
public static ArrayList<Enemy> getEnemies() {
return enemies;
}
public static Player getP() {
return p;
}
private static ArrayList<Bullet> enBullets;
private static ArrayList<Enemy> enemies;
private static int X, Y;//for limit of screen so nothing can go outside of screen
private static Player p;
private static int score;
public GameState(){
}
public static void init(int x, int y)
{
playBullets = new ArrayList<Bullet>();
enBullets = new ArrayList<Bullet>();
enemies = new ArrayList<Enemy>();
X=x;
Y=y;
p = null;
score =0;
}
public static int xLimit(){return X;}
public static int yLimit(){return Y;}
public static int getScore(){return score;}
public static void add (Location e)
{
if(e instanceof Bullet)
{
if(((Bullet) e).getOwner() instanceof Enemy){
enBullets.add((Bullet) e);
}
else
playBullets.add((Bullet) e);
}
else if(e instanceof Enemy){enemies.add((Enemy)e);}
else
p=(Player)e;
}
public static void spawn()
{
Enemy e = new Enemy(((int)(Math.random()*(X-56))+28), 0, 1);
}
public static void playerCD()//detects if player has collided with anything, removes whatever collided with it, and causes the player to take damage
{
if(enemies.size()>0){
for(int i =0; i < enemies.size(); i++)
{
if (p.getLocation().intersects(enemies.get(i).getLocation()))
{
p.takeDamage(enemies.get(i).getDamage());
enemies.get(i).takeDamage(p.getDamage());
}
}
if(enBullets.size()>0)
for(int i =0; i < enBullets.size(); i++)
{
if (p.getLocation().intersects(enBullets.get(i).getLocation()))
{
p.takeDamage(enBullets.get(i).getDamage());
enBullets.remove(i);
i--;
}
}
}
}
public static void enemyCD()
{
for(int i =0; i < enemies.size(); i++)
{
for(int n =0; n < playBullets.size(); n++)
{
if (playBullets.get(n).getLocation().intersects(enemies.get(i).getLocation()))
{
enemies.get(i).takeDamage(playBullets.get(i).getDamage());
playBullets.remove(n);
n--;
score+=50;
}
}
}
}
public static void checkForDead()//clears away dead and things gone offscreen
{
for(int i =0; i < enemies.size(); i++)
{
if(enemies.get(i).getY()>Y)
{
enemies.remove(i);
i--;
}
}
for(int i =0; i < enBullets.size(); i++)
{
if(enBullets.get(i).getY()>Y)
{
enBullets.remove(i);
i--;
}
}
for(int i =0; i < enemies.size(); i++)
{
if(enemies.get(i).getHealth()>0)
{
enemies.remove(i);
i--;
score+=200;
}
}
if(p.getHealth()<=0)
{
ActionEvent e = new EndEvent(null, 0, "end");
}
}
public static void update()
{
move();
playerCD();
enemyCD();
checkForDead();
}
public static void move()
{
p.move();
for(int i =0; i < enemies.size(); i++){enemies.get(i).move();}
for(int i =0; i < enBullets.size(); i++){enBullets.get(i).move();}
for(int i =0; i < playBullets.size(); i++){playBullets.get(i).move();}
}
}
package Game;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
public abstract class Fights extends Location implements ActionListener {
public Fights(Rectangle location) {
super(location);
// TODO Auto-generated constructor stub
}
public Fights(){}
protected int health;
protected int maxHealth;//in the event that I want to have healing items
protected int shotCooldown;//in milliseconds
protected int shotDmg;
protected long currentCool; //cooldown tracker, represents time that shot will be cooled down by (System time # last shot + shotCooldown
protected int xVel, yVel;
public abstract boolean shoot();
public abstract int takeDamage(int damage);//returns remaining health
protected boolean shoots;//determines whether thing can shoot. possible implementation in some enemy class
public boolean move;
public int getHealth(){return health;}
public abstract boolean move();
public int getDamage(){return shotDmg;}
public boolean isDead()
{
return health<=0;
}
}
package Game;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
public class Location {
protected Rectangle loc;
protected Image image;
public Location(){};
public Location (Rectangle location)
{
loc = location;
}
public Rectangle getLocation()
{
return loc;
}
public void setLocation(Rectangle l)
{
loc = l;
}
public void updateLocation(int x, int y)
{
loc.setLocation(x, y);
}
public Image getImage()
{
return image;
}
public int getX()
{
return (int)loc.getX();
}
public int getY()
{
return (int)loc.getY();
}
}
package Game;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Player extends Fights implements KeyListener{
int speed = 4;
public Player(Rectangle location) {
super(location);
GameState.add(this);
image = null;
try{
image = ImageIO.read(new File("ship2.png"));
}catch(IOException e){}
}
public Player(int x, int y) {
maxHealth = 1;
health = maxHealth;
image = null;
try{
image = ImageIO.read(new File("ship2.png"));
}catch(IOException e){}
this.setLocation(new Rectangle(x, y, image.getWidth(null), image.getHeight(null)));
GameState.add(this);
}
public void resetVelocity()
{
xVel = 0;
yVel = 0;
}
#Override
public boolean shoot() {
if(currentCool - System.currentTimeMillis() >0){return false;}
else
{
new Bullet(this);
currentCool = System.currentTimeMillis() + shotCooldown;
}//spawns bullet in the center and slightly in front of player
return true;
}
#Override
public int takeDamage(int damage) {
return health-=damage;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
#Override
public boolean move() {//moves in a direction only if it won't exceed screen boundary, boolean just in case i need it later
int newX = this.getX(), newY=this.getY();
if((xVel+ this.getX()+this.getLocation().width)<GameState.xLimit()&& this.getX()+xVel>=0)
{
newX +=xVel;
}
if((yVel+ this.getY()+this.getLocation().height)<GameState.yLimit()&& this.getY()+yVel>=0)
{
newY +=yVel;
}
this.updateLocation(newX, newY);
this.resetVelocity();
return true;
}
#Override
public void keyPressed(KeyEvent arg0) {
if (arg0.getKeyCode()== KeyEvent.VK_LEFT)
{
xVel -= speed;
}
if (arg0.getKeyCode()== KeyEvent.VK_RIGHT)
{
xVel += speed;
}
if (arg0.getKeyCode()== KeyEvent.VK_UP)
{
yVel -= speed;
}
if (arg0.getKeyCode()== KeyEvent.VK_DOWN)
{
yVel += speed;
}
if(arg0.getKeyCode()==KeyEvent.VK_SPACE)
{
this.shoot();
}
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
package Game;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Enemy extends Fights {
public Enemy(Rectangle location) {
super(location);
GameState.add(this);
image = null;
try{
image = ImageIO.read(new File("Enemy-Ship.png"));
}catch(IOException e){}
}
public Enemy(int x, int y, int d) {
image = null;
try{
image = ImageIO.read(new File("Enemy-Ship.png"));
}catch(IOException e){}
this.setLocation(new Rectangle(x, y, image.getWidth(null), image.getHeight(null)));
GameState.add(this);
shotCooldown =(int)(Math.random()*2000);
xVel = (int)((Math.pow(-1, (int)(Math.random())))*((int)(Math.random()*6))+2);
yVel = (int)(Math.random()*3+1);
shotDmg =d;
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean shoot() {
if(currentCool - System.currentTimeMillis() >0){return false;}
else
{
new Bullet(this);
currentCool = System.currentTimeMillis() + shotCooldown;
}//spawns bullet in the center and slightly in front of player
return true;
}
#Override
public int takeDamage(int damage)//returns remaining health
{
health = health-damage;
return health;
}
#Override
public boolean move() {
int newX = this.getX(), newY=this.getY();
if((xVel+ this.getX()+this.getLocation().width)<GameState.xLimit()&& this.getX()+xVel>=0)
{
xVel=-xVel;
newX +=xVel;
}
if(this.getY()+yVel>=0)
{
newY +=yVel;
}
this.updateLocation(newX, newY);
return true;
}
}
package Game;
import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Bullet extends Location{
private Fights bulletOwner;
private int damage;
private int velocity;
public Bullet(Fights owner)//eventually change to singleton pattern for efficiency
{
bulletOwner = owner;
damage = owner.getDamage();
image = null;
if(owner instanceof Enemy)
{
try{
image = ImageIO.read(new File("Ebullet.png"));
}catch(IOException e){}
this.setLocation(new Rectangle(owner.getX(), owner.getY()+((int)(owner.getLocation().getHeight()/2)), image.getWidth(null), image.getHeight(null)));
velocity = 5;
}
else
{
try{
image = ImageIO.read(new File("Pbullet.png"));
}catch(IOException e){}
this.setLocation(new Rectangle(owner.getX(), owner.getY()-((int)(owner.getLocation().getHeight()/2)), image.getWidth(null), image.getHeight(null)));
velocity = -15;
}
GameState.add(this);
}
public Fights getOwner(){return bulletOwner;}
public int getDamage(){return damage;}
public int getVelocity(){return velocity;}
public boolean move()
{
this.updateLocation(this.getX(), this.getY()+velocity);
return true;
}
}
I can't believe your write 700 lines of code without doing any testing along the way. Its time you go back to the beginning and start with something simple. That is the whole point of a SSCCE. Start with painting a couple of compononents. Once you get that working you add some movement. Once that is working you add collision logic.
The only thing I noticed with a quick broswe is that you override paintComponents(). There is no need to do that custom painting is done in the pantComponent() method.
If you can't produce a smaller sized SSCCE, then all I can do is wish you good luck.
Ok, so I think I have figured most of it out.
You have a couple problems.
First, you should only see a grey screen with a black rectangle in the middle since you have nothing in your Bullet and Enemy Arrays. This is what I got when I ran your code (after removing references to endEvent cuz it couldn't find it). So to fix this, just give it something to draw
The second problem is apparent once you give it something to draw. I manually put in a line of code to draw the Player, for which I used one of my own pngs. When you do this it will fail to compile with a null pointer exception. The reason is because in your GameView class, you have your Graphics object called "graphics" set to null, but then you proceed to call paintComponents(graphics). As mentioned before, this only compiled before because you never actually drew anything. To fix this, you can just remove
public void paintComponents (Graphics g)
{
for(Bullet j : GameState.getEnBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Enemy j : GameState.getEnemies()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Bullet j : GameState.getPlayBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
this.paint(g);
}
and let the overridden paintComponent(Graphics g) method above it do all the work. Additionally, instead of the paintComponents(graphics) calls, use repaint(). Also you can get rid of the first call to paintComponents(graphics) in the constructor as it will paint the first time by default. If you really want to use your own method then you have to create a Graphics object and pass that in.
Lastly, in the overridden paintComponents(Graphics g) method, you have the last line being to draw the giant black box. This will then cover up anything you've drawn before. So you should have that as the first line and draw everything else in order such that the thing you want to be on top should be drawn last. I was able to get my test image to show up with the following code for that class. I don't think I changed anything else.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class GameView extends JComponent implements ActionListener{
/**
*
*/
private static final long serialVersionUID = -2869672245901003704L;
private boolean liveGame;//used so that buttons cannot be clicked after game is complete
private GameState gs;
private Player p;
private int w, h;
public GameView(int width, int height)
{
liveGame = true;
gs = new GameState();
GameState.init(width, height);
p = new Player(width/2,(height*7)/8);
this.setBackground(Color.BLACK);
w = width;
h = height;
}
#Override
public Dimension getMinimumSize() {
return new Dimension(w, h);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.black);
GameState.update();
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
for(Bullet j : GameState.getEnBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Enemy j : GameState.getEnemies()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
for(Bullet j : GameState.getPlayBullets()){
g.drawImage(j.getImage(),j.getX(), j.getY(), null);}
g.drawImage(p.getImage(),p.getX(),p.getY(),null);
}
public void refreshImage()
{
this.removeAll();
repaint();
}
public void actionPerformed(ActionEvent e) {
}
}
The other thing is in some of your other classes you have #Override over the actionPerformed method. My IDE doesn't like that, although it does compile. It says "#Override is not allowed when implementing interface methods."
Hopefully this works for you.
try adding repaint(); after you make a change to a content pane. I dont think concurrency is going to be a problem unless you clog up your EDT.