Good Morning, I was building when i find the problem that I don't know how to make my Player jump.
There are my classes:
GamePanel
package src;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class GamePanel extends JPanel implements Runnable{
public static final int WIDTH=300, HEIGHT=300, MIN_X_COORD=0, MIN_Y_COORD=0, MAX_X_COORD=19, MAX_Y_COORD=19;
private Thread thread;
private boolean playing, key=false;
private Random r;
int xCoord = 0, yCoord = 16, size = 15;
char direction;
private Player p;
private Victory v;
private ArrayList<Ground> grounds;
private ArrayList<Grass> grasses;
private ArrayList<Sky> sky;
Action jump=new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
yCoord--;
yCoord--;
yCoord++;
yCoord++;
}
};
Action right=new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if(xCoord!=MAX_X_COORD)xCoord++;
direction='l';
}
};
Action left=new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if(xCoord!=MIN_X_COORD)xCoord--;
direction='r';
}
};
public GamePanel() {
this.getInputMap().put(KeyStroke.getKeyStroke('d'),"right");
this.getInputMap().put(KeyStroke.getKeyStroke('a'),"left");
this.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),"up");
this.getActionMap().put("right", right);
this.getActionMap().put("left", left);
this.getActionMap().put("up", jump);
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
grounds = new ArrayList<Ground>();
grasses=new ArrayList<Grass>();
r=new Random();
v=new Victory(16,19, size);
p=new Player(xCoord, yCoord, size);
sky=new ArrayList<Sky>();
start();
}
public void start() {
playing=true;
thread=new Thread(this);
thread.start();
}
#Override
public void run() {
while (playing) {
tick();
repaint();
}
}
public void stop() {
playing = false;
// now we create the Game Over Screen
JFrame f=new JFrame("Game Over Screen");
JButton b=new JButton("Press this to play again!");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setPreferredSize(new Dimension(500,500));
JButton close = new JButton("Quit!");
b.setBounds(130,200,250, 40);
f.add(b);
f.add(close);
f.setLayout(new FlowLayout());
f.pack();
f.setVisible(true);
f.setLocationRelativeTo(null);
Main.returnFrame().dispatchEvent(new WindowEvent(Main.returnFrame(), WindowEvent.WINDOW_CLOSING));
Main.returnFrame().dispose();
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
f.dispatchEvent(new WindowEvent(f, WindowEvent.WINDOW_CLOSING));
Main.main(null);
}
});
close.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void tick() {
p=new Player(xCoord, yCoord, size);
if(grounds.size()==0) {
for(int y=MAX_Y_COORD;y>17;y--)
for(int x = 0;x<=MAX_X_COORD;x++)
grounds.add(new Ground(x,y,size));
}
if(grasses.size()==0)
for (int x=0;x<=MAX_X_COORD;x++)
grasses.add(new Grass(x, 17, size));
if (v.getxCoord()==p.getxCoord()&&v.getyCoord()==p.getyCoord()) {
win();
}
if (sky.size()==0)
for (int x=MIN_X_COORD;x<=MAX_X_COORD;x++)
for (int y=MIN_Y_COORD;y<17;y++)
sky.add(new Sky(x, y, size));
for(int i = 0;i< grounds.size();i++)
if(p.getxCoord() == grounds.get(i).getX_COORD() && p.getyCoord() ==grounds.get(i).getY_COORD())
back();
for(int i = 0;i< grasses.size();i++)
if(p.getxCoord() == grasses.get(i).getX_COORD() && p.getyCoord() ==grasses.get(i).getY_COORD())
back();
}
#Override
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
for(int i = 0;i<WIDTH/10;i++) { // draws lines
g.drawLine(i*10, 0, i*10, HEIGHT);
}
for(int i = 0;i<HEIGHT/10;i++) {
g.drawLine(0, i*10, HEIGHT, i*10);
}
for(int i = 0;i<grounds.size();i++) {
grounds.get(i).draw(g);
}
for (Grass grass : grasses) {
grass.draw(g);
}
for (Sky s:sky)
s.draw(g);
v.draw(g);
p.draw(g);
}
public void win() {
JOptionPane.showMessageDialog(null, "Hai Vinto");
stop();
}
public void die() {
JOptionPane.showMessageDialog(null, "Sei morto");
stop();
}
public void back() {
switch (direction) {
case 'l': xCoord++;break;
case 'r': xCoord--;break;
}
}
}
Player
import java.awt.Color;
import java.awt.Graphics;
public class Player {
int xCoord, yCoord, width, height;
public Player(int xCoord, int yCoord, int size) {
this.xCoord=xCoord;
this.yCoord=yCoord;
width=size;
height=size;
}
public void draw(Graphics g) {
g.setColor(Color.RED);
g.fillRect(xCoord*width, yCoord*height, width, height);
}
public void setxCoord(int xCoord) {
this.xCoord = xCoord;
}
public int getxCoord() {
return xCoord;
}
public int getyCoord() {
return yCoord;
}
public void setyCoord(int yCoord) {
this.yCoord = yCoord;
}
}
I need that the action jump make the player character jump of two squares and return down.
I thought that i had to increase the yCoord and to repaint but it doesn't affect
Related
I'm trying to make a game with ducks, the ducks are moving on the screen and I can't get a mouse click on them. I'm obviously doing something wrong because despite setting a MouseListener, its methods are not called. This is my code, I omitted getters and the DuckGame class, which is only generating ducks.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class DuckGameScreen extends JPanel {
private int initialDuckNum = 7;
private final int INTERVAL = 25;
private final int INTERVAL_BTWN_DUCKS = 1000;
private Timer duckTimer;
private int ducksStarted = 0;
private DuckGame duckGame;
public DuckGameScreen() {
setBackground(Color.cyan);
askAboutDifficulty();
startTimer();
startGame();
startDifficultyIncrease();
}
private void startGame() {
duckGame = new DuckGame(initialDuckNum);
startDucks();
addDuckListeners();
}
private void addDuckListeners() {
for (Duck duck : duckGame.getDucks()) {
duck.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("Duck clicked");}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
});
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
drawDucks(g);
Toolkit.getDefaultToolkit().sync();
}
private void animateDuck(Duck duck) {
new Thread() {
#Override
public void run() {
super.run();
while (!duck.isDuckStopped()) {
try {
Thread.sleep(INTERVAL);
duck.move();
if (duck.getX() - duck.getWidth() >= Toolkit.getDefaultToolkit().getScreenSize().width) {
duck.resetPosition();
}
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
duck.stop();
break;
}
}
}
}
.start();
}
private void drawDucks(Graphics g) {
for (Duck duck : duckGame.getDucks()) {
duck.paintComponent(g);
}
}
}
And my Duck class:
public class Duck extends JComponent {
private final static int INIT_X = -100;
private int x = INIT_X;
private int y = 100;
private int width = 0;
private int height = 0;
private Image image = null;
private boolean isDuckStopped = false;
private final int STEP = 5;
public Duck() {
initRandomPosition();
loadImage();
setVisible(true);
setBounds(x, y, width, height);
}
private void initRandomPosition() {
y = getRandomY();
}
public void move() {
x += STEP;
}
private void loadImage() {
ImageIcon imageIcon = new ImageIcon(getFilePath(Images.DUCK.getFileName()));
Dimension newDimension = Utils.getScaledDimension(100, 100, imageIcon.getIconWidth(), imageIcon.getIconHeight());
image = imageIcon.getImage().getScaledInstance(newDimension.width, newDimension.height, Image.SCALE_DEFAULT);
width = image.getWidth(null);
height = image.getHeight(null);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
drawDuck(g);
Toolkit.getDefaultToolkit().sync();
}
private void drawDuck(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(image, x, y, this);
setBounds(x, y, width, height);
}
public void stop() {
isDuckStopped = true;
setVisible(false);
}
public void resetPosition() {
x = INIT_X;
y = getRandomY();
}
}
** Here i created only one moving object ,i want to create more objects which falls down and has random X coordinate .i know i should implement runnable and i should create squres then store them in a collection but its really hard for me to merge everything.i also might have done some mistakes btw . Could you help me some ? **
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
public class Project3 extends JFrame {
public Project3(){
super("Game");
setSize(600,600);
add(new Game(600,600));
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Project3());
}
class Squares{
public int x;
public int y;
public Squares(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
class Game extends JPanel implements ActionListener {
private int score;
private java.util.List<Squares> shapeList=new ArrayList<>();
private boolean play ;
private int X=50;
private int Y=0;
Timer timer=new Timer(10,this);
public Game(int w , int h){
Dimension d = new Dimension(w, h);
setBackground(Color.BLUE);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.fillRect(X,Y,60,60);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
Y=Y+5;
repaint();
if(Y==600){
Random random=new Random();
Y=0;
X=random.nextInt(600-60);
}
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class Project3 extends JFrame {
public Project3() {
super("Game");
setSize(600, 600);
add(new Game(600,600));
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Project3());
}
class Square {
public int squareX;
public int squareY;
int squareW = 25;
int squareH = 25;
public Square(int X, int Y) {
this.squareX = X;
this.squareY = Y;
}
public int getSquareX() {
return squareX;
}
public void setSquareX(int X) {
this.squareX = X;
}
public int getSquareY() {
return squareY;
}
public void setSquareY(int Y) {
this.squareY = Y;
}
}
class Game extends JPanel implements ActionListener ,Runnable,MouseListener {
public int score;
private java.util.List<Square> shapeList = new ArrayList<>();
Timer timer = new Timer(10, this);
private boolean play= true;
public Game(int w, int h) {
Dimension d = new Dimension(600, 600);
setBackground(Color.BLUE);
add(new Label("SCORE...."),BorderLayout.PAGE_END);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.YELLOW);
for (Square s:shapeList) {
g.fillRect(s.squareX,s.squareY,25,25);
}
}
#Override
public void actionPerformed(ActionEvent e) {
for (Square k : shapeList) {
k.setSquareY(k.getSquareY() + 5);
repaint();
}
}
public void stop() {
play = false;
}
#Override
public void run() {
while(play){
int randomNumber=(int)(Math.random()*600)+1;
shapeList.add(new Square(randomNumber,0));
for (Square k : shapeList) {
if (k.getSquareY()== 600) {
stop();
}try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
}
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
int mouseX=e.getX();
int mouseY=e.getY();
for (Square s:shapeList){
if ((mouseX > s.squareX) && (mouseX < s.squareX + s.squareW) && (mouseY > s.squareY) && (mouseY < s.squareY + s.squareH)) {
shapeList.remove(s);
score++;
}
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
}
This code produces three layers of 'snow flakes' which drift towards the bottom of the screen.
Have a look over it, for tips:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.Random;
public class AnimatedSnowFall {
private JComponent ui = null;
AnimatedSnowFall() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new SnowFall());
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
AnimatedSnowFall o = new AnimatedSnowFall();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
class SnowFall extends JPanel implements ActionListener {
Dimension prefSize = new Dimension(1600, 900);
SnowFlake[] farFlakes = new SnowFlake[200];
SnowFlake[] midFlakes = new SnowFlake[150];
SnowFlake[] closeFlakes = new SnowFlake[75];
Color farColor = new Color(100,100,255);
Color midColor = new Color(150,150,255);
Color closeColor = new Color(255,255,255);
SnowFall() {
setBackground(Color.BLACK);
for (int ii = 0; ii < farFlakes.length; ii++) {
farFlakes[ii] = new SnowFlake(prefSize.width, prefSize.height, 2, 4);
}
for (int ii = 0; ii < midFlakes.length; ii++) {
midFlakes[ii] = new SnowFlake(prefSize.width, prefSize.height, 3, 6);
}
for (int ii = 0; ii < closeFlakes.length; ii++) {
closeFlakes[ii] = new SnowFlake(prefSize.width, prefSize.height, 4, 8);
}
Timer timer = new Timer(50, this);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(farColor);
for (SnowFlake snowFlake : farFlakes) {
snowFlake.draw(g);
}
g.setColor(midColor);
for (SnowFlake snowFlake : midFlakes) {
snowFlake.draw(g);
}
g.setColor(closeColor);
for (SnowFlake snowFlake : closeFlakes) {
snowFlake.draw(g);
}
}
#Override
public Dimension getPreferredSize() {
return prefSize;
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
class SnowFlake {
int w;
int h;
int x;
int y;
int size;
int speed;
static Random r = new Random();
SnowFlake(int w, int h, int size, int speed) {
this.w = w;
this.h = h;
x = r.nextInt(w);
y = r.nextInt(h);
this.size = size;
this.speed = speed;
}
public void draw(Graphics g) {
y += speed;
if (y > h) {
x = r.nextInt(w);
y = 0;
}
g.fillOval(x, y, size, size);
}
}
I am trying to get an animation using a spritesheet in JFrame. The problem is the once loaded, the image doesn't change. It only shows the first image.
I have searched a lot and tried almost all the advice but can't get it to work.
By the way, getSprite has a return type of Image.
When I do everything in JFrame, only one image is shown. When I do it in separate class extending JPanel, I get only a white Window.
Update 1: Thanks to andrew, got JFrame working. Fixed my old part too. Here's the working code at ideone
Update 2:
Here's my version with timer.
class TestSpriteSheet extends JFrame{
//same old variables
public TestSpriteSheet(){
//same old stuff goes here before this
add(new PanelSprite(this, ss));
this.setVisible(true);
}
}
class PanelSprite extends JPanel{
private long runningTime = 0;
private int fps = 3;
private boolean stop = false;
private SpriteSheetManager ss;
private TestSpriteSheet temp;
public PanelSprite(TestSpriteSheet test, SpriteSheetManager sm){
ss = sm;
temp = test;
setSize(180,180);
setLayout(new BorderLayout()); init();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
long time = 5000;
animate_with_gfx(g, time);
}
public void init(){
Timer t = new Timer((int)(1000/fps), new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stop) {
repaint();
} else {
((Timer)e.getSource()).stop();
}
}
});
t.setRepeats(true);
t.setDelay((int)(1000/fps));
t.start();
}
public void animate_with_gfx(Graphics g, long time){
if(runningTime <= time){
try {
System.out.println(runningTime); //Checking if this part works
int x = 0; int y = 0;
g.drawImage(ss.getSprite(x, y), 40, 40, null);
x++; y++; runningTime+=(1000/fps);
}catch (Exception ex) {
ex.printStackTrace();
}
}
else{
stop = true;
}
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
long time = 5000; int fps = 3;
boolean stop = false;
Timer t = new Timer((int)(1000/fps), new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stop) {
animate_with_gfx(g, time, fps, stop);
repaint();
} else {
((Timer)e.getSource()).stop();
}
}
});
t.setRepeats(true);
t.setDelay((int)(1000/fps));
t.start();
System.exit(0);
}
This part is entirely wrong, since the paintComponent() method is called whenever the JRE thinks the view needs repainting. So definitely remove the System.exit(0);!
Then the Timer needs a single instance, to be started once. That would best be done in the constructor or an init() type method.
It might look something like this:
private int fps = 3;
private boolean stop = false;
public void paintComponent(Graphics g){
super.paintComponent(g);
long time = 5000;
animate_with_gfx(g, time, fps, stop);
}
/** Called from constructor.. */
public void init(){
Timer t = new Timer((int)(1000/fps), new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!stop) {
repaint();
} else {
((Timer)e.getSource()).stop();
}
}
});
t.setRepeats(true);
t.setDelay((int)(1000/fps));
t.start();
}
Update
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.*;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
class SpriteSheetManager {
private BufferedImage spriteSheet;
int cols;
int rows;
public SpriteSheetManager() {
setSpriteSheet();
}
public void setSpriteSheet() {
try {
spriteSheet = ImageIO.read(
new URL("http://s8.postimg.org/vso6oed91/spritesheet.png"));
setColsAndRows(3, 3);
} catch (IOException e) {
e.printStackTrace();
}
}
public BufferedImage getSpriteSheet() {
return spriteSheet;
}
public void setColsAndRows(int cols, int rows) {
this.cols = cols;
this.rows = rows;
}
public Image getSprite(int x, int y) {
Image sprite = null;
try {
sprite = spriteSheet.getSubimage(
x * spriteSheet.getWidth() / cols,
y * spriteSheet.getHeight() / rows,
spriteSheet.getWidth() / cols,
spriteSheet.getHeight() / rows);
} catch (Exception e) {
e.printStackTrace();
}
return sprite;
}
}
class Ideone {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestSpriteSheet();
}
});
}
}
class TestSpriteSheet extends JFrame {
private static final long serialVersionUID = 1L;
private SpriteSheetManager ss;
public TestSpriteSheet() {
super("Testing SpriteSheets");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLayout(new BorderLayout());
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent) {
System.exit(0);
}
});
ss = new SpriteSheetManager();
add(new PanelSprite(this, ss));
pack();
setSize(200, 200);
this.setVisible(true);
}
}
class PanelSprite extends JPanel {
private long runningTime = 0;
private int fps = 10;
private boolean stop = false;
private SpriteSheetManager ss;
private TestSpriteSheet temp;
private Timer t;
int count = 0;
long time = 50000;
public PanelSprite(TestSpriteSheet test, SpriteSheetManager sm) {
ss = sm;
temp = test;
init();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
animate_with_gfx(g);
}
public void init() {
t = new Timer((int) (1000 / fps), new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!stop) {
repaint();
} else {
((Timer) e.getSource()).stop();
}
}
});
t.setRepeats(true);
t.setDelay((int) (1000 / fps));
t.start();
}
public void animate_with_gfx(Graphics g) {
if (runningTime <= time) {
Image img = ss.getSprite((count % 9) % 3, (count % 9) / 3);
g.drawImage(img, 40, 40, this);
count++;
runningTime += (1000 / fps);
} else {
stop = true;
}
}
}
I'm trying to render a rectangle to a JPanel:
playerRect = new Rectangle(100,100,10,10);
Problem is, playerRect renders at 100,0 every time. I've updated Eclipse and Java, as well as troubleshoot my code and played with the x, y, width, height (although I'm not sure how my code could affect java.awt.Rectangle).
Any clue as to what is causing this?
package game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
public class Player {
private World world;
private Rectangle playerRect;
private Image playerImg;
protected int xDirection, yDirection;
//block variables
private int hoverX, hoverY;
private boolean hovering;
public Player(World world){
this.world = world;
playerImg = new ImageIcon("D:/Student Data/gametest1/GameEngine/res/player.png").getImage();
playerRect = new Rectangle(100, 100, 10, 10); // ### here's the issue ###
}
private void setXDirection(int d){
xDirection = d;
}
private void setYDirection(int d){
yDirection = d;
}
public void update(){
move();
checkForCollision();
}
private void move(){
playerRect.x += xDirection;
playerRect.y =+ yDirection;
}
private void checkForCollision(){
}
//Drawing methods
public void draw(Graphics g){
g.drawImage(playerImg, playerRect.x, playerRect.y, null);
}
private void drawBlackOutline(Graphics g){
g.setColor(Color.BLACK);
g.drawRect(hoverX,hoverY, world.blocks[0].width, world.blocks[0].height);
if(hovering){drawBlackOutline(g);}
}
//mouse events
public void mousePressed(MouseEvent e){
}
public void mouseReleased(MouseEvent e){
}
public void mouseMoved(MouseEvent e){
int x = e.getX();
int y = e.getY();
int px = playerRect.x;
int py = playerRect.y;
for(int i =0; i <world.arrayNum; i++){
if(world.blocks[i].contains(x,y)){
hovering = true;
hoverX = world.blocks[i].x;
hoverY = world.blocks[i].y;
break;
}else{hovering = false;}
}
}
public void mouseDragged(MouseEvent e){
}
private class Weapon{
public static final int UNARMED = 0;
public static final int PICKAXE = 1;
public static final int GUN = 2;
public int CURRENT_WEAPON;
public Weapon( int w){
switch(w){
default:
System.out.println("no weapon sellected");
break;
case UNARMED:
CURRENT_WEAPON = UNARMED;
break;
case PICKAXE:
CURRENT_WEAPON = PICKAXE;
break;
case GUN:
CURRENT_WEAPON = GUN;
break;
}
}
public void selectWeapon( int w){
switch(w){
default:
System.out.println("no weapon sellected");
break;
case UNARMED:
CURRENT_WEAPON = UNARMED;
break;
case PICKAXE:
CURRENT_WEAPON = PICKAXE;
break;
case GUN:
CURRENT_WEAPON = GUN;
break;
}
}
public boolean isEquipped(int w){
if(w == CURRENT_WEAPON){
return true;
}
else
return false;
}
}
}
Here's where the rectangle is drawn to the JPanel:
package game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
private static final long serialVersionUID = 1L;
//Double Buffering
private Image dbImage;
private Graphics dbg;
//JPanel variables
static final int GWIDTH = 900, GHEIGHT = 600;
static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);
//Game variables
private Thread game;
private volatile boolean running = false;
public int tickCount = 0;
private static final int DELAYS_BEFORE_YIELD = 10;
private long period = 6*1000000; //ms --> nano
//Game Objects
World world;
Player p1;
public GamePanel(){
world = new World();
p1 = new Player(world);
setPreferredSize(gameDim);
setBackground(Color.WHITE);
setFocusable(true);
requestFocus();
//Handle all key inputs from user
addKeyListener(new KeyAdapter(){
#Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_W){
world.navigateMap(World.PAN_UP);}
if(e.getKeyCode() == KeyEvent.VK_S){
world.navigateMap(World.PAN_DOWN);}
if(e.getKeyCode() == KeyEvent.VK_A){
world.navigateMap(World.PAN_LEFT);}
if(e.getKeyCode() == KeyEvent.VK_D){
world.navigateMap(World.PAN_RIGHT);}
}
#Override
public void keyReleased(KeyEvent e){
world.stopMoveMap();
}
#Override
public void keyTyped(KeyEvent e){
}
});
addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e){
}
#Override
public void mouseReleased(MouseEvent e){
}
#Override
public void mouseClicked(MouseEvent e){
}
});
addMouseMotionListener(new MouseAdapter(){
#Override
public void mouseMoved(MouseEvent e){
p1.mouseMoved(e);
}
#Override
public void mouseDragged(MouseEvent e){
}
#Override
public void mouseEntered(MouseEvent e){
}
#Override
public void mouseExited(MouseEvent e){
}
});
}
private void startGame(){
if(game == null || !running){
game = new Thread(this);
game.start();
running = true;
}
}
public void addNotify(){
super.addNotify();
startGame();
}
public void stopGame(){
if(running){
running = false;
}
}
public void run() {
long lastTime = System.nanoTime();
long beforeTime, afterTime, diff, sleepTime, overSleepTime = 0;
int delays = 0;
while(running){
beforeTime =System.nanoTime();
gameUpdate();
gameRender();
paintScreen();
afterTime = System.nanoTime();
diff = afterTime - beforeTime;
sleepTime = (period - diff) - overSleepTime;
//if the sleep time is between 0 and the period, sleep
if(sleepTime < period && sleepTime > 0){
try {
game.sleep(sleepTime/1000000L);
overSleepTime = 0;
} catch (InterruptedException e) {
System.err.println("You done goofed!");
}
}
//the difference was greater than the period
else if(diff>period){
overSleepTime = diff - period;
}
//accumulate the amount of delays, and eventually yield
else if(++delays >= DELAYS_BEFORE_YIELD){
game.yield();
}
//the loop took less time than expected,but we need to make up for oversleep time
else{overSleepTime = 0;}}
}
private void gameUpdate(){
if(running && game != null){
//update game state
world.moveMap();
p1.update();
}
}
private void gameRender(){
if(dbImage == null){ //create the buffer
dbImage = createImage(GWIDTH, GHEIGHT);
if(dbImage == null){
System.err.println("dbImage is still null!");
return;
}else{
dbg = dbImage.getGraphics();
}
}
//Clear the screen
dbg.setColor(Color.BLACK);
dbg.fillRect(0, 0, GWIDTH, GHEIGHT);
//Draw Game elements
draw(dbg);
}
//##### Draw all game content in this method #####//
public void draw(Graphics g){
world.draw(g);
p1.draw(g);
//g.setColor(Color.RED);
//g.setFont(new Font("PR Celtic Narrow", Font.BOLD, 50));
//String str = "MentalBrink Lv. 5";
//g.drawString(str, 100,100);
}
private void paintScreen(){
Graphics g;
try{
g = this.getGraphics();
if(dbImage != null && g != null){
g.drawImage(dbImage, 0, 0, null);
}
Toolkit.getDefaultToolkit().sync(); //for Linux people.
g.dispose();
}catch(Exception e){
System.err.println(e);
}
}
private void log(String s){
System.out.println(s);
}
}
The player is a panel, and it is getting removed, its position changed, and then re-added to another panel (which is what contains this method) which is drawn to the main frame. There are also a lot of other small panels containing a grass sprite being drawn to the primary panel as terrain tiles. I think the problem is that when I call revalidate(), it revalidates all those little panels as well. How can I solve this?
EDIT: I should mention that I am using RelativeLayout to position the players on the primary panel.
private class MainKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent evt) {
// TODO add your handling code here:
if(AttentionedPlayer != null)
{
if (evt.getKeyCode() == KeyEvent.VK_UP) {
AttentionedPlayer.Ypos -= 16;
}
if (evt.getKeyCode() == KeyEvent.VK_DOWN) {
AttentionedPlayer.Ypos += 16;
}
if (evt.getKeyCode() == KeyEvent.VK_LEFT) {
AttentionedPlayer.Xpos -= 16;
}
if (evt.getKeyCode() == KeyEvent.VK_RIGHT) {
AttentionedPlayer.Xpos += 16;
}
remove(AttentionedPlayer);
AttentionedPlayer.movePlayer();
System.out.println("!!!!"+AttentionedPlayer.constraints.toString());
add(AttentionedPlayer, AttentionedPlayer.constraints, AttentionedPlayer.Zpos);
AttentionedPlayer.revalidate();
}
}
}
AttentionedPlayer.movePlayer(); seems to be an intensive operation, and you execute it from within EDT (the GUI thread). Instead, execute it from within a new thread or a SwingWorker.
Read this answer to know more about SwingWorker.
#Eng.Fouad had a good point +1 to him, though I personally have never needed this for that exact reason, but your move method might be very cpu intensive.
Just to show an example (expanding from my comments) using your JPanel game logic, if implemented correctly there would be no need for revalidate() on player move (via setLocation(..)) which IMO is what also could cause a great amount of lag especially if there are many components. As you will see my GamePanel extends JPanel and uses Null/Absolute Layout (but for good reason in gaming we want more control over the Layout).
Also used KeyBindings to show you their useage.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class GameLogic {
public GameLogic() {
initComponents();
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Entity entity = new Entity("Player", 100, 100, 50, 50);//starting location 100,100 and width/height 50x50
GamePanel gp = new GamePanel(300, 300);
gp.addEntity(entity);
setGamePanelKeyBindings(gp, entity);
frame.add(gp);
frame.pack();
frame.setVisible(true);
}
private void setGamePanelKeyBindings(GamePanel gp, final Entity entity) {
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "D pressed");
gp.getActionMap().put("D pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.move(Entity.RIGHT);
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "A pressed");
gp.getActionMap().put("A pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.move(Entity.LEFT);
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "W pressed");
gp.getActionMap().put("W pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.move(Entity.UP);
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "S pressed");
gp.getActionMap().put("S pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.move(Entity.DOWN);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GameLogic();
}
});
}
}
class Entity extends JPanel {
private int width = 50, height = 50;
private int speed = 5;
public static final int UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4;
public Entity(String text, int x, int y, int width, int height) {
this.width = width;
this.height = height;
add(new JLabel(text));
setBorder(new LineBorder(Color.BLACK));
setBounds(x, y, width, height);
}
public void move(int direction) {
switch (direction) {
case UP:
setLocation(getX(), getY() - speed);
break;
case DOWN:
setLocation(getX(), getY() + speed);
break;
case LEFT:
setLocation(getX() - speed, getY());
break;
case RIGHT:
setLocation(getX() + speed, getY());
break;
}
}
#Override
public void setBounds(int x, int y, int w, int h) {
super.setBounds(x, y, width, height);
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
grphcs.setColor(Color.CYAN);
grphcs.fillRect(0, 0, getWidth(), getHeight());
}
}
class GamePanel extends JPanel {
private int width, height;
GamePanel(int w, int h) {
setLayout(null);
width = w;
height = h;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void addEntity(Entity e) {
add(e);
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
grphcs.setColor(Color.GREEN);
grphcs.fillRect(0, 0, getWidth(), getHeight());
}
}
Sorry I couldn't stop myself
if you are interested here is a bit of an advanced version with gameloop that can be paused, frame rate etc can be set, 2 keys (like W and D may be pressed simultaneously thus causing JPanel to move diagonally):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class GameLogic {
public GameLogic() {
initComponents();
}
final GamePanel gp = new GamePanel(500, 500);
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Entity entity = new Entity("Player", 100, 100, 100, 100);
gp.addEntity(entity);
setGamePanelKeyBindings(gp, entity);
frame.add(gp);
frame.pack();
frame.setVisible(true);
//start the game loop which will repaint the screen
runGameLoop();
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop() {
Thread loop = new Thread(new Runnable() {
#Override
public void run() {
gp.running = true;
gp.gameLoop();
}
});
loop.start();
}
private void setGamePanelKeyBindings(GamePanel gp, final Entity entity) {
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "D pressed");
gp.getActionMap().put("D pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.RIGHT = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "A pressed");
gp.getActionMap().put("A pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.LEFT = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "W pressed");
gp.getActionMap().put("W pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.UP = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "S pressed");
gp.getActionMap().put("S pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.DOWN = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "D released");
gp.getActionMap().put("D released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.RIGHT = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "A released");
gp.getActionMap().put("A released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.LEFT = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "W released");
gp.getActionMap().put("W released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.UP = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "S released");
gp.getActionMap().put("S released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
entity.DOWN = false;
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GameLogic();
}
});
}
}
class Entity extends JPanel {
private int width = 50, height = 50;
private int speed = 5;
public boolean UP = false, DOWN = false, LEFT = false, RIGHT = false;
public Entity(String text, int x, int y, int width, int height) {
this.width = width;
this.height = height;
add(new JLabel(text));
setBorder(new LineBorder(Color.BLACK));
setBounds(x, y, width, height);
}
public void move() {
if (UP) {
setLocation(getX(), getY() - speed);
}
if (DOWN) {
setLocation(getX(), getY() + speed);
}
if (LEFT) {
setLocation(getX() - speed, getY());
}
if (RIGHT) {
setLocation(getX() + speed, getY());
}
}
#Override
public void setBounds(int x, int y, int w, int h) {
super.setBounds(x, y, width, height);
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
grphcs.setColor(Color.CYAN);
grphcs.fillRect(0, 0, getWidth(), getHeight());
}
}
class GamePanel extends JPanel {
private int width, height;
private int frameCount = 0;
private int fps = 0;
public static boolean running = false, paused = false;
final ArrayList<Entity> entities = new ArrayList<>();
GamePanel(int w, int h) {
setLayout(null);
width = w;
height = h;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void addEntity(Entity e) {
add(e);
entities.add(e);
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
grphcs.setColor(Color.GREEN);
grphcs.fillRect(0, 0, getWidth(), getHeight());
grphcs.setColor(Color.BLACK);
grphcs.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
//Only run this in another Thread!
public void gameLoop() {
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running) {
double now = System.nanoTime();
int updateCount = 0;
if (!paused) {
//Do as many game updates as we need to, potentially playing catchup.
while (now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER) {
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if (now - lastUpdateTime > TIME_BETWEEN_UPDATES) {
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
drawGame();
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
if (thisSecond > lastSecondTime) {
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
fps = frameCount;
frameCount = 0;
lastSecondTime = thisSecond;
}
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
//allow the threading system to play threads that are waiting to run.
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
//On my OS it does not unpuase the game if i take this away
try {
Thread.sleep(1);
} catch (Exception e) {
}
now = System.nanoTime();
}
}
}
}
private void updateGame() {
for (Entity e : entities) {
e.move();
}
}
private void drawGame() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
repaint();
}
});
}
}