Java JApplet doesn't remove an old rectangle once it is moved - java

I am new to graphics and japplets, and I made a rectangle that goes across the screen. But for some reason, it just draws a line across, not removing the old instance of the rectangle once it moves.
Main:
public class Main extends JApplet implements Runnable {
private static final long serialVersionUID = 1L;
private static int width = 900;
private static int height = 600;
public static int fps = 60;
public Thread thread = new Thread(this);
public static Ailoid ailoid = new Ailoid();
public void init() {
setSize(width, height);
setBackground(Color.white);
ailoid.setLocation(new Location(100, 100));
AlienManager.registerAlien(ailoid);
}
public void paint(Graphics g) {
g.setColor(Color.green);
for (Alien alien : AlienManager.getAliens()) {
Location loc = alien.getLocation();
int x = loc.getX();
int y = loc.getY();
g.fillRect(x, y, 10, 20);
}
}
// Thread start
#Override
public void start() {
thread.start();
}
// Thread stop
#SuppressWarnings("deprecation")
#Override
public void destroy() {
thread.stop();
}
#Override
public void run() {
while (true) {
Updater.run();
repaint();
try {
// 1000 divided by fps to get frames per millisecond
Thread.sleep(1000 / fps);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Updater:
public class Updater {
public static void run() {
for (Alien alien : AlienManager.getAliens()) {
Location loc = alien.getLocation();
int x = loc.getX();
int y = loc.getY();
alien.setLocation(new Location(x, y));
}
}
}
Why doesn't it remove the old graphics? thank you!

Your main problem is that your paint(...) method does not call the super method, the method that allows the component to redraw its contents:
public void paint(Graphics g) {
super.paint(g);
//....
Having said that, you're far better off not drawing in a top level window but rather in the paintComponent method of a JPanel that is displayed by the applet. If you do this correction, then do the same thing -- call the super method.
class MyPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//....
As an aside, this code:
public class Updater {
public static void run() {
for (Alien alien : AlienManager.getAliens()) {
Location loc = alien.getLocation();
int x = loc.getX();
int y = loc.getY();
alien.setLocation(new Location(x, y));
}
}
}
Doesn't look like it's moving things all that much. In fact per this code, your aliens should stay completely still.
Edit
Also, this is never code, code you should never have in your application:
#SuppressWarnings("deprecation")
#Override
public void destroy() {
thread.stop();
}
There's a reason that thread's stop() method is deprecated and should never be called. If you're curious as to why, please check out the API.

Related

First Java Game Not Rendering

I decided I wanted to experiment with making a game and I like Java, so I started following a tutorial here. I did deviate from the video a few times when I felt it was cleaner while being synonymous with the tutorial's code, but not in any way I thought would affect how the code worked. For example, it made sense to me that there should only ever be one instance of the Renderer, and Object Registry so I made them Singletons.
The code I have so far is supposed to create a window with a black background, and a blue square in the middle of the window representing the player, that much is working. However, it should also be sliding around in response to the wasd keys, and even more slowly drifting in one direction regardless. Instead it's doing nothing.
I spent no less than an hour trying to figure out why it wasn't working. It seems to be ticking just fine and the data looks like it's updating properly, but even though my render methods are also being called, the screen just isn't changing.
This is all the code I have so far, since I'm out of ideas as to the problem. I apologize for listing a whole project.
public class Game implements Runnable {
private final Thread thread;
private boolean running = false;
Game() {
thread = new Thread(this);
}
public static void main(String[] args) {
Game game = new Game();
game.start();
new Player(600,450,0));
}
private void start() {
thread.start();
running = true;
}
#Override
public void run() {
double tps = 10.0;
double nsPerTick = 1000000000 / tps;
double delta = 0;
int frames = 0;
long timer = System.currentTimeMillis();
long lTime = System.nanoTime();
long now;
while (running) {
now = System.nanoTime();
delta += (now - lTime) / nsPerTick;
lTime = now;
while (delta >= 1) {
Registry.getInstance().tick();
delta--;
}
if (running) Renderer.getInstance().run();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
private void stop() {
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
running = false;
}
}
public class Renderer extends Canvas {
private static final Renderer renderer = new Renderer();
private final Window window;
private final BufferStrategy bs;
private final Graphics g;
boolean black = true;
private Renderer() {
window = new Window(1200, 900, "First Game", this);
this.createBufferStrategy(2);
bs = this.getBufferStrategy();
g = bs.getDrawGraphics();
addKeyListener(Controller.getInstance());
}
public static Renderer getInstance() {return renderer;}
public void run() {
g.setColor(Color.BLACK);
//this was to see if even the background would update, it wouldn't
//g.setColor(black ? Color.BLACK : Color.WHITE);
//black = !black;
g.fillRect(0,0,1200, 900);
Registry.getInstance().render();
g.dispose();
bs.show();
}
public Graphics getGraphics() {return g;}
private static class Window extends Canvas {
private Window(int width, int height, String title, Renderer renderer) {
JFrame frame = new JFrame(title);
frame.setPreferredSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(renderer);
frame.setVisible(true);
}
}
}
public class Registry {
private static final Registry reg = new Registry();
private final LinkedList<GameObject> objects = new LinkedList<>();
private Registry() {
}
public static Registry getInstance() { return reg; }
public void tick() { //System.out.println("tick");
objects.forEach(GameObject::tick); }
public void render() { objects.forEach(GameObject::render); }
public void add(GameObject gameObject) { objects.add(gameObject); }
public void remove(GameObject gameObject) { objects.remove(gameObject);}
}
public class Controller extends KeyAdapter {
private static final Controller controller = new Controller();
private final HashMap<Character,Boolean> keyStates = new HashMap<>();
private Controller() {
}
public static Controller getInstance() {
return controller;
}
public void keyPressed(KeyEvent e) {
if (!keyStates.getOrDefault(e.getKeyChar(), true)) System.out.println(e.getKeyChar() + " down");
keyStates.put(e.getKeyChar(),true);
}
public void keyReleased(KeyEvent e) {
keyStates.put(e.getKeyChar(),false);
System.out.println(e.getKeyChar() + " up " + keyStates.size());
}
public boolean isKeyDown(char c) {return keyStates.getOrDefault(c,false);}
}
public abstract class GameObject {
protected Graphics graphics = Renderer.getInstance().getGraphics();
protected final ObjectType type;
protected float x,y,r;
protected GameObject(ObjectType objectType, float x, float y, float r) {
this.type = objectType;
this.x = x;
this.y = y;
this.r = r;
Registry.getInstance().add(this);
}
public abstract void tick();
public abstract void render();
public void destroy() { Registry.getInstance().remove(this); }
public float getX() { return x; }
public void setX(float x) { this.x = x; }
public float getY() { return y; }
public void setY(float y) { this.y = y; }
public float getR() { return r; }
public void setR(float r) { this.r = r; }
}
public class Player extends GameObject {
private final Controller controller;
public Player(float x, float y, float r) {
super(ObjectType.PLAYER, x, y, r);
controller = Controller.getInstance();
}
#Override
public void tick() {
this.x += 1;
if (controller.isKeyDown('w')) x += 2;
if (controller.isKeyDown('a')) y -= 2;
if (controller.isKeyDown('s')) x -= 2;
if (controller.isKeyDown('d')) y += 2;
}
#Override
public void render() {
graphics.setColor(Color.BLUE);
graphics.fillRect((int) (this.x-12),(int) (this.y-12), 24,24);
}
}
The problem lies in your handling of Graphics. There's only ONE active Graphics object you can effectively address.
Refactor your code, so that you pass the current Graphics object via parameter through the target methods (like here: Player.render() should become Player.render(Gpahics g). And get rid of the Gameobject.graphics member variable. That is the culprit.
Adding to that, the best way to do simple rendering is to override the paint(Graphics g) method or the paintComponents(Graphics g), and from outside call repaint() on the JPanel/Canvas. This way the UI instigates drawing itself, takes care of the actual frequency, and draws default components/design too if there is some.

Why can't I draw my line without the use of an infinitely running while loop

I have to use a permanently running while loop to draw my line, otherwise the line renders for a millisecond and goes away. It may look fine but I may add hundreds upon hundreds of methods that would be running in one loop, that may cause some performance issues.
Debug (The main class)
public class Debug {
public static void main(String[] args) {
boolean running = true;
Window test = new Window(800, 600, 100, 10, true, "This is the title");
Renderer3D renderer = new Renderer3D();
// my permanantly running while loop
while (running) {
renderer.draw();
}
test.addRenderer();
}
}
Window (the class to create the window)
public class Window
static int width;
static int height;
static int x;
static int y;
static boolean v;
static String title;
public Window() {}
public Window(int WIDTH, int HEIGHT, int X, int Y, boolean V, String TITLE) {
// TODO Auto-generated constructor stub
width = WIDTH;
height = HEIGHT;
x = X;
y = Y;
v = V;
title = TITLE;
}
public static JFrame window = new JFrame();
public void setWindowVisible(boolean v) {
window.setVisible(v);
}
public void setWindowSize(int Width, int Height) {
window.setSize(Width, Height);
}
public void setWindowLocation(int X, int Y) {
window.setLocation(X, Y);
}
public void setWindowTitle(String TITLE) {
window.setTitle(TITLE);
}
public static void displayProperties() {
window.setSize(width, height);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(x, y);
window.setTitle(title);
window.setVisible(v);
window.setLocationRelativeTo(null);
}
public void addRenderer() {
window.pack();
displayProperties();
}
public JFrame returnWindow() {
return window;
}
}
Renderer (the class to draw things)
public class Renderer3D extends JFrame {
public boolean executed;
public boolean running = true;
public Thread thread;
public Canvas canvas = new Canvas() {
public void paint(Graphics g) {
}
};
#SuppressWarnings("deprecation")
public Renderer3D() {
canvas.setBackground(Color.black);
Window.window.add(canvas);
Window.displayProperties();
Window.window.show();
}
public void draw() {
if (canvas == null) {
canvas.createBufferStrategy(3);
}
Graphics g = canvas.getGraphics();
g.setColor(Color.BLUE);
g.drawLine(100, 100, 300, 300);
}
}
You need to call your draw() method inside paint() as for Canvas in JAVA, paint() method paints this canvas. No need to call it explicitly in your Debug class.
Completely remove the while loop and what is inside it. In your Renderer3D class, modify the canvas creation part like this:
public Canvas canvas = new Canvas() {
public void paint(Graphics g) {
draw();
}
};

Globally Modify a global variable within a method Java

I am making Conways Game of Life. In the mouse listener I want the cell to appear/disappear on the screen when I click once. I use a 40x40 boolean array (gameState) of 20x20 pixel cells. I want to paint the squares in my paint method using the co-ordinates of my mouse which i get in its clicked method. However, I am getting a null-pointer exception at line 71 and do not know what to do to solve it.
Main
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
public class mainApplication extends JFrame implements Runnable, MouseListener {
private static final Dimension windowsize = new Dimension(80, 600);
private BufferStrategy strategy;
private Graphics offscreenGraphics;
private static boolean isGraphicsInitialised = false;
private static int rows = 40;
private static int columns = 40;
private static int height = windowsize.height;
private static int width = windowsize.width;
private static Cells cells;
private int xArrayElement,yArrayElement, xPosition, yPosition;
private static boolean gameState[][] = new boolean[rows][columns];
public mainApplication() {
System.out.println(System.getProperty("user.dir"));
setDefaultCloseOperation(EXIT_ON_CLOSE);
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width / 2 - windowsize.width / 2;
int y = screensize.height / 2 - windowsize.height / 2;
setBounds(x, y, screensize.width, screensize.height);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
offscreenGraphics = strategy.getDrawGraphics();
isGraphicsInitialised = true;
// MouseEvent mouseEvent = new MouseEvent();
addMouseListener(this);
// addMouseMotionListener(MouseEvent);
Thread t = new Thread(this);
t.start();
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 1){
xPosition = e.getX();
yPosition = e.getY();
cells.setPosition(xPosition,yPosition);
xArrayElement = (xPosition/20);
yArrayElement = (yPosition/20);
if(gameState[xArrayElement][yArrayElement]){
gameState[xArrayElement][yArrayElement] = false;
}
else if (!gameState[xArrayElement][yArrayElement]) {
gameState[xArrayElement][yArrayElement] = true;
}
}
}
#Override
public void run() {
while (true) {
try { //threads entry point
Thread.sleep(20); //forces us to catch exception
}
catch (InterruptedException e) {
}
}
}
public void paint(Graphics g) {
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
if (gameState[xArrayElement][yArrayElement]) {
g.setColor(Color.WHITE);
cells.paint(g);
}
else if (!gameState[xArrayElement][yArrayElement]) {
g.setColor(Color.BLACK);
g.fillRect(xPosition, yPosition, 20, 20);
}
strategy.show();
}
}
public static void main(String[]args){
mainApplication test = new mainApplication();
}
}
Cells class
import java.awt.*;
public class Cells {
int x;
int y;
public Cells(){
}
public void setPosition(int xi, int xj){
x = xi;
y = xi;
System.out.println(xi);
System.out.println("sjdkgffdjv" + y);
}
public boolean cellState(boolean visible){
return visible;
}
public void paint(Graphics g){
g.drawRect(x, y, 20,20);
}
}
It's because you haven't initialized your cells variable in Main class..
So try this
private static Cells cells = new Cells();
As #nullPointer has pointed out (sorry, dad joke) you're getting a NPE because you haven't initialized the class member Cells. There are also a few other points to make that might unrelated to the question.
Don't create that thread
Swing already uses a thread to handle UI events and drawing so creating another thread is dangerous.
Make Cells immutable
Cells should be immutable. At no point should you need to set the position of a cell. If you need to change where a Cell is at, just dispose of the object and create a new one at that position.

Setting up a timer for game

I want to make a fruit basket game. The idea here is that I want to draw fruits from the top of screen to bottom and I also want to do that with timer.I tried several ways but I got no result. Here is what I did but it's totally doing wrong.
Timer timer = new Timer();
while (getY() != 1500) {
timer.schedule(new DrawFruit(frame, g, x) {
#Override
public void run() {
g.drawImage(Toolkit.getDefaultToolkit().getImage(Panel.class.getResource(Consts.ImageResource.APRICOT_DIR)), 500, getY(), frame);
frame.repaint();
setY(getY() + 30);
}
}, 0, 1000);
}
and the DrawFruit Class
abstract class DrawFruit extends TimerTask {
private JFrame jFrame;
private Graphics g;
private int x;
public JFrame getJFrame() {
return jFrame;
}
public void setJFrame(JFrame jFrame) {
this.jFrame = jFrame;
}
public Graphics getG() {
return g;
}
public void setG(Graphics g) {
this.g = g;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public DrawFruit(JFrame frame , Graphics g , int x){
setJFrame(frame);
setG(g);
setX(x);
}
#Override
public void run() {
}
}
You should NOT be using looping code. The point of a Timer is that it replaces the loop. All a Timer does is generate an event at your specified time interval. So when the event is generated you just adjust the "Y" value and repaint the component.
However, you should not be using a TimerTask for this.
Swing components should be updated on the Event Dispatch Thread (EDT). Therefore you should be using a Swing Timer. Read the tutorial for a working example to get you started.

Java car animation smooth and take curves

I'm trying to let a car image follow a path. The car has to "drive" at a constant speed and it has to look smooth. I'm able to let the car follow a list of points but I don't know how I can make the car drive smooth (the car moves to the next point in the list every 2 seconds now) with a constant speed and how to take hardcoded turns. Anyone who can help?
Code
Track class where the track underlay is loaded.
public class Track{
BufferedImage track;
Point trackPosition;
static final Point TRACK_POS = new Point(0, 0);
static final Point SENSOR_POS = new Point(250, 70);
public Track(){
try {
track = ImageIO.read(Roundabout.class.getResource("track.png"));
} catch (Exception ex) {
System.out.println("Problem loading track image: " + ex);
}
trackPosition=new Point(TRACK_POS.x,TRACK_POS.y);
}
public void paint (Graphics g)
{
g.drawImage(track,TRACK_POS.x, TRACK_POS.y, null);
}
}
Car class
public class Car extends JComponent implements Vehicle{
BufferedImage car;
Point carPosition;
static final Point START_POS = new Point(10, 150);
int counter=0;
public Car(){
try {
car = ImageIO.read(Car.class.getResource("beetle_red.gif"));
} catch (Exception e) {
System.out.println("Problem loading car images: " + e);
}
carPosition = new Point(START_POS.x, START_POS.y);
}
public void paint (Graphics g)
{
g.drawImage(car,carPosition.x, carPosition.y, null); //original paint
}
public Point getCarPosition() {
return new Point(carPosition.x,carPosition.y);
}
public void update(){
repaint();
if(counter < Lane.firstLane.size()){
carPosition.x = Lane.firstLane.get(counter).x;
carPosition.y= Lane.firstLane.get(counter).y;
System.out.println("Pos: "+getCarPosition());
counter++;
}
else{
System.out.println("Destination reached");
}
repaint();
}
}
Lane class
public class Lane {
public static List<Point> firstLane = new ArrayList<>(Arrays.asList(new Point(10,135),new Point(124,190),new Point(363,190),new Point(469,210)));
}
Roundabout (main class)
public class Roundabout extends JFrame{
Track track=new Track();
TrafficLight trafficLight=new TrafficLight();
Car car=new Car();
ArrayList<Car> cars = new ArrayList<>();
byte[] array=new byte[]{0,2,1,1}; //test byte array
class Surface extends JPanel {
private void doDrawing(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
Dimension size = getSize();
Insets insets = getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
/* Draw the track first */
track.paint(g);
/* Draw a car */
car.paint(g);
cars.add(car); //add to list
trafficLight.paint(g);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
public Roundabout(){
initUI();
}
private void initUI() {
setTitle("Roundabout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Surface());
setSize(580, 550);
setLocationRelativeTo(null);
moveCar();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Roundabout roundabout=new Roundabout();
roundabout.setVisible(true);
}
});
}
public void moveCar() {
Runnable helloRunnable = new Runnable() {
public void run() {
car.update();
repaint();
}
};
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(helloRunnable, 0, 2, TimeUnit.SECONDS);
}
}
Essentially, you need to move your car along a line segment, then another line segment, etc...
Here is an explanation of motion along a line
Relevant code, with t being in the range 0 to 1 (essentially t = percent of line crossed at said time):
x = xstart + (xend-xstart) * t
y = ystart + (yend-ystart) * t
It's all math.
In order to determine what speed (as change in t) each segment needs to be cruised at, you'll need to determine its length.
The math is easy:
if t+=(1/10) per 1 second for 10px long line, then its speed is 1 px per second. For a line 339 px long, you would need 339 seconds and t+=(1/339).

Categories