I've been working on a game but messed something up and I can't figure what it is. I've simplified the code as much as possible in this example and it retains the same issue.
In this example, instead of the red square going upwards without leaving a trace, it leaves behind a red trace meaning the graphics are not being disposed of properly or the buffer strategy isn't working.
How do I make the red square not leave behind a trail?
import java.awt.*;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class game extends Canvas implements Runnable {
private boolean running = false;
private int w = 1920/2, h = 1080/2, move = 300;
private JFrame frame;
private Thread thread;
public game() {
frame = new JFrame("Test");
frame.setPreferredSize(new Dimension(w,h));
frame.setMaximumSize(new Dimension(w,h));
frame.setMinimumSize(new Dimension(w,h));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.add(this);
frame.setVisible(true);
start();
setBackground(Color.black);
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1) {
tick();
delta--;
}
if(running) render();
}
}
private void tick() {
move--;
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.red);
g.fillRect(300, move, 50, 50);
g.dispose();
bs.show();
}
public static void main(String[] args) { new game(); }
}
How do I make the red square not leave behind a trail?
g.setColor(Color.red);
g.fillRect(300, move, 50, 50);
Before you draw your red square you need to paint the entire background of your canvas.
g.setColor(...);
g.fillRect(...);
g.setColor(Color.red);
g.fillRect(300, move, 50, 50);
Related
If I create a window with JFrame, several rows of pixels along the bottom and several columns along the right hand side are outside the window that is created so they don't show up. For example when I create a 800x600 window, the window will only show stuff in the top left 786x563 area. The amount that gets cut off also seems to vary with the size of the window. So far I've just manually adjusted the size and position of things. Currently in my code is set up like this:
import java.awt.*; //Canvas and Dimension
import java.util.*;
import javax.swing.JFrame;
import java.awt.image.BufferStrategy;
import java.awt.event.*;
public class Main extends Canvas implements Runnable {
static final int WIDTH = 800, HEIGHT = WIDTH/4*3; //800, 600
private Thread thread;
private boolean running = false;
public Main() { //constructor
new Window(WIDTH, HEIGHT, "Game", this);
requestFocus();
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
}
catch(Exception e) {
e.printStackTrace();
}
}
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 /amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames =0;
while(running) {
long now = System.nanoTime();
delta+= (now - lastTime) / ns;
lastTime = now;
while(delta>=1) {
tick();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer > 1000) {
timer+=1000;
frames = 0;
}
}
stop();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs==null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
//creates a line that should be 38 units above the bottom but instead is right along the bottom
g.setColor(Color.GREEN);
g.fillRect(1, 562, 30, 1);
g.dispose();
bs.show();
try{Thread.sleep(5);} catch(Exception e) {}
}
public void tick() {
}
public static void main(String args[]) {
new Main();
}
}
class Window extends Canvas {
public Window(int w, int h, String t, Main game) {
JFrame frame = new JFrame(t);
frame.setPreferredSize(new Dimension(w,h));
frame.setMinimumSize(new Dimension(w,h));
frame.setMaximumSize(new Dimension(w,h));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(game);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
game.start();
}
}
If I didn't include enough of my code to diagnose the problem please tell me so I can put the rest of it.
I've been trying to get the background colour of my jframe to turn blue, but all it does is show the default jframe colours. How do i get the background to actually display blue?
In other words, it won't allow me to get a blue background but the jframe will open with no colour whatsoever.
package DisplayPackagev1;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Sea_InvadersDisplay extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static void main(String[] args){
Sea_InvadersDisplay display = new Sea_InvadersDisplay();
JFrame frame = new JFrame();
frame.add(display);
frame.pack();
frame.setTitle("Sea Invaders");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
display.start();
}
private boolean running = false;
private Thread thread;
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {e.printStackTrace();}
}
public int FPS;
public Sea_InvadersDisplay(){
this.setSize(1300, 690);
this.setFocusable(true);
}
#Override
public void run() {
long timer = System.currentTimeMillis();
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 999999999 / TARGET_FPS;
int frames = 0;
this.createBufferStrategy(3);
BufferStrategy bs = this.getBufferStrategy();
while(running){
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double) OPTIMAL_TIME);
// double delta = updateLength / ((double) OPTIMAL_TIME); means that when I update it, it doesn't jump.
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
FPS = frames;
frames = 0;
System.out.println(FPS);
}
draw(bs);
try{
Thread.sleep(((lastLoopTime - System.nanoTime()) + OPTIMAL_TIME) / 999999999);
} catch(Exception e){};
}
}
public void draw(BufferStrategy bs){
do {
do {
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
g.setColor(Color.BLUE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.dispose();
}while(bs.contentsRestored());
bs.show();
} while (bs.contentsLost());
}
// Buffer Strategy, way to use Buffer Damage so that there isn't any flickering. ALos takes up less resources
}
when you add your Sea_InvadersDisplay you fill all area of that frame with this component. So even if your JFrame background would have any background color it would ne be visible because of the overlaying Sea_InvadersDisplay.
instead try to set the background color of your Sea_InvadersDisplay.
public static void main(String[] args){
Sea_InvadersDisplay display = new Sea_InvadersDisplay();
display.setBackground( Color.BLUE ); //set background on display instead
JFrame frame = new JFrame();
...
display.start();
}
frame.getContentPane().setBackground( Color.BLUE );
You must call the above line.
For example:
public static void main(String[] args){
Sea_InvadersDisplay display = new Sea_InvadersDisplay();
JFrame frame = new JFrame();
frame.add(display);
frame.pack();
frame.setTitle("Sea Invaders");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.getContentPane().setBackground( Color.BLUE );
frame.setVisible(true);
display.start();
}
I am building the test application to improve later. I have a Java Graphic Element drawn on a canvas using a Game Loop (update,render). It is a red ball that changes its color when the mouse is placed on top of it.
I am trying to figure out a method to create a JPanel when the mouse is on top of the ball,to show some sort of "Hidden Information" inside the ball. My original idea is to display a histogram made with JFreeChart API as the "Hiden information, so I believe that if I create this JPanel I can later add the histogram to the JPanel created. Similar to this http://www.bitjuice.com.au/research/#hierarchicalclassificationexample. In the link, whenever you put the mouse on top of the rectangles, you display extra information.
So far I've got this code:
*Window.java * (The JFrame)
public class Window extends JFrame {
JLabel title_label = new JLabel();
public Window(int width, int height, String title, Animation animation){
setTitle(title);
setPreferredSize(new Dimension(width,height));
setMaximumSize(new Dimension(width,height));
setMinimumSize(new Dimension(width,height));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
add(animation);
add(title_label, BorderLayout.SOUTH);
setVisible(true);
animation.start();
}
public void update(){
title_label.setText(Animation.mouseX + " " + Animation.mouseY);
}
}
Animation.java(The game Loop)
public class Animation extends Canvas implements Runnable {
public static final int WIDTH = 1024, HEIGHT = WIDTH/12*9 ;
private Thread thread;
private boolean running = false;
public static int mouseX,mouseY;
public Window window;
Button button = new Button();
public Animation(){
window = new Window(WIDTH, HEIGHT,"Test", this);
addMouseMotionListener(new Handler(window));
addMouseListener(new Handler(window));
}
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000/amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now-lastTime) / ns;
lastTime = now;
while(delta >= 1){
update();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer >1000){
//System.out.println(frames);
timer += 1000;
frames = 0;
}
}
stop();
}
public synchronized void start(){
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop(){
try{
thread.join();
running = false;
}catch(Exception e){
e.printStackTrace();
}
}
public static int getMouseX(){
return mouseX;
}
public static int getMouseY(){
return mouseY;
}
public static void setMouseX(int x){
mouseX = x;
}
public static void setMouseY(int y){
mouseY = y;
}
private void update(){
window.update();
button.update();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(4);
return;
}
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
Graphics g = bs.getDrawGraphics();
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHints(rh);
g2d.setColor(Color.white);
g2d.fillRect(0, 0, WIDTH, HEIGHT);
button.render(g);
g.dispose();
g2d.dispose();
bs.show();
}
public static void main(String args[]){
new Animation();
}
}
Handler.java
public class Handler extends MouseAdapter {
int x,y;
private Window window;
public Handler(Window window){
this.window = window;
}
public void mouseMoved(MouseEvent e){
Animation.setMouseX(e.getX());
Animation.setMouseY(e.getY());
}
}
Button.java
public class Button {
Ellipse2D mask;
boolean mouseIsOn = false;
public Button(){
mask = new Ellipse2D.Double(500,350,50,50);
}
public void update(){
if(mask.contains(Animation.mouseX,Animation.mouseY)){
mouseIsOn = true;
}else
mouseIsOn = false;
}
public void render(Graphics g){
if(mouseIsOn)
g.setColor(Color.green);
else
g.setColor(Color.red);
g.fillOval(500,350, 50, 50);
}
}
I appreciate the help.
Heavy weight and light weight components don't mix. JPanel is a lightweight component and Canvas is heavyweight. Heavyweight components always get drawn on top of lightweight ones.
What you may want to do instead is just draw the mouseover portion directly to your canvas. You can use FontMetrics for drawing Strings if that is what you need.
I wrote some code to create a little square on the screen, but when I press the left button, nothing seems to happen. The rectangle doesn't move, and "Move Left." doesn't get printed out in the console. Here's the code.
package game;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings({ "serial" })
public class Game extends Canvas implements Runnable, KeyListener{
public static final int WIDTH = 400;
public static final int HEIGHT = WIDTH/12 * 9;
public static final int SCALE = 3;
public static final String NAME = "Game";
//Size, scale, and name of window.
boolean running = false;
public int tickCount = 0;
//X and Y coordinates of the rectangle on the screen.
private static int rectX = 10;
private int rectY = 10;
JFrame f;
Canvas can;
BufferStrategy bs;
Controls c;
public Game(){
f = new JFrame(NAME);
f.setSize(400, 400);
f.setVisible(true);
//Sets the size of the window and makes it visible.
JPanel panel = (JPanel) f.getContentPane();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
//Sets preferred size and layout to null.
can = new Canvas();
can.setBounds(0, 0, 400, 400);
can.setIgnoreRepaint(true);
//Creates new canvas.
panel.add(can);
//Adds the canvas to the JPanel.
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setResizable(false);
//Makes the window packed, nonresizable, and close the program on exit.
can.createBufferStrategy(3);
bs = can.getBufferStrategy();
//Creates buffer strategy for the canvas.
System.out.println("Window created.");
addKeyListener(this);
}
public synchronized void start(){
running = true;
new Thread(this).start();
//Starts thread
}
public synchronized void stop(){
running = false;
//For stopping the program.
}
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000.0/60.0;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while(running)
{
long now = System.nanoTime();
delta += (now - lastTime)/nsPerTick;
lastTime = now;
boolean shouldRender = true;
while(delta>=1)
{
ticks++;
tick();
delta -= 1;
shouldRender = true;
//Creates 60fps timer. Not in use.
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(shouldRender)
{
frames++;
render();
//Renders the image.
}
if(System.currentTimeMillis() - lastTimer >= 1000)
{
lastTimer += 1000;
System.out.println(frames + " frames, " + ticks + " ticks");
frames = 0;
ticks = 0;
//Resets timer. Not in use.
}
}
}
public void tick(){
tickCount++;
//Not in use, yet.
}
public void render(){
Graphics2D g = (Graphics2D)bs.getDrawGraphics();
//Sets g to the buffer strategy bs.
g.setColor(Color.BLACK);
g.fillRect(rectX, rectY, 100, 100);
//Creates black rectangle.
g.dispose();
bs.show();
//Puts the rectangle on the screen.
}
public static void main(String [] args){
new Game().start();
//Starts thread.
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_LEFT)
{
--rectX;
System.out.println("Move left.");
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Because at your constructor, you create a new Canvas,and don't use the Game canvas and your rectangle is drawn at the new Canvas, not Game canvas, so your listener has no effect.
Please see the the follow new constructor, I tested it, it works fine.
public Game() {
frame = new JFrame(NAME);
frame.setSize(400, 400);
frame.setVisible(true);
// Sets the size of the window and makes it visible.
JPanel panel = (JPanel) frame.getContentPane();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
// Sets preferred size and layout to null.
//can = new Canvas();
//can.setBounds(0, 0, 400, 400);
//can.setIgnoreRepaint(true);
setBounds(0, 0, 400, 400);
setIgnoreRepaint(true);
// Creates new canvas.
panel.add(this);
// Adds the canvas to the JPanel.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(false);
// Makes the window packed, nonresizable, and close the program on exit.
//can.createBufferStrategy(3);
createBufferStrategy(3);
bs = getBufferStrategy();
// Creates buffer strategy for the canvas.
System.out.println("Window created.");
addKeyListener(this);
}
I am having issues with a 2D platform game. I get an error that reads what the title of the question said. Here are my Game.java and Window.java files. Please tell me what I should do.
I've tried a ton of things and I just don't know where to go or what to do. Thanks in advance :)
Window.java
package com.sam.platform.window;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Window
{
public Window(int w, int h, String title, Game game)
{
game.setPreferredSize(new Dimension(w, h));
game.setMaximumSize(new Dimension(w, h));
game.setMinimumSize(new Dimension(w, h));
JFrame frame = new JFrame(title);
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
}
Game.java
package com.sam.platform.window;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Window;
import java.awt.image.BufferStrategy;
import com.sam.platform.framework.ObjectId;
public class Game extends Canvas implements Runnable
{
private static final long serialVersionUID = -414187095722102896L;
private boolean running = false;
private Thread thread;
public static int WIDTH, HEIGHT;
//Object
Handler handler;
private void init()
{
WIDTH = getWidth();
HEIGHT = getHeight();
handler = new Handler();
handler.addObject(new Player(100, 100, handler, ObjectId.Player));
handler.createLevel();
this.addKeyListener(new KeyInput(handler));
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public void run()
{
init();
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int updates = 0;
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
updates++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println("FPS:" + frames + " TICKS: " + updates);
frames = 0;
updates = 0;
}
}
}
private void tick()
{
handler.tick();
}
private void render()
{
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
//////////////////////////////////
//Draw Here
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
handler.render(g);
//////////////////////////////////
g.dispose();
bs.show();
}
public static void main(String args[]){
new Window(900, 900, "Hop", new Game()); //error is here "The constructor Window(int, int, String, Game) is undefined"
}
}
Your Window class is fine, but the class you're importing in Game is java.awt.Window.
You could solve this by doing new com.sam.platform.window.Window(...), but I would advise against it, it will just confuse you.
Rename the class to something like GameWindow instead.
You have two different classes called Window in use in your Game class. One is com.sam.platform.window.Window. The other is java.awt.Window. Since you have imported java.awt.Window into your Game class, it thinks you are trying to instantiate one of those (not your own Window class).
I suggest renaming you own class to disambiguate (and avoid confusion) to, say, GameWindow.