Cannot locate cause of nullpointer when using .getWidth() - java

I have a hard time locating why I am returned a nullpointer on this piece of code:
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Move {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int x_1 = 1;
int y_1 = 1;
private GameStart game;
public void Ball(GameStart game) {
this.game = game;
}
void moveBall() {
if (x + x_1 < 0) {
x_1 = 1;
}
if (x + x_1 > game.getWidth() - DIAMETER) {
x_1 = -1;
}
if (y + y_1 < 0) {
y_1 = 1;
}
if (y + y_1 > game.getHeight() - DIAMETER) {
game.gameOver();
}
if (collision()) {
y_1 = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x + x_1;
y = y + y_1;
}
private boolean collision() {
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
public Rectangle getBounds() {
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
And the GameStart class is here:
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
#SuppressWarnings("serial")
public class GameStart extends JPanel {
Move move_ball = new Move();
Racquet racquet = new Racquet(this);
public GameStart() {
addKeyListener(new MyKeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
private void move() {
move_ball.moveBall();
racquet.move();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D graphics = (Graphics2D) g;
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
move_ball.paint(graphics);
racquet.paint(graphics);
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "Spil slut", "Du tabte", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main (String[] args) throws InterruptedException {
JFrame mainWindow = new JFrame("Matematikken");
GameStart game = new GameStart();
mainWindow.add(game);
mainWindow.setSize(300, 400);
mainWindow.setVisible(true);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
}
I am getting a nullpointer on the line if (x + x_1 > game.getWidth() - DIAMETER) {. I am using .getWidth() in the samme manner in another class and it Works fine - but for some reason it wont in this. I've tried printing the result but that is just another nullpointer. I know i am missing something but I cannot locate it.

You are not calling
public void Ball(GameStart game) {
this.game = game;
}
That's why in your Move class, GameStart is still null.

Seems like you wanted that method
public void Ball(GameStart game) { this.game = game; }
to actually be a constructor:
public Move(GameStart game) { this.game = game; }
And then, you must use this constructor (as there is no no-arg constructor anymore) when instantiating a Move:
Move move_ball = new Move(this);

You have not yet set the member variable game of the instance move_ball of the type Move to a value so it is null and therefore throws a NullPointerException.
You'll want to instantiate this member variable, for example by calling move_ball.Ball(<some Game instance>).
Also, please don't let methods which are not constructors start with a capital and please use camelCase throughout instead of switching between name formatting. It makes your code hard to read.

You do not pass GameStart to Move via your Ball method. It is very misleading name. It should be setGame or something else.

You should make a constructor for the Move class, which takes the game as a parameter, and store that parameter in a variable within the class.
Example:
Public Move(GameStart mygame){
game = mygame;
}
This should allow you to use the methods of the game from which you are creating the move. It will basically replace the "Ball" method you have.

Related

Game class not calling other classes

I am new to java code that is fresh code (I used to make minecraft mods) and I am trying to create a simple pong game. I have everything I believe I need for the game to play properly however it seems that the main game class is not calling the other classes when I need it to. Is there anything wrong here that you can see that I am missing? It would be a really great help.
Main Game Class
package crim.pong.main;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel{
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
Ball ball = new Ball(this);
Racquet racquet = new Racquet(this);
private void moveBall(){
ball.move();
racquet.move();
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, 30, 30);
ball.paint(g2d);
racquet.paint(g2d);
}
public void gameOver(){
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main(String[] args) throws InterruptedException{
JFrame frame = new JFrame("Pong");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while(true){
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
}
Keyboard class
package crim.pong.main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class KeyboardInput extends JPanel{
public KeyboardInput(){
KeyListener listener = new MyKeyListener();
addKeyListener(listener);
setFocusable(true);
}
public static void main(String[] args){
JFrame frame = new JFrame("Pong");
KeyboardInput keyboardInput = new KeyboardInput();
frame.add(keyboardInput);
frame.setSize(200, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public class MyKeyListener implements KeyListener{
#Override
public void keyTyped(KeyEvent e){
}
#Override
public void keyPressed(KeyEvent e){
System.out.println("keyPressed="+KeyEvent.getKeyText(e.getKeyCode()));
}
#Override
public void keyReleased(KeyEvent e){
System.out.println("keyReleased="+KeyEvent.getKeyText(e.getKeyCode()));
}
}
}
Ball class
package crim.pong.main;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
public Ball(Game game){
this.game = game;
}
void move(){
if(x + xa < 0)
xa = 1;
if(x + xa > game.getWidth() - DIAMETER)
xa = -1;
if(y + ya < 0)
ya = 1;
if(y + ya > game.getHeight() - DIAMETER)
game.gameOver();
if(collision()){
ya = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x - xa;
y = y - ya;
}
private boolean collision(){
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g){
g.fillOval(x, y, 30, 30);
}
public Rectangle getBounds(){
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
Racquet class
package crim.pong.main;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet {
private static final int Y = 330;
private static final int WIDTH = 60;
private static final int HEIGHT = 20;
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game){
this.game = game;
}
public void move(){
if(x + xa > 0 && x + xa < game.getWidth() - 60)
x = xa + xa;
}
public void paint(Graphics2D g){
g.fillRect(x, 330, 60, 10);
}
public void keyReleased(KeyEvent e){
xa = 0;
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public Rectangle getBounds(){
return new Rectangle(x, Y, WIDTH, HEIGHT);
}
public int getTopY(){
return Y;
}
}
As mentioned in the comments you have 2 main class files. This is wrong.
A class with a 'main' function is the entry point of the program and obviously there can be only one entry point and presumably you have set this as 'Game'.
KeyboardInput should also not try to create a new JFrame. You only need one and it should be created by your 'Game' class.
If you want to keep the keyboard input in a seperate class then you want 'KeyboardInput' to implement KeyListener directly and then add it to the jframe created by 'Game', e.g.
(In 'Game')
KeyboardInput listener = new KeyboardInput();
addKeyListener(listener);
(In 'KeyboardInput')
public class KeyboardInput implements KeyListener
{
public void keyTyped(KeyEvent e){
//... etc etc

Why does it wants the method to be static?

I am building my first game, relying heavily on various tutorials and guides on the Java website, and I have come across a problem.
In my game engine, I want to call the Player.update() method, but it says it has to be static (cannot make static reference to non-static method)
However, the method calling it is not static. Can anyone tell me why it requires it to be static? It doesn't require the only other method in Update to be static.
package Main;
import java.awt.*;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import Graphics.Assets;
import Sprites.Player;
#SuppressWarnings("serial")
public class Game extends JPanel
implements Runnable, KeyListener{
//TEST CODE
private int x = 0;
private int y = 0;
private int dY = 1;
private int dX = 1;
public void moveBall() {
x = x + dX;
y = y + dY;
if(x > WIDTH - 28) {
dX = -1;
}
if(y > HEIGHT) {
dY = -1;
}
if(x < 0) {
dX = 1;
}
if(y < 10) {
dY = 1;
}
}
//dimensions
public static final int WIDTH = 400;
public static final int HEIGHT = 300;
public static final int SCALE = 2;
//game thread
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000 / FPS;
//image
private BufferedImage image;
private Graphics2D g;
//Constructor
public Game () {
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if(thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
private void init () {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D)image.getGraphics();
running = true;
Assets.init();
}
public void run() {
init();
long start;
long elapsed;
long wait;
//game loop
while(running){
start = System.nanoTime();
update();
draw(g);
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if(wait < 0) wait= 5;
try {
Thread.sleep(wait);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
private void update() {
moveBall();
Player.update();
}
private void draw(Graphics g2d) {
super.paint(g2d);
Graphics2D g = (Graphics2D) g2d;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.drawString("Hello", x, y);
}
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g2.dispose();
}
public void keyPressed(KeyEvent e){}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
}
That is the main code. Now for the Player class.
package Sprites;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import Main.Game;
import Graphics.*;
public class Player extends Creature implements KeyListener{
private int dir;
public Player(Game game, float x, float y) {
super(game, x, y, Creature.DEFAULT_CREATURE_WIDTH, Creature.DEFAULT_CREATURE_HEIGHT);
dir = 0;
}
public void update() {
getInput();
move();
}
private void getInput() {
xMove = dir;
}
public void render(Graphics g) {
g.drawImage(Assets.player, (int) (x), (int) (y), width, height, null);
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_A)
dir = -1;
if(e.getKeyCode() == KeyEvent.VK_D)
dir = 1;
else dir = 0;
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_A)
dir = 0;
if(e.getKeyCode() == KeyEvent.VK_D)
dir = 0;
}
public void keyTyped(KeyEvent e) {
}
}
Look at your method call:
Player.update();
That's calling it as if it's a static method - on the type, rather than on an instance of the type. Which player do you want to update? You don't seem to have any instances of it... you should almost certainly be creating an instance of Player within Game, and saving a reference to it.
You have called update() method of Player like this -
private void update() {
moveBall();
Player.update();
}
Here you did not create the object of Player. So the compiler expect the update() method is static. To resolve the problem you may do either of -
1. Make update() of player static. Or -
2. Create an instance/object of Player inside your Game class as a field/property before calling update() method of Player class -
Player aPlayer = new Player(.....);
.....
.....
.....
private void update(){
moveBall();
aPlayer.update();
}

Can't figure out how to repaint

So I have this little project where I make the mario jump. But I can't figure out how to repaint it. If I do it in the Main class after a click, then the whole jumping will be very jerky.
I tried to do it at the end of my jump function but that did not work too.
Here is my code:
Main:
package klassid;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Main extends JComponent implements KeyListener, ActionListener{
static Hero hero;
Timer t = new Timer(500,this);
public static void main(String[] args) {
JFrame aken = new JFrame("Simple jumping simulator");
aken.setSize(600, 600);
aken.getContentPane().setBackground(new Color(255,255,255));
aken.getContentPane().add(new Main());
aken.setVisible(true);
aken.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
hero.the_jump();
}
public Main(){
addKeyListener(this);
setFocusable(true);
t.start();
hero = new Hero(0, 320);
}
public void paintComponent(Graphics g){
hero.render(g, this);
g.setColor(Color.GREEN);
g.fillRect(0, 550, 600, 2);
}
#Override
public void keyPressed(KeyEvent e) {
hero.move(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
hero.move2(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {}
public void actionPerformed(ActionEvent e) {}
}
And my Hero class:
package klassid;
import java.awt.Toolkit;
import java.awt.Image;
import java.awt.Graphics;
public class Hero {
static Main main;
int y;
Image pilt = Toolkit.getDefaultToolkit().getImage("../mario.png");
private double height = 0, speed = 4;
public static final double gravity = 9.81;
private double x = 25;
private boolean left = false, right = false, up = false;
public Hero(int x, int y){
this.x = x;
this.y = y;
}
public void render(Graphics g, Main pohiKlass){
g.drawImage(pilt, (int) (x), (int) (500-(height*100)), 50, 50, pohiKlass);
}
public void the_jump() {
long previous = 0, start = 0;
while(true){
start= System.nanoTime();
if(previous != 0 && up){
double delta = start - previous;
height += (delta/1000000000) * speed;
speed -= (delta/1000000000) * gravity;
}
if(left)
x -= 3;
if(right)
x += 3;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(height < 0){
height = 0;
speed = 4;
up = false;
}
previous = start;
repaint();
}
}
public void move(int i){
if(i == 38)
up=true;
if(i == 37)
left=true;
if(i == 39)
right=true;
}
public void move2(int i){
if(i == 37)
left=false;
if(i == 39)
right=false;
}
}
I also tried to access the paintComponent in the_jump function but it did not work as I have no idea what kind of a parameter it expects.
How is this mess solvable?
The first line in your paintComponent method should be:
super.paintComponent(g);
JComponent will do a lot of things for you, but you need to explicitly call the super class method to do so. Take a look at the Oracle Documentation here.
You could call repaint() in your actionPerformed method, if you decrease the timer value to something very low. This will give you "continuous" repainting (as many times a second as you can reasonably perform).

How to paint another object when the first one is offscreen?

I need to make a system where a obstacle is drawn on the screen, when it scrolls off the screen, another one will be drawn at a random value (up to a max of a certain value) on the screen after that one.
I have some code here:
public int xElapsed = 0;
this is just incremented all the time, it is how much the player has moved.
obstacleHole.paint(g);
if(obstacleHole.getX() <= 0){
obstacleHole.paint(g);
}
This is the paint function. The first obstacle is painted straight away, and the second after that condition is met. This is not working as intended, however.
x = position.nextInt(500 + player.xElapsed * 2);
and this is how the x coordinate of the obstacle is set. "position" is a random value generator.
This code is not working because only one obstacle ever shows up. How can I fix this to work as intended? I can provide extra code if necessary.
Here is the ObstacleHole class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Random;
public class ObstacleHole {
Player player = new Player();
Random position = new Random();
int x;
int y;
int dx = 1;
int width = 100;
int height = 100;
public ObstacleHole(){
x = position.nextInt(500 + player.xElapsed * 2);
y = 250;
}
public void move(){
x = x - player.playerSpeed;
}
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
public Rectangle bounds(){
return (new Rectangle(x, y, width, height));
}
public int getX() {
return x;
}
}
Screen.java
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Screen extends JPanel implements ActionListener, KeyListener{
Player player = new Player();
ObstacleHole obstacleHole = new ObstacleHole();
public Screen(){
addKeyListener(this);
setDoubleBuffered(true);
setFocusable(true);
Timer tick = new Timer(5, this);
tick.start();
}
public void actionPerformed(ActionEvent e) {
repaint();
player.move();
obstacleHole.move();
System.out.println(player.getXElapsed());
}
public void paint(Graphics g){
super.paint(g);
player.paint(g);
obstacleHole.paint(g);
if(obstacleHole.getX() <= 0){
obstacleHole.paint(g);
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(player.jumpReady){
if(key == KeyEvent.VK_UP){
player.dy = -1;
player.jumpReady = false;
}
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
Player.java
import java.awt.Color;
import java.awt.Graphics;
public class Player {
int x;
int y;
int dx;
public int xElapsed = 0;
public int dy;
int width = 64;
int height = 64;
public int playerSpeed = 3;
public boolean isMoving = true;
public boolean hasJumped = false;
public boolean jumpReady = true;
public Player(){
x = 150;
y = 250;
}
public void move(){
x = x + dx;
y = y + dy;
xElapsed++;
if(hasJumped == true){
dy = -1;
}
if(y == 150){
dy = 1;
}
if(y == 250){
dy = 0;
jumpReady = true;
}
}
public void paint(Graphics g){
g.setColor(Color.RED);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getXElapsed(){
return xElapsed;
}
}
In your code you are painting obstacleHole, then when the x value of obstacleHole is less than or equal to 0, you draw it again. All you are doing is sending two calls to the paint() method of the same object.
If you want to paint a second one, you will need to create another object. Or, alternatively, move the original object back onto the screen after it leaves.
It is hard to give you sample code when you have provided so little context, but try something like this:
MyObject obstacleHoleA = new MyObject();
MyObject obstacleHoleB = new MyObject();
obstacleHoleA.paint(g);
if(obstacleHoleA.getX() <= 0){
obstacleHoleB.paint(g);
}
Or this:
obstacleHole.paint(g);
if(obstacleHole.getX() <= 0){
obstacleHole.setX(randomValueUpToAMaxOfCertainValue);
}
Edit: There are a lot of things I would do a lot differently with the above code, but they are outside the scope of the question.
Try this for your ObstacleHole class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Random;
public class ObstacleHole {
Player player = new Player();
Random position = new Random();
int x;
int y;
int dx = 1;
int width = 100;
int height = 100;
public ObstacleHole(){
x = getNewPosition();
y = 250;
}
public void move(){
x = x - player.playerSpeed;
if(x < 0 - width) {
x = getNewPosition();
}
}
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
public Rectangle bounds(){
return (new Rectangle(x, y, width, height));
}
public int getX() {
return x;
}
private int getNewPosition() {
return 200 + position.nextInt(300);
}
}
Note the change to the constructor and move() method, along with the new method getNewPosition().

Graphics not appearing in JFrame (SSCCE included)

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.

Categories

Resources