I'am making a game, and my JFrame add only one class, i don't getting error, but one of two classes dosen't show. I am try to make JFrame frame 2 = new JFrame();, but nothing.
Game.java:
import java.awt.Component;
import javax.swing.JFrame;
public class Game{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
private static final String TITLE = "Game Dev [ Week #1 ]";
public static void main(String[] args){
JFrame frame = new JFrame();
Player player = new Player();
Rabbit rabbit = new Rabbit();
// Draw on the map
player.setPlayer(250,250);
rabbit.setRabbit(200,200);
// Draw on the map
frame.add(player);
frame.add(rabbit); // Add only this
// Window
frame.setVisible(true);
frame.setSize(WIDTH,HEIGHT);
frame.setTitle(TITLE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Player.java:
public class Player extends JPanel implements ActionListener, KeyListener{
// Varibles
Timer time = new Timer(5, this);
static int x; double velX = 0;
static int y; double velY = 0;
private BufferedImage player;
boolean W = false;
boolean A = false;
boolean S = false;
boolean D = false;
public void setPlayer(int x, int y){
this.x = x;
this.y = y;
}
public Player(){
time.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
try {
player = ImageIO.read(getClass().getResourceAsStream("/Player.png"));
} catch (IOException e){
e.printStackTrace();
}
}
// Draw player
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(player, (int)x, (int)y, 100, 100, null);
}
// Set the start up position of player
public void actionPerformed(ActionEvent e){
x += velX;
y += velY;
repaint();
}
// Functions for keyEvent
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
if(key == KeyEvent.VK_W) // UP
velY = -0.5;
if(key == KeyEvent.VK_A) // LEFT
velX = -0.5;
if(key == KeyEvent.VK_S) // DOWN
velY = 1.5;
if(key == KeyEvent.VK_D) // RIGHT
velX = 1.5;
}
public void keyTyped(KeyEvent e){}
// IF any key released
public void keyReleased(KeyEvent arg0) {
velX = 0;
velY = 0;
W = false;
A = false;
S = false;
D = false;
}
}
Rabbit.java:
public class Rabbit extends JPanel implements ActionListener{
static int x; double velX = 0;
static int y; double velY = 0;
BufferedImage rabbit;
public void setRabbit(int x, int y){
this.x = x;
this.y = y;
}
public Rabbit(){
try {
rabbit = ImageIO.read(getClass().getResourceAsStream("/Rabbit.png"));
} catch (IOException e){
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(rabbit, (int)x, (int)y, 100, 100, null);
}
public void actionPerformed(ActionEvent e){
x += velX;
y += velY;
repaint();
}
}
What's happening is that the JFrame is not combining the graphics for Player and Rabbit; rather, it is placing the player as a panel, and then placing the rabbit. So, the player and the rabbit are always separated. What you want is the Player and Rabbit classes NOT to extend JPanel, but to have a method called paint(Graphics). That way, you can make a class called GamePanel that extends JPanel, and create new methods setPlayer(Player) and setRabbit(Rabbit). The GamePanel class should look like this:
public class GamePanel extends JPanel {
Player player;
Rabbit rabbit;
public void setPlayer(Player player) {
this.player = player;
}
public void setRabbit(Rabbit rabbit) {
this.rabbit = rabbit;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
player.paint(g);
rabbit.paint(g);
}
}
and your Player class should look like this:
public class Player {
public void paint(Graphics g) {
// How to paint the graphics in the player class
}
}
and your Rabbit class should look the same, except as public class Rabbit.
Hope that helps!
EDIT: Full Script
package game;
import java.awt.Graphics;
public interface Displayable {
public void paint(Graphics graphics);
}
package game;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Rabbit implements Displayable {
private int x, y;
private Image image;
public Rabbit(int x, int y) throws IOException {
this.x = x;
this.y = y;
this.image = ImageIO.read(new File("RABBIT_FILE")); // Replace
// "RABBIT_FILE"
// with the image
// file you have
}
public void paint(Graphics graphics) {
graphics.drawImage(this.image, this.x, this.y, new ImageObserver() {
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
return false;
}
});
/**
* Optional: JDK 8 only:
*
* graphics.drawImage(this.image, this.x, this.y, (Image img, int
* infoflags, int x0, int y0, int width0, int height0) -> false);
* //Lambda Expression
*/
}
public void setCoordinates(int x, int y) {
this.x = x;
this.y = y;
}
}
package game;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Player implements Displayable {
private int x, y;
private Image image;
public Player(int x, int y) throws IOException {
this.x = x;
this.y = y;
this.image = ImageIO.read(new File("PLAYER_FILE")); // Replace
// "PLAYER_FILE"
// with the image
// file you have
}
public void paint(Graphics graphics) {
graphics.drawImage(this.image, this.x, this.y, new ImageObserver() {
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
return false;
}
});
/**
* Optional: JDK 8 only:
*
* graphics.drawImage(this.image, this.x, this.y, (Image img, int
* infoflags, int x0, int y0, int width0, int height0) -> false);
* //Lambda Expression
*/
}
public void setCoordinates(int x, int y) {
this.x = x;
this.y = y;
}
}
package game;
import java.awt.Graphics;
import javax.swing.JPanel;
public final class GamePanel extends JPanel {
private static final long serialVersionUID = -385535147711891740L;
private Player player;
private Rabbit rabbit;
public void setPlayer(Player player) {
this.player = player;
}
public void setRabbit(Rabbit rabbit) {
this.rabbit = rabbit;
}
public GamePanel(Player player, Rabbit rabbit) {
this.setPlayer(player);
this.setRabbit(rabbit);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.player.paint(g);
this.rabbit.paint(g);
}
}
package game;
import javax.swing.JFrame;
public final class Main {
public static void main(String... args) {
try {
JFrame frame = new JFrame("Player & Rabbit Game"); // Or whatever
// title
// you have in mind
GamePanel panel = new GamePanel(new Player(0, 0), new Rabbit(0, 0));
frame.add(panel);
frame.setVisible(true);
frame.setDefaultCloseOperation(3);
frame.setExtendedState(6);
} catch (Exception e) {
// Handle Exception if file is corrupted, unable to be read to an
// image, or does not exist
}
}
}
Related
These are all of my classes, I'm trying to make a platformer game with an array list to hold my platforms, this is so I can add more platforms any time and anywhere. For some reason, it's not drawing the platforms.
Can someone please help me with this issue or give me an alternative?
NOTE: some of the variables and methods I either haven't used yet or forgot to delete when i was re-creating my code.
package Game;
import Game.Frame;
public class Main {
public static void main(String[] args) {
new Frame();
}
}
package Game;
import javax.swing.*;
import java.awt.*;
public class Frame extends JFrame {
GamePanel panel;
public Frame() {
panel = new GamePanel();
this.add(panel);
this.setTitle("Platformer Game");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
package Game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Timer;
public class GamePanel extends JPanel implements ActionListener{
Player player1;
Map map1;
final int SCREEN_WIDTH = 1000;
final int SCREEN_HEIGHT = 600;
final int PLAYER_WIDTH = 50;
final int PLAYER_HEIGHT = 60;
final Dimension SCREEN_SIZE = new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT);
boolean falling = false;
boolean playing = true;
Image backgroundImage;
Thread gameThread;
Image image;
Graphics graphics;
Timer gameTimer;
ArrayList<Map> platform = new ArrayList<>();
public GamePanel() {
java.net.URL imgIcon = Main.class.getResource(
"/Resources/spaceImage.jpg");
backgroundImage = new ImageIcon(imgIcon).getImage();
newPlayer();
newMap();
this.setFocusable(true);
this.setPreferredSize(SCREEN_SIZE);
this.setOpaque(true);
this.addKeyListener(new KeyListener(
) {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
KeyPressed(e);
}
#Override
public void keyReleased(KeyEvent e) {
KeyReleased(e);
}
});
gameTimer = new Timer();
gameTimer.schedule(new TimerTask(){
#Override
public void run() {
player1.move();
repaint();
}
}, 0 , 17);
}
public void paint(Graphics g) {
image = createImage(getWidth(),getHeight());
graphics = image.getGraphics();
draw(graphics);
g.drawImage(image, 0,0, null);
}
public void draw(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(backgroundImage, 0,0, null);
player1.paint(g);
for(Map map1: platform) {
map1.paint(g2D);
}
}
public void KeyPressed(KeyEvent e) {
if(e.getKeyChar()=='a') {
player1.keyLeft = true;
}
if(e.getKeyChar()=='d') player1.keyRight = true;
if(e.getKeyChar()=='s') player1.keyDown = true;
if(e.getKeyChar()=='w') player1.keyUp = true;
}
public void KeyReleased(KeyEvent e) {
if(e.getKeyChar()=='a') player1.keyLeft = false;
if(e.getKeyChar()=='d') player1.keyRight = false;
if(e.getKeyChar()=='s') player1.keyDown = false;
if(e.getKeyChar()=='w') player1.keyUp = false;
}
public void newPlayer() {
player1 = new Player((SCREEN_WIDTH/2)-(PLAYER_WIDTH/2), (SCREEN_HEIGHT/2)-(PLAYER_WIDTH/2), PLAYER_WIDTH, PLAYER_HEIGHT, this);
}
public void newMap() {
for(int i=50;i<650;i+=50){
platform.add(new Map(i,600,50,50));
}
}
public void gameOver() {
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
package Game;
import Game.GamePanel;
import java.awt.*;
import java.awt.event.KeyEvent;
public class Player extends Rectangle{
double velocityY = 0;
double velocityX = 0;
final int PLAYER_WIDTH = 50;
final int PLAYER_HEIGHT = 50;
static int speed = 2;
GamePanel panel;
boolean keyRight = false;
boolean keyLeft = false;
boolean keyUp = false;
boolean keyDown = false;
Rectangle hitbox;
public Player(int x, int y, int PLAYERWIDTH, int PLAYERHEIGHT, GamePanel panel) {
super(x,y,PLAYERWIDTH,PLAYERHEIGHT);
this.panel = panel;
hitbox = new Rectangle();
}
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setColor(Color.red);
g2D.fillRect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT);
}
public void move() {
if(keyLeft && keyRight || !keyLeft && !keyRight) {
velocityX *= 0.8;
}
if(keyLeft && !keyRight) {
velocityX--;
}
if(keyRight && !keyLeft) {
velocityX++;
}
if(velocityX > 0 && velocityX < 0.75) velocityX = 0;
if(velocityX < 0 && velocityX > -0.75) velocityX = 0;
if(velocityX > 7) velocityX = 7;
if(velocityX < -7) velocityX = -7;
if(keyUp) {
velocityY = -6;
}
velocityY += 0.3;
y += velocityY;
x += velocityX;
hitbox.x = x;
hitbox.y = y;
}
}
package Game;
import java.awt.*;
public class Map {
int PLATFORM_WIDTH = 600;
int PLATFORM_HEIGHT = 150;
int x;
int y;
Rectangle hitbox;
public Map(int x, int y, int PLATFORM_WIDTH, int PLATFORM_HEIGHT) {
this.x = x;
this.y = y;
this.PLATFORM_WIDTH = PLATFORM_WIDTH;
this.PLATFORM_HEIGHT = PLATFORM_HEIGHT;
hitbox = new Rectangle(x,y,PLATFORM_WIDTH, PLATFORM_HEIGHT);
}
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setColor(Color.gray);
g2D.fillRect(x,y,PLATFORM_WIDTH,PLATFORM_HEIGHT);
}
}
So you set the screen height to 600, final int SCREEN_HEIGHT = 600; but then create your platforms y position to 600 as well, platform.add(new Map(i,600,50,50));.
Since they never move, this is going to paint them off screen, so, a quick solution is to change the y position to something which is within the visible range, maybe 550, that way you will see them (to start with).
Observations
There's a lot of, interesting, ideas going on and I'm not sure you entirely understand how the API works.
Start by having a look at:
Performing Custom Painting
Painting in AWT and Swing
This will give you a better understanding of how the paint system works in Swing and how you should work with it.
Having said that, Swing is double buffered by default, so you don't need your own backing buffer, just override paintComponent and paint to the Graphics context
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
draw(g2d);
g2d.dispose();
}
this will help eliminate one possible area of issues.
Swing is also not thread safe, so you should avoid making up dates to the UI (or state the UI relies on) from outside the context of the Event Dispatching Thread.
Instead of using java.util.Timer, you should be using javax.swing.Timer, which will generate it's callbacks within the context of the EDT.
See Concurrency in Swing and How to Use Swing Timers for more details
gameTimer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
player1.move();
repaint();
}
});
gameTimer.start();
KeyListener is well know for causing issues and there is a better system available which resolves these issues, see How to Use Key Bindings for more details.
I'm also not really sure what's going on with Player
public class Player extends Rectangle {
double velocityY = 0;
double velocityX = 0;
final int PLAYER_WIDTH = 50;
final int PLAYER_HEIGHT = 50;
static int speed = 2;
GamePanel panel;
boolean keyRight = false;
boolean keyLeft = false;
boolean keyUp = false;
boolean keyDown = false;
Rectangle hitbox;
public Player(int x, int y, int PLAYERWIDTH, int PLAYERHEIGHT, GamePanel panel) {
super(x, y, PLAYERWIDTH, PLAYERHEIGHT);
this.panel = panel;
hitbox = new Rectangle();
}
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setColor(Color.red);
g2D.fillRect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT);
}
You extend it from Rectangle, but then you create another Rectangle within it and I have no idea what all the instance fields are doing at all (you basically ignore what ever's passed in, in favour of your properties)
You could just do something like and use Player as the hotbox itself
public class Player extends Rectangle {
enum Direction {
UP, DOWN, LEFT, RIGHT
}
private double velocityY = 0;
private double velocityX = 0;
private int speed = 2;
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void paint(Graphics2D g2D) {
g2D.setColor(Color.RED);
g2D.fill(this);
}
Runnable example...
Key bindings can be fun to get your head around, so I've modified your code to support them (and the above mentioned changes) to give you a better idea.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new GamePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GamePanel extends JPanel implements ActionListener {
protected static final int SCREEN_WIDTH = 1000;
protected static final int SCREEN_HEIGHT = 600;
protected static final int PLAYER_WIDTH = 50;
protected static final int PLAYER_HEIGHT = 60;
protected static final Dimension SCREEN_SIZE = new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
boolean falling = false;
boolean playing = true;
Player player1;
Map map1;
Image backgroundImage;
Timer gameTimer;
ArrayList<Map> platform = new ArrayList<>();
public GamePanel() {
BufferedImage img = new BufferedImage(SCREEN_WIDTH, SCREEN_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.BLUE);
g2d.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g2d.dispose();
backgroundImage = new ImageIcon(img).getImage();
newPlayer();
newMap();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");
am.put("Pressed.left", new MoveAction(player1, Player.Direction.LEFT, true));
am.put("Pressed.right", new MoveAction(player1, Player.Direction.RIGHT, true));
am.put("Pressed.up", new MoveAction(player1, Player.Direction.UP, true));
am.put("Pressed.down", new MoveAction(player1, Player.Direction.DOWN, true));
am.put("Released.left", new MoveAction(player1, Player.Direction.LEFT, false));
am.put("Released.right", new MoveAction(player1, Player.Direction.RIGHT, false));
am.put("Released.up", new MoveAction(player1, Player.Direction.UP, false));
am.put("Released.down", new MoveAction(player1, Player.Direction.DOWN, false));
gameTimer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
player1.move();
repaint();
}
});
gameTimer.start();
}
#Override
public Dimension getPreferredSize() {
return SCREEN_SIZE;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
draw(g2d);
g2d.dispose();
}
public void draw(Graphics2D g2D) {
g2D.drawImage(backgroundImage, 0, 0, null);
player1.paint(g2D);
for (Map map1 : platform) {
map1.paint(g2D);
}
}
public void newPlayer() {
player1 = new Player((SCREEN_WIDTH / 2) - (PLAYER_WIDTH / 2), (SCREEN_HEIGHT / 2) - (PLAYER_WIDTH / 2), PLAYER_WIDTH, PLAYER_HEIGHT);
}
public void newMap() {
for (int i = 50; i < 650; i += 50) {
platform.add(new Map(i, 550, 50, 50));
}
}
public void gameOver() {
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
public class MoveAction extends AbstractAction {
private Player player;
private Player.Direction direction;
private boolean pressed;
public MoveAction(Player player, Player.Direction direction, boolean pressed) {
this.player = player;
this.direction = direction;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
player.putDirection(direction);
} else {
player.removeDirection(direction);
}
}
}
public class Player extends Rectangle {
enum Direction {
UP, DOWN, LEFT, RIGHT
}
private double velocityY = 0;
private double velocityX = 0;
private int speed = 2;
private Set<Direction> directions = new TreeSet<>();
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void putDirection(Direction direction) {
directions.add(direction);
}
public void removeDirection(Direction direction) {
directions.remove(direction);
}
public void paint(Graphics2D g2D) {
g2D.setColor(Color.RED);
g2D.fill(this);
}
protected boolean hasDirection(Direction direction) {
return directions.contains(direction);
}
public void move() {
System.out.println(hasDirection(Direction.UP));
if (hasDirection(Direction.LEFT) && hasDirection(Direction.RIGHT) || !hasDirection(Direction.LEFT) && !hasDirection(Direction.RIGHT)) {
velocityX *= 0.8;
}
if (hasDirection(Direction.LEFT) && !hasDirection(Direction.RIGHT)) {
velocityX--;
}
if (hasDirection(Direction.RIGHT) && !hasDirection(Direction.LEFT)) {
velocityX++;
}
if (velocityX > 0 && velocityX < 0.75) {
velocityX = 0;
}
if (velocityX < 0 && velocityX > -0.75) {
velocityX = 0;
}
if (velocityX > 7) {
velocityX = 7;
}
if (velocityX < -7) {
velocityX = -7;
}
if (hasDirection(Direction.UP)) {
velocityY = -6;
}
velocityY += 0.3;
y += velocityY;
x += velocityX;
}
}
public class Map {
int width;
int height;
int x;
int y;
Rectangle hitbox;
public Map(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
hitbox = new Rectangle(x, y, width, height);
}
public void paint(Graphics2D g2D) {
g2D.setColor(Color.GRAY);
g2D.fill(hitbox);
}
}
}
I am working on a 2D platformer in Java for an assignment. The assignment specifies I must use an abstract shape class to draw shapes. The problem I am having is getting my collision detection to work with multiple Rectangle Objects which I am using as platforms - I store these in a list. At the moment my collision detection will move my player regardless of which platform I have collided with, so if I collide with a platform from the right it will move me to the top of that platform because it's still checking another platform below me, and will assume I've hit that, therefore moving me to the top of the platform. I was wondering how I can change this so that my collision detection also detects which platform I have collided with and collide relative to that platform (as opposed to every platform).
Here's what is currently happening:
Expected Output:
My player should stop where it is when colliding with platforms.
My App class:
package A2;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class App extends JFrame {
public App() {
final Player player = new Player(200, 100);
final ArrayList<Rectangle> platforms = new ArrayList<>();
platforms.add(new Rectangle(100, 500, 400 ,10));
platforms.add(new Rectangle(500, 100, 10 ,400));
JPanel mainPanel = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
player.draw(g);
for(Rectangle r : platforms){
r.draw(g);
}
}
};
mainPanel.addKeyListener(new InputControl(this, player, platforms));
mainPanel.setFocusable(true);
add(mainPanel);
setLayout(new GridLayout());
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(600, 600);
}
public static void main(String[] args) {
App app = new App();
app.setVisible(true);
}
}
abstract class Shape {
public void draw(Graphics g) { }
}
My input handling class:
package A2;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import static java.awt.event.KeyEvent.*;
public class InputControl implements ActionListener, KeyListener {
App app;
Player player;
Timer time = new Timer(5, this);
ArrayList<Rectangle> platforms;
ArrayList<Integer> keyList = new ArrayList<>();
boolean keyReleased = false;
boolean keyPressed = false;
boolean[] keyUp = new boolean[256];
boolean[] keyDown = new boolean[256];
boolean topCollision = false;
boolean rightCollision = false;
boolean leftCollision = false;
boolean botCollision = false;
boolean onGround = false;
private static final double GRAVITY = 2;
private static final int MAX_FALL_SPEED = 5;
double Xoverlap = 0;
double Yoverlap = 0;
boolean collision = false;
public InputControl(App app, Player player, ArrayList<Rectangle> platforms) {
this.app = app;
this.player = player;
this.platforms = platforms;
time.start();
}
public void gravity(){
if(player.yVelocity > MAX_FALL_SPEED){
player.yVelocity = MAX_FALL_SPEED;
}
player.yVelocity += GRAVITY;
}
public void momentum(){}
public void actionPerformed(ActionEvent e) {
Rectangle2D offset = player.getOffsetBounds();
for(int i = 0; i < platforms.size(); i++) {
Rectangle r = platforms.get(i);
//If collision
if (offset.intersects(r.obj.getBounds2D())) {
//Collision on Y axis
if (offset.getX() + offset.getWidth() > r.obj.getX() &&
offset.getX() < r.obj.getX() + r.obj.getWidth() &&
offset.getY() + offset.getHeight() > r.obj.getY() &&
offset.getY() + player.yVelocity < r.obj.getY() + r.obj.getHeight()) {
player.y -= (offset.getY() + offset.getHeight()) - r.obj.getY();
}
//Collision on X axis
if (offset.getX() + offset.getWidth() + player.xVelocity > r.obj.getX() &&
offset.getX() + player.xVelocity < r.obj.getX() + r.obj.getWidth() &&
offset.getY() + offset.getHeight() > r.obj.getY() &&
offset.getY() < r.obj.getY() + r.obj.getHeight()) {
player.x -= (offset.getX() + offset.getHeight()) - r.obj.getX();
}
}
else {
player.x += player.xVelocity;
player.y += player.yVelocity;
}
}
player.x += player.xVelocity;
player.y += player.yVelocity;
app.repaint();
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() >= 0 && e.getKeyCode() < 256) {
keyDown[e.getKeyCode()] = true;
keyUp[e.getKeyCode()] = false;
keyPressed = true;
keyReleased = false;
}
if (keyDown[VK_UP]) {
player.yVelocity = -1;
}
if (keyDown[VK_RIGHT]){
player.xVelocity = 1;
}
if (keyDown[VK_LEFT]) {
player.xVelocity = -1;
}
if (keyDown[VK_DOWN]) {
player.yVelocity = 1;
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() >= 0 && e.getKeyCode() < 256) {
keyDown[e.getKeyCode()] = false;
keyUp[e.getKeyCode()] = true;
keyPressed = false;
keyReleased = true;
}
if(keyUp[VK_RIGHT] || keyUp[VK_LEFT]){
player.xVelocity = 0;
}
if(keyUp[VK_UP]){
player.yVelocity = 0;
}
}
public void keyTyped(KeyEvent e) { }
}
My Player class:
package A2;
import java.awt.*;
import java.awt.geom.Rectangle2D;
public class Player extends Shape {
public double xVelocity;
public double yVelocity;
public double x;
public double y;
public double width = 60;
public double height = 60;
public double weight = 5;
public Rectangle2D obj;
public Player(double x, double y) {
this.x = x;
this.y = y;
obj = new Rectangle2D.Double(x, y, width, height);
}
public Rectangle2D getOffsetBounds(){
return new Rectangle2D.Double( x, y, width, height);
}
public void draw(Graphics g) {
Color c =new Color(1f,0f,0f,0.2f );
obj = new Rectangle2D.Double(x, y, width, height);
g.setColor(Color.BLACK);
Graphics2D g2 = (Graphics2D)g;
g2.fill(obj);
g.drawString("(" + String.valueOf(x) + ", " + String.valueOf(y) + ")", 10, 20);
g.drawString("X Speed: " + String.valueOf(xVelocity) + " Y Speed: " + String.valueOf(yVelocity) + ")", 10, 35);
g.setColor(c);
}
}
My Rectangle class:
package A2;
import java.awt.*;
import java.awt.geom.Rectangle2D;
public class Rectangle extends Shape {
public double width;
public double height;
public double x;
public double y;
boolean hasCollided = false;
public Rectangle2D obj;
public Rectangle(double x, double y, double width, double height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
obj = new Rectangle2D.Double(x, y, width, height);
}
public void draw(Graphics g) {
g.setColor(Color.ORANGE);
Graphics2D g2 = (Graphics2D)g;
g2.fill(obj);
}
}
First, define ColorRectangle class that extends Shape and provide logic for drawing:
// extends java.awt.Shape
abstract class ColorRectangle extends Rectangle {
private static final long serialVersionUID = -3626687047605407698L;
private final Color color;
protected ColorRectangle(int x, int y, int width, int height, Color color) {
super(x, y, width, height);
this.color = color;
}
public void draw(Graphics2D g) {
g.setColor(color);
g.fillRect(x, y, width, height);
}
}
Second, define separate class for represent Player and Platform:
public final class Player extends ColorRectangle {
private static final long serialVersionUID = -3909362955417024742L;
public Player(int width, int height, Color color) {
super(0, 0, width, height, color);
}
}
public final class Platform extends ColorRectangle {
private static final long serialVersionUID = 6602359551348037628L;
public Platform(int x, int y, int width, int height, Color color) {
super(x, y, width, height, color);
}
public boolean intersects(Player player, int offsX, int offsY) {
return intersects(player.x + offsX, player.y + offsY, player.width, player.height);
}
}
Third, define class that contains logic of demo application. Actually, you could split logic for demo and logic for board (including actiona and key listeners), but these classes are very simple, so in given case, no need to split it.
public class CollisionDetectionDemo extends JFrame {
public CollisionDetectionDemo() {
setLayout(new GridLayout());
add(new MainPanel());
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(600, 600);
}
private static class MainPanel extends JPanel implements ActionListener, KeyListener {
private static final long serialVersionUID = 8771401446680969350L;
private static final int OFFS = 5;
private final Player player = new Player(60, 60, Color.BLACK);
private final List<Platform> platforms = Arrays.asList(
new Platform(100, 500, 400, 10, Color.ORANGE),
new Platform(500, 100, 10, 410, Color.RED),
new Platform(150, 300, 100, 10, Color.BLUE),
new Platform(150, 100, 100, 10, Color.GREEN));
private MainPanel() {
player.x = 200;
player.y = 200;
new Timer(5, this).start();
setFocusable(true);
addKeyListener(this);
}
private void drawPlayerPosition(Graphics g) {
g.setColor(Color.BLACK);
g.drawString(String.format("(%d, %d)", player.x, player.y), 10, 20);
}
private void movePlayer(int offsX, int offsY) {
if (!intersects(player, offsX, offsY)) {
player.x += offsX;
player.y += offsY;
}
}
private boolean intersects(Player player, int offsX, int offsY) {
for (Platform platform : platforms)
if (platform.intersects(player, offsX, offsY))
return true;
return false;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Color color = g.getColor();
drawPlayerPosition(g);
player.draw((Graphics2D)g);
platforms.forEach(platform -> platform.draw((Graphics2D)g));
g.setColor(color);
}
#Override
public void actionPerformed(ActionEvent event) {
repaint();
}
#Override
public void keyTyped(KeyEvent event) {
}
#Override
public void keyPressed(KeyEvent event) {
if (event.getKeyCode() == VK_UP)
movePlayer(0, -OFFS);
else if (event.getKeyCode() == VK_DOWN)
movePlayer(0, OFFS);
else if (event.getKeyCode() == VK_LEFT)
movePlayer(-OFFS, 0);
else if (event.getKeyCode() == VK_RIGHT)
movePlayer(OFFS, 0);
}
#Override
public void keyReleased(KeyEvent event) {
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new CollisionDetectionDemo().setVisible(true));
}
}
I'm trying to create a rectangle that can freely move around the screen whilst also rotating so that it faces a circle or certain point.
My current state makes the object move in a very bizarre fashion and can't seem to fix it.
import javax.swing.JFrame;
public class Start {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setTitle("Minigame");
f.setContentPane(new Panel());
f.setSize(1000, 1000);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Panel extends JPanel implements ActionListener, KeyListener{
private Timer timer;
private Graphics2D g2d;
private Planet planet;
private Player player;
private double rotation=0;
private int dx=0;
private int dy=0;
public Panel(){
setFocusable(true);
requestFocus();
planet = new Planet(100,100,100);
player = new Player(200,200,20,50);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d=(Graphics2D)g;
g2d.fillOval(planet.getX(), planet.getY(), planet.getRadius(), planet.getRadius());
g2d.setColor(Color.BLUE);
g2d.rotate(rotation,planet.centerX(),planet.centerY());
g2d.fillRect(player.getX(), player.getY(), player.getWidth(),player.getHeight());
g2d.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
rotation=Math.atan2(player.centerX()-planet.centerX(), player.centerY()-planet.centerY());
player.x+=dx;
player.y+=dy;
repaint();
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -5;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 5;
}
if (key == KeyEvent.VK_UP) {
dy = -5;
}
if (key == KeyEvent.VK_DOWN) {
dy = 5;
}
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
if (dx==-5)
dx = 0;
}
if (key == KeyEvent.VK_RIGHT) {
if (dx==5)
dx = 0;
}
if (key == KeyEvent.VK_UP) {
if (dy==-5)
dy = 0;
}
if (key == KeyEvent.VK_DOWN) {
if (dy==5)
dy = 0;
}
}
#Override
public void addNotify(){
super.addNotify();
timer=new Timer(10,this);
timer.start();
addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
public class Planet{
public int x;
public int y;
private int radius;
public Planet(int x,int y,int radius){
this.x=x;
this.y=y;
this.radius=radius;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getRadius(){
return radius;
}
public int centerX(){
return x+(radius/2);
}
public int centerY(){
return y+(radius/2);
}
}
public class Player {
public int x;
public int y;
private int width;
private int height;
public Player(int x,int y,int width,int height){
this.x=x;
this.y=y;
this.width=width;
this.height=height;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getHeight(){
return height;
}
public int getWidth(){
return width;
}
public int centerX(){
return x+(width/2);
}
public int centerY(){
return y+(height/2);
}
}
This is working for me. I changed the sign of the angle, and the way that the player is drawn.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g2d=(Graphics2D)g;
// Draw planet
g2d.fillOval(planet.getX(), planet.getY(), planet.getRadius(), planet.getRadius());
// Draw player
g2d.setColor(Color.BLUE);
g2d.rotate(rotation, player.centerX(), player.centerY());
Rectangle rect = new Rectangle(player.centerX()-(player.getWidth()/2), player.centerY()-(player.getHeight()/2), player.getWidth(),player.getHeight());
g2d.draw(rect);
g2d.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
rotation=Math.atan2(+player.centerX()-planet.centerX(), - player.centerY()+planet.centerY());
player.x+=dx;
player.y+=dy;
repaint();
}
I haven't checked the calculation of the rotation, but I think fillOval should use twice the radius to draw the planet:
g2d.fillOval(planet.getX(), planet.getY(), planet.getRadius()*2, planet.getRadius()*2);
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();
}
This is an excerise i have to complete for a uni course, its not a marked assignment and i could do with a bit of help. I can get the ball to appear on the screen and bounce of the sides, it doesnt matter at the moment if it falls through the bottom of the screen and i can get the paddle to appear on the screen at different times but i cant get them both to appear at the same time. Help please
Here are my classes
MainClass
package movingball;
public class Main
{
public static void main (String []args)
{
MovingBall world = new MovingBall("Moving Ball");
world.setVisible(true);
world.move();
}
}
BallClass
package movingball;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Ball
{
private final int RADIUS = 10;
private Point pos;
private Color ballColour;
private int yChange = 2;
private int xChange = 1;
private int height, width;
private int change;
public Ball (int frameWidth, int frameHeight)
{
change = 3;
ballColour = Color.RED;
width = frameWidth;
height = frameHeight;
pos = new Point();
pos.x = (int)(Math.random() * (width - RADIUS)) + RADIUS;
pos.y = (int)(Math.random() * (height/2 - RADIUS)) + RADIUS;
}
//There are lots of ways you can updateBallState
//Note that the menu bar occupies some of the visible space
public void move()
{
if(pos.y < RADIUS)
{
yChange = - yChange;
}
if(pos.x < RADIUS)
{
xChange = -xChange;
}
if(pos.x > width - RADIUS)
{
xChange = -xChange;
}
if(pos.y < height - RADIUS)
{
pos.translate(xChange, yChange);
}
if(pos.x < width - RADIUS)
{
pos.translate(xChange, yChange);
}
}
public void updateBallState()
{
if (pos.y + change < height - 3*RADIUS)
{
pos.translate(0, change);
// change++; //accelerate
}
}
//This method can be called with a provided graphics context
//to draw the ball in its current state
public void draw(Graphics g)
{
g.setColor(ballColour);
g.fillOval(pos.x - RADIUS, pos.y - RADIUS, 2*RADIUS, 2*RADIUS);
}
public void bounce()
{
yChange = -yChange;
pos.translate(xChange, yChange);
}
public Point getPosition()
{
return pos;
}
}
BallGame
package movingball;
import java.awt.Graphics;
import java.awt.event.*;
public class BallGame extends MovingBall
{
private Paddle myPaddle = new Paddle(FRAME_WIDTH, FRAME_HEIGHT);
public BallGame(String title)
{
super(title);
addKeyListener(new KeyList());
}
public void paint(Graphics g)
{
super.paint(g);
myPaddle.paint(g);
if(isContact())
{
myBall.bounce();
}
else
{
myPaddle.paint(g);
}
}
public boolean isContact()
{
if (myPaddle.area().contains(myBall.getPosition()))
{
return true;
}
else
{
return false;
}
}
public class KeyList extends KeyAdapter
{
public void keyPressed(KeyEvent k)
{
if(k.getKeyCode() == KeyEvent.VK_LEFT)
{
myPaddle.moveLeft();
}
if(k.getKeyCode() == KeyEvent.VK_RIGHT)
{
myPaddle.moveRight();
}
}
}
}
MovingBall class
package movingball;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MovingBall extends JFrame
{
protected final int FRAME_WIDTH = 240;
protected final int FRAME_HEIGHT = 320;
protected Ball myBall = new Ball(FRAME_WIDTH, FRAME_HEIGHT);
public MovingBall (String title)
{
super(title);
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
super.paint(g);
myBall.draw(g);
}
public void move()
{
while(true)
{
myBall.move();
repaint();
try
{
Thread.sleep(50);
}
catch(InterruptedException e)
{
System.exit(0);
}
}
}
}
Paddle class
package movingball;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Paddle
{
private Color paddleColour = Color.GREEN;
private int x,y;
private int paddleWidth = 20;
private int paddleHeight = 10;
private int move = 5;
/** Creates a new instance of Paddle */
public Paddle(int frameWidth, int frameHeight)
{
x =(int)(Math.random()*(frameWidth - paddleWidth));
y = frameHeight - paddleHeight;
}
public void moveRight()
{
x = x + move;
}
public void moveLeft()
{
x = x - move;
}
public Rectangle area()
{
return new Rectangle(x,y, paddleWidth, paddleHeight);
}
public void paint(Graphics g)
{
g.setColor(paddleColour);
g.fillRect(x,y,paddleWidth, paddleHeight);
}
}
Here are a couple of pointers to get you started. I have a lot of things to suggest but I'll just say this to get you further than you are now. You want your JFrame to be double-buffered. That's the first step. To do this, create a new buffer strategy for your JFrame after making it visible:
world.setVisible(true);
world.createBufferStrategy(2);
As for why your Paddle isn't painting? You're going to kick yourself. Look at this line:
MovingBall world = new MovingBall("Moving Ball");
You're not actually creating a BallGame, which is where the logic for painting the paddle is contained! (BallGame.paint()) Try:
BallGame world = new BallGame("Moving Ball");