I am trying to make my own engine but I need some help.
I am currently doing the level system. The level class extends the render class and the level class overides the Render classes render method. Finally the render class is called from the main class but I dont call the level class.
EDIT:
I have removed the static but now cannot call the render method. I know I am very nooby I kind of teach my self.
package SimpleEngine.Render;
Render Class (This is called)
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import SimpleEngine.Primitives.*;
import static org.lwjgl.opengl.GL11.glClear;
public class Render {
public void Render() {
}
}
Level Class (This is not called) I want this Render method to override the Render classes render method but it doesn't work.
package SimpleEngine.Level;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.glClear;
import SimpleEngine.Render.*;
import SimpleEngine.Primitives.*;
public class Level extends Render {
public void Render() {
glClear(GL_COLOR_BUFFER_BIT);
Primitives.DrawSquare(200, 200, 50, 50, 1, 0, 0);
}
}
My main method (calls render but cannot anymore)
package SimpleEngine;
import org.lwjgl.LWJGLException;
import SimpleEngine.Level.*;
import SimpleEngine.Logic.*;
import SimpleEngine.Input.*;
import SimpleEngine.Render.*;
import SimpleEngine.Entites.*;
import SimpleEngine.Timer.*;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
public class simpleEngine {
public static final int WIDTH = 640;
public static final int HEIGHT = 480;
private static boolean isRunning = true;
public static void main(String[] args) {
setUpDisplay();
setUpOpenGL();
Entity.setUpEntities();
Timer.setUpTimer();
while (isRunning) {
Render.Render();
Logic.logic(Timer.getDelta());
Input.input();
Display.update();
Display.sync(60);
if (Display.isCloseRequested()) {
isRunning = false;
}
}
Display.destroy();
System.exit(0);
}
private static void setUpDisplay() {
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.setTitle("SimpleEngine");
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
Display.destroy();
System.exit(1);
}
}
private static void setUpOpenGL() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 480, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
}
}
You can't override static methods.
As per Oracle tutorail
If a subclass defines a class method with the same signature as a class method in the superclass, the method in the subclass hides the one in the superclass.
AND
You will get a compile-time error if you attempt to change an instance method in the superclass to a class method in the subclass, and vice versa.
Remove static from Render class render() method and change Level class Render method to render() to introduce overriding behavior
EDIT:
while (isRunning) {
new Level().Render();
Note: Java naming convention suggests that method name should start with small letter and name should be camelcase.
You can't override a static method.
Also, be careful because Java is a case sensitive language, so Render() is not the same as render(), and could be a completely different method.
I would recommend doing something more generic such as having an interface which defines common methods for any state your game could be in which actually looks like the direction you're heading in. This would just combine your Logic and Render classes. For example:
public Interface IGameState {
public void update(int delta);
public void render();
}
And then you can have a class that implements that interface such as:
public class InGameState implements IGameState {
public InGameState() { }
// This is similar to your Logic class
public void update(int delta) {
// Perform any updates necessary such as handling keyboard input
}
public void render() {
// What you included in your example
glClear(GL_COLOR_BUFFER_BIT);
Primitives.DrawSquare(200, 200, 50, 50, 1, 0, 0);
}
}
And then your main method could look something like this:
public static final int WIDTH = 640;
public static final int HEIGHT = 480;
private static boolean isRunning = true;
private IGameState currentGameState;
public static void main(String[] args) {
setUpDisplay();
setUpOpenGL();
Entity.setUpEntities();
Timer.setUpTimer();
// Create a new game state
currentGameState = new InGameState();
while (isRunning) {
// Change to this type of thing
// The delta would be the time since last frame so you can stay frame rate
// independent
currentGameState.update(delta);
currentGameState.render();
Display.update();
Display.sync(60);
if (Display.isCloseRequested()) {
isRunning = false;
}
}
Display.destroy();
System.exit(0);
}
Related
I use this class for my school app projects. It is how I set the application up and it extends JFrame and implements Runnable. Now whenever I use this in school on a Windows computer and everything works and the screen updates, but at home on a Mac it doesn't. I use Eclipse neon with JDK 1.8.0_101
Please help me out, I can't test any projects at home cause of this.
import java.awt.Graphics;
import javax.swing.JFrame;
public abstract class GUIApplication extends JFrame implements Runnable{
private Screen currentScreen;
//no main, cant instentiate an abstract class
public GUIApplication(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int x=40;
int y=40;
int width=1000;
int height=640;
setBounds(x,y,width,height);
initScreen();
setVisible(true);
}
//this is a method for creating the starting screen
protected abstract void initScreen();
public void setScreen(Screen screen){
//stop controls from previous screen
removeListeners();
setCurrentScreen(screen);
//add new controls
addListeners();
}
private void removeListeners(){
if(getCurrentScreen() != null){
if(getCurrentScreen().getMouseListener() != null) removeMouseListener(getCurrentScreen().getMouseListener());
if(getCurrentScreen().getMouseMotionListener() != null) removeMouseMotionListener(getCurrentScreen().getMouseMotionListener());
if(getCurrentScreen().getKeyListener() != null) removeKeyListener(getCurrentScreen().getKeyListener());
// if(currentScreen.getMouseWheelListener() != null) removeMouseWheelListener(currentScreen.getMouseWheelListener());
}
}
private void addListeners(){
if(getCurrentScreen() != null){
if(getCurrentScreen().getMouseListener() != null)addMouseListener(getCurrentScreen().getMouseListener());
if(getCurrentScreen().getMouseMotionListener() != null) addMouseMotionListener(getCurrentScreen().getMouseMotionListener());
if(getCurrentScreen().getKeyListener() != null){
addKeyListener(getCurrentScreen().getKeyListener());
}
// if(currentScreen.getMouseWheelListener() != null) addMouseWheelListener(currentScreen.getMouseWheelListener());
}
}
public void paint(Graphics g){
g.drawImage(getCurrentScreen().getImage(), 0, 0, null);
}
public void run(){
while(true){
getCurrentScreen().update();
repaint();
try {
Thread.sleep(30);
repaint();
revalidate();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public Screen getCurrentScreen() {
return currentScreen;
}
public void setCurrentScreen(Screen currentScreen) {
this.currentScreen = currentScreen;
}
}
This is how a game would start:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.ArrayList;
import javax.swing.JFrame;
import game.mainScreenTeam.Dragon;
import game.mainScreenTeam.HomeScreen;
import game.miniGameTeam.GameInstructions;
import game.miniGameTeam.GameScreen;
import game.miniGameTeam.HighScoreScreen;
import game.shopScreen.BuyScreenWendy;
import game.shopScreen.HomeShopScreen;
import game.shopScreen.SellShopZheng;
import guiPractice.GUIApplication;
import guiPractice.Screen;
import guiPractice.components.AnimatedComponent;
/**
* #author Kat
*
*/
public class DragonLand extends GUIApplication {
public static DragonLand game;
public static int coins = 1500;
public static HomeScreen homeScreen;
public static Screen shopMain; // shop 1
public static Screen sellScreen; // shop 2
public static Screen buyScreen; // shop 3
public static Screen highscoreScreen; // high score
public static GameScreen miniGameScreen; // minigame
public static Screen gameInstructionsScreen;
public static Screen HelpScreen;
public static Color NAVY;
public static Color BRIGHT_PINK;
public static Color LIGHT_PINK;
public static Color LIGHT_NUDE;
public static Color DARKER_NUDE;
/**
*
*/
// public static void addDragon(AnimatedComponent a){
// dragonList.add(a);
// }
public DragonLand() {
}
/* (non-Javadoc)
* #see guiPractice.GUIApplication#initScreen()
*/
#Override
protected void initScreen() {
initColors();
miniGameScreen = new GameScreen(getWidth(),getHeight());
shopMain = new HomeShopScreen(getWidth(),getHeight());
sellScreen = new SellShopZheng(getWidth(),getHeight());
homeScreen = new HomeScreen(getWidth(),getHeight());
buyScreen = new BuyScreenWendy(getWidth(),getHeight());
highscoreScreen = new HighScoreScreen(getWidth(),getHeight());
HomeScreen.jenCode = new game.mainScreenTeam.HomeJenniber();
gameInstructionsScreen = new GameInstructions(getWidth(), getHeight());
setScreen(homeScreen);
}
private void initColors() {
NAVY = new Color(62,74,99);
BRIGHT_PINK = new Color(224,102,102);
LIGHT_PINK = new Color(248,186,182);
LIGHT_NUDE = new Color(244,215,183);
DARKER_NUDE = new Color(230,195,147);
}
/**
* #param args
*/
public static void main(String[] args) {
game = new DragonLand();
Thread go = new Thread(game);
go.start();
}
//public coin getter + setter
public void setCoins(int x){
coins = x;
}
public int getCoins(){
return coins;
}
}
This is the home screen
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import game.DragonLand;
import guiPractice.ClickableScreen;
import guiPractice.components.Action;
import guiPractice.components.AnimatedComponent;
import guiPractice.components.Button;
import guiPractice.components.Graphic;
import guiPractice.components.TextLabel;
import guiPractice.components.Visible;
import guiPractice.sampleGames.MouseFollower;
/**
* #author Kat
* #author Jenniber
*
*/
public class HomeScreen extends ClickableScreen implements Runnable{
private Graphic background;
public static HomeJenniber jenCode;
public HomeScreen(int width, int height) {
super(width, height);
Thread play = new Thread(this);
play.start();
}
#Override
public void initAllObjects(ArrayList<Visible> viewObjects) {
background=new Graphic(0,0,getWidth(),getHeight(),"img/Grassland.png");
viewObjects.add(background);
HomeKat katCode=new HomeKat(viewObjects, getWidth(), getHeight());
}
#Override
public void run() {
}
}
katCode adds buttons to the screen and image annimations
public void paint(Graphics g){
g.drawImage(getCurrentScreen().getImage(), 0, 0, null);
}
Don't override paint() on a JFrame.
The proper way to do custom painting is to override paintComponent(...) on a JPanel (or JComponent) and then you can set the content pane of the frame to this panel. And don't forget to invoke super.paintComponent(...) as the first statement in the method. Read the section from the Swing tutorial on Custom Painting for more information and working examples.
However if you do get lazy, then at minimum you need to invoke super.paint(...) as the first statement in the paint(...) method.
Also, I doubt you need the revalidate(), since you don't appear to be adding/removing components from the frame.
But in general the order should be:
revalidate(); // to invoke the layout manager
repaint(); // paint components in new location.
I also don't know why you are invoking the update() method. That seems like old AWT code which you don't use in Swing. I suggest you take a look at the tutorial link I gave you and look at the table of contents for other Swing basics.
I am trying to start my game from a Main Menu class that implements NiftyGUI. I am using OpenGL (LWJGL) and Java. The problem is that I am never able to get the main menu to disappear and then start the game class, which is World.java.
The following is what I would usually do when I have no main menu.
package com.dev.voxy;
import com.dev.voxy.utilities.GLScreen;
import com.dev.voxy.world.World;
public class Main extends GLScreen {
public static int WIDTH = 1280;
public static int HEIGHT = 720;
private World world;
public static void main(String[] args) {
Main main = new Main();
main.GLScreen(WIDTH, HEIGHT, false, 60, "Voxy");
}
#Override
public void init() {
world = new World();
}
#Override
public void update() {
world.update();
}
#Override
public void dispose() {
world.dispose();
}
That is my main class and extends GLScreen
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;
public abstract class GLScreen {
protected static int SCREEN_WIDTH;
protected static int SCREEN_HEIGHT;
protected boolean FULL_SCREEN;
protected static int FPS = 60;
protected static String SCREEN_TITLE;
private static long lastFPS;
private static int lfps;
public static int fps;
public void GLScreen(int width, int height, boolean fullscreen, int sync, String title) {
this.SCREEN_HEIGHT = height;
this.SCREEN_WIDTH = width;
this.FULL_SCREEN = fullscreen;
this.FPS = sync;
this.SCREEN_TITLE = title;
InitScreen();
}
public void InitScreen() {
createWindow();
InitGL();
init();
Run();
}
void createWindow() {
try {
Display.setFullscreen(FULL_SCREEN);
Display.setTitle(SCREEN_TITLE);
DisplayMode displayMode = new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT);
Display.setDisplayMode(displayMode);
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
}
}
void InitGL(){
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glViewport(0, 0, Display.getWidth(), Display.getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(67.0f, SCREEN_WIDTH / SCREEN_HEIGHT, 0.001f, 1000f); //TODO watch coding universe video
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
lastFPS = getTime();
}
public abstract void init();
public abstract void update();
public static int getFPS() {
int cfps;
if (getTime() - lastFPS > 1000 && lfps != fps) {
lfps = fps;
fps = 0; //reset the FPS counter
lastFPS += 1000; //add one second
cfps = fps;
} else {
cfps = lfps;
}
fps++;
return cfps;
}
public static long getTime() {
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
void Run(){
while(!Display.isCloseRequested()){
try{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0, 0, 0f, 0f);
glLoadIdentity();
update();
Display.update();
Display.sync(FPS);
} catch (Exception e){
e.printStackTrace();
}
}
dispose();
destroy();
}
public abstract void dispose();
public void destroy() {
Display.destroy();
System.exit(0);
}
}
And finally my World Class is below.
import com.dev.voxy.Main;
import org.lwjgl.opengl.Display;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
public class World extends WorldManager {
private Chunk chunk;
public World() {
super(Main.WIDTH, Main.HEIGHT);
init();
}
#Override
public void init() {
chunk = new Chunk(0, 0, 0);
setRenderStats(true);
}
public void update() {
input();
render();
}
public void render() {
render3D();
Translate();
chunk.render();
glLoadIdentity();
if (isRenderStats()) {
render2D();
glColor3f(1, 1, 1);
renderStats();
}
}
#Override
public void dispose() {
chunk.dispose();
Display.destroy();
System.exit(0);
}
}
The problem is that when I try and incorporate my Menu into this it never works. First I tried GameStates so that whenever the game state is GAME the nifty should no longer render but this causes the Window to close because nifty no longer keeps it open, so then I tried to have the loop be outside the MainMenu Class but that also did not work because I kept running into static/non-static errors which I could not figure out. Then my last idea was why not try and put the gameloop inside the MainMenu Class but try to stop the nifty render while I try to start the game, but that left elements of the nifty on the screen and the rest was blank and the World class did not render. The following are my current Main, MainMenu, GLScreen and MyScreenController and MainMenu.xml files The MyscreenController controls what happens when the respective buttons are pressed and the MainMenu.xml is the nifty xml file that lays out everything.
All relevant files and classes may be found at the following link, they are the current ones where I am trying to get the main menu working. The classes shown above show what I did to get ONLY the game part working in the first place, without a menu.
LINK
To sum up, I can get my game working when there is not main menu and I can get my main menu working when there is no game, I have tried as many things I can think of but after 3 days I'm simply lost and would like any suggestion/recommendation or idea. I think I just can't figure out how to manage game states and the game loop when there is a main menu and a game, I was thinking maybe if there was a way to stop nifty completely then clear the screen then set OpenGL to 3D I can get my game rendered, this is what I was trying to do near the end but could not figure it out.
Thank you.
I am getting a error that looks like this,
run:
Exception in thread "main" java.lang.ExceptionInInitializerError
at ao.Game.main(Game.java:11)
Caused by: java.lang.RuntimeException: Uncompilable source code -
ao.Panel is not abstract and does not override abstract method
keyReleased(java.awt.event.KeyEvent) in java.awt.event.KeyListener
at ao.Panel.<clinit>(Panel.java:15)
... 1 more
Java Result: 1
BUILD SUCCESSFUL (total time: 3 seconds)
I can't figure out what the problem with the public class is.
There are 2 separate files below.
Game.java
Panel.java
First File:
package ao;
import ao.Panel;
import javax.swing.JFrame;
public class Game {
public static void main(String[] args) {
JFrame frame = new JFrame("2D Shooter Pre-Alpha");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new Panel());
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Next File:
package ao;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
/**
*
* #author andyoppenheimer
*/
public class Panel extends JPanel implements Runnable, KeyListener {
// panel dimensions
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 2;
// main loop
private Thread thread;
private boolean running = false;
private int fps = 60;
private long targetTime = 1000 / fps;
// drawing
private Graphics2D g;
private BufferedImage image;
public Panel() {
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
running = true;
addKeyListener(this);
thread = new Thread(this);
thread.start();
}
}
public void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
}
public void update() {
}
public void draw() {
g.clearRect(0, 0, WIDTH, HEIGHT);
}
public void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g2.dispose();
}
public void run() {
init();
long start;
long elapsed;
long wait;
while (running == true) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void KeyPressed(KeyEvent k) {
}
public void KeyReleased(KeyEvent k) {
}
public void KeyTyped(KeyEvent k) {
}
}
In java methods starts with lower case keyTyped keyReleased and keyPressed so you are not overriding KeyListener methods.
You can annotate a method with #Override
this causes a compile error if it doesn't actually override. Section 9.6.1.4 of the JLS says:
The annotation type Override supports early detection of such problems. If a method declaration is annotated with the annotation #Override, but the method does not in fact override any method declared in a superclass, a compile-time error will occur.
Your class definition will lead to possible potential bugs cause
public class Panel extends JPanel implements Runnable, KeyListener
Calling Panel it's confusing cause already exists java.awt.Panel so call it different. Implementing multiple interface like that brokes Single Responsability Principle . A possible solution is to make inner classes or anonymous classes. For sure if you don't override a method is not necessary to extends JPanel. Take care that if you use KeyListener components must be in focus and be focusable and bind it to all keys, instead you can use KeyBindings. Don't use requestFocus instead use requestFocusInWindow() if you read api it says it's discouraged.
The class implements the KeyListener interface but does not provide an implementation for the keyReleased, keyPressed and keyTyped methods specified on the interface. Instead it provides implementations for: KeyReleased, KeyPressed and KeyTyped which are not properly cased.
I am trying to make a game where the character is a 75x75 object, and he moves around the screen. However, when I run my code, I get the error:
java.lang.IllegalArgumentException: Invalid display mode
at sun.awt.Win32GraphicsDevice.setDisplayMode(Unknown Source)
at sylvyrfysh.Screen.setFullScreen(Screen.java:17)
at sylvyrfysh.ImageDrawer.run(ImageDrawer.java:26)
at sylvyrfysh.ImageDrawer.main(ImageDrawer.java:17)
at sylvyrfysh.Main.main(Main.java:7)
I am not sure what is causing this, as I made another project with the same DisplayMode arguments, and it worked fine.
package sylvyrfysh;
import game.infos.Information;
import java.awt.*;
import javax.swing.*;
public class ImageDrawer extends JFrame{
/**
*
*/
private static final long serialVersionUID = -4278324581016693552L;
public static void main() throws InterruptedException{
DisplayMode dm=new DisplayMode(Information.sX,Information.sY,16,DisplayMode.REFRESH_RATE_UNKNOWN);
ImageDrawer i=new ImageDrawer();
i.run(dm);
}
private void loader(){
bg=new ImageIcon("src/sylvyrfysh/maze_icon.png").getImage();
chara=new ImageIcon("src/sylvyrfysh/char.png").getImage();
}
private void run(DisplayMode dm){
System.out.println("HI");
loader();
s=new Screen();
s.setFullScreen(dm,this);//error here
repaint();
while(EHandler.run){
if(rp){
repaint();
rp=false;
}
}
}
public void paint(Graphics g){
g.drawImage(bg,0,0,null);
g.drawImage(bg,360,0,null);
g.drawImage(bg,720,0,null);
g.drawImage(bg,0,480,null);
g.drawImage(bg,360,480,null);
g.drawImage(bg,720,480,null);
g.drawImage(chara,imgX,imgX,null);
}
private Image bg,chara;
Screen s;
public static int imgX=0;
public static int imgY=525;
public static Boolean rp=false;
}
Any help would be appreciated.
The ability to change graphics device's
display mode is platform- and configuration-dependent and may not always be available. GraphicsDevice.isDisplayChangeSupported() should be used to check prior to change the display mode on graphics device.
Some other important suggestion are made here nicely.
Im on to create a little "game", something like an 2d AirForce Shooter.
So, i have a problem with deleting unused enemys.
An Enemy is an simple JPanel, which is saved in the main logic as an array List.
public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
The Enemy run logic does the following:
while(!destroyed){
if(Game.running){
x--;
if(getBounds().intersects(Field.player.getBounding())){
Player.death = true;
}
if(x < 0){
Field.deleteEnemy(this);
}
setBounds((int) x, (int) y, 100, 50);
try{Thread.sleep(10);}catch(InterruptedException e){}
}
}
So you can seem there i already tried to call the method deleteEnemy, and just give it the unused Enemy.
But it isnt possible - when i just do this:
public static void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
}
It will be just removed from the list, but coninues existing on the Main JPanel.
And i cannot say
remove(e);
Because then i try to call a non static function in a static.
So, how could i delete an Enemy? Someone knows?
Thanks for help!
The hole code: (Game.java)
And, Enemy.java:
package Game;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Field extends JPanel implements Runnable{
public static Player player = new Player();
public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
private Thread moveBackground = new Thread(this);
private boolean bgMoving = false;
public static boolean addMob = false;
private int x = 0;
private int bgSpeed = -1;
public Field(){
setBounds(0, 0, 800, 600);
setFocusable(true);
setLayout(null);
addKeyListener(new Handler());
add(player);
}
public void paintComponent(Graphics g){
Field.super.paintComponent(g);
g.drawImage(Images.images[0], x, 0, this);
}
public static void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
}
public void run(){
while(!Player.death){
if(bgMoving){
bgMoving = true;
x += bgSpeed;
if(x < -(Images.images[0].getWidth(this) - this.getWidth() - 20)){
bgMoving = false;
}
repaint();
try { Thread.sleep(20); } catch (InterruptedException e) {}
}
if(addMob){
enemys.add(new Enemy());
add(enemys.get(enemys.size() - 1));
addMob = false;
}
}
JOptionPane.showMessageDialog(null, "DIED!");
}
public class Handler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
player.KeyPressed(e);
if(!bgMoving){
if(Game.running){
bgMoving = true;
if(moveBackground.getState().toString() == "NEW"){
moveBackground.start();
}
}
}
}
public void keyReleased(KeyEvent e) {
player.KeyReleased(e);
}
}
}
And, Enemy.java:
package Game;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Enemy extends JPanel implements Runnable{
Thread t = new Thread(this);
private double x = Game.width();
private double y = Math.random() * Game.height();
private double xF = 0, yF = 0;
private boolean destroyed = false;
public Enemy(){
setBounds((int) x, (int) y, 100, 50);
setOpaque(false);
t.start();
}
public void paintComponent(Graphics g){
Enemy.super.paintComponent(g);
g.setColor(Color.GREEN);
g.drawImage(Images.images[2], 0, 0, this);
}
public void run() {
while(!destroyed){
if(Game.running){
x--;
if(getBounds().intersects(Field.player.getBounding())){
Player.death = true;
}
if(x < 0){
Field.deleteEnemy(this);
}
setBounds((int) x, (int) y, 100, 50);
try{Thread.sleep(10);}catch(InterruptedException e){}
}
}
}
}
After removing you will need to call revalidate() and repaint()
[Too long for a comment]
I think the problem is in your logic on removing an Enemy/JPanel:
You are removing it from the ArrayList only, what about the containing JPanel/JFrame you added it to?
You must remove the JPanel from its container (maybe another JPanel or the JFrame) not just the ArrayList via Component#remove(Component c).
If you drew the Enemy images directly in paintComponent(...) of your container via iterating the ArrayList; removing it from the ArrayList would be sufficient, as it will no longer be in the Array and thus no longer drawn on the next repaint().
+1 to #Optional, you may need to call revalidate() and repaint() on the container for the affects of the removed JPanel/Enemy to be shown.
Also as #darijan mentioned, the use of static variables along with instance is not really a great design (though for certain designs this may be fine).
In your case if you need access to an instance method of another class, within another class, simply pass the instance of the class whos method you would like to access to the object which will access it.
Here is some psuedo code expressing much of the above mentioned problems / solutions:
public class Field extends JPanel {
private ArrayList<Enemy> enemies;
public Field() {
...
enemies.add(new Enemy(this));//create a new enemy and pas it the JPanel instance so it may access instance methods of this class
}
//ONLY USED IF JPanel for Enemy is ommited and Enemy class created which represents Enemy object and not Enemy object and aJPanel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ArrayList<Enemy> enemiesClone = new ArrayList<>(enemies);//copy array into another so we don't get a ConcurrentModificaton exception if removeEnemy is called while iterating the list
if(!enemiesClone.isEmpty())
for(Enemy e:enemiesClone) {//iterate through array of images
draw(e.getImage(),e.getX(),e.getY(),this);
}
}
public void removeEnemy(Enemy e) {
enemies.remove(e);//remove from the array
//ONLY USED IF JPanels are used as Enemy
remove(e);//remove from the JPanel
//so the changes of removed panel can be visible seen
revalidate();
repaint();
}
}
class Enemy extends JPanel //extends JPanel should be ommited for paintComponent method of drawing an enemy onscreen
{
private int x,y;
private BufferedImage image;
private Field f;
public Enemy(Field f) {//constructor accepts Field instance to access instance method for the class
this.f=f;
}
public void update() {
if(offscreen||dead) {
f.removeEnemy(this);//call removeEnemy which is an instance method of Field
}
}
//BELOW METHODS ONLY USED WHEN Enemy represents object and not a JPanel which can draw its image itself (and update position by simply changing co-ordinates)
public BufferedImage getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
For a more detailed look check Game Development Loop, Logic and Collision detection Java Swing 2D I made which will give you the basics needed for most 2D games. However I do not use JPanels rather draw directly to a container.
Where do you add an Enemy to JPanel?
Basically, you should call remove on Field JPanel:
public void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
this.remove(e);
}
The method should not be static.