I have just started on learning how to use keyBindings and I cannot find out what I am doing wrong as when I press the UP arrow on my keyboard it does nothing.
My Main Game Window
public class GameWindow extends JFrame{
private static final long serialVersionUID = 1L;
public int WIDTH = 160, HEIGHT = WIDTH/12 *9, SCALE = 3;
public boolean running = false;
BackGround bg = new BackGround();
Ranger R = new Ranger();
TimerClass T = new TimerClass();
public static void main(String[] args) {
new GameWindow();
}
public GameWindow() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WIDTH * SCALE, HEIGHT * SCALE);
setResizable(false);
running = true;
add(bg);
bg.add(R);
bg.setFocusable(true);
R.setFocusable(true);
setFocusable(true);
setVisible(true);
bg.repaint();
run();
}
public void run() {
while (running) {
render();
}
}
public void render() {
bg.setLocation(Ranger.bgX, Ranger.bgY);
R.setLocation(Ranger.X, Ranger.Y);
R.setIcon(Ranger.rangerA[Ranger.I]);
R.repaint();
bg.repaint();
}
}
And My Ranger Class
public class Ranger extends JLabel {
private static final long serialVersionUID = 1L;
public static int X, Y, dX, dY, bgX, bgY, I = 0, jumpTime = 100;
public static boolean moving = false, movingLeft = false,
movingRight = false, onFloor = false, jumping = false,
movingUp = false, movingDown = false;
public int totalImages = 6;
public BufferedImage ranger1, ranger2, ranger3, ranger4, ranger5, ranger6;
public static ImageIcon[] rangerA;
static TileMap TileMap = new TileMap();
public Ranger() {
try {
// not moving
ranger1 = ImageIO.read(getClass().getResource(
"/Images/Sprites/ranger/Ranger0.png"));
ranger2 = ImageIO.read(getClass().getResource(
"/Images/Sprites/ranger/Ranger1.png"));
// moving Left
ranger3 = ImageIO.read(getClass().getResource(
"/Images/Sprites/ranger/Ranger2.png"));
ranger4 = ImageIO.read(getClass().getResource(
"/Images/Sprites/ranger/Ranger3.png"));
// moving Right
ranger5 = ImageIO.read(getClass().getResource(
"/Images/Sprites/ranger/Ranger4.png"));
ranger6 = ImageIO.read(getClass().getResource(
"/Images/Sprites/ranger/Ranger5.png"));
} catch (IOException e) {
e.printStackTrace();
}
array();
}
public void array() {
rangerA = new ImageIcon[6];
{
rangerA[0] = new ImageIcon(ranger1);
rangerA[1] = new ImageIcon(ranger2);
rangerA[2] = new ImageIcon(ranger3);
rangerA[3] = new ImageIcon(ranger4);
rangerA[4] = new ImageIcon(ranger5);
rangerA[5] = new ImageIcon(ranger6);
}
}
public void move() {
AbstractAction moveUp = new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
System.out.println("Move up");
}
};
this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "moveUp");
this.getActionMap().put("moveUp", moveUp);
X += dX;
Y += dY;
dX = 0;
dY = 0;
if (movingRight || movingLeft) {
moving = true;
}
}
}
I am trying it to output that it will move up in the console so that i can lean how to make new KeyBindings but I don't know why it dosn't work. Any solutions/tips will be much appreciated.
P.S. I am new to Java so sorry for simple mistakes and I am also aware of the wild loop in the main game window class.
EDIT: move() is called every few miliseconds in a seperate timer class.
KeyStroke.getKeyStroke("W") doesn't do what you think it does. Using this form requires a verbose description of the action, ie typed w.
For this reason, I never use it. Instead, I prefer to use KeyStroke.getKeyStroke(KeyEvent.VK_W, 0) which is much more direct
See KeyStroke#getKeyStroke(int, int) for more details.
You're also not binding the key strokes as you never call the move method. Instead, bind the key strokes in the classes constructor or some other method which should be called only once.
Related
I am trying to create a LinkedList of all the keys pressed, but the keyPressed() and keyReleased() methods aren't being called. I've already tried frame.setFocusable(true).
Here is my code (also sorry if's a big pile of spaghetti):
Window.java
public class Window {
protected JFrame frame;
private boolean clicked = false; // TODO: Mouse input
private LinkedList<Character> keysDown = new LinkedList<>();
public Window(String title, Dimension resolution, Canvas display) {
frame = new JFrame(title);
Dimension decoratedResolution = new Dimension(resolution.width + 16, resolution.height + 38); // The resolution of the window is mismatched, this makes it so resolution.height is actually the bottom of the screen and not a little further below and the same for resolution.width.
frame.setPreferredSize(decoratedResolution);
frame.setMinimumSize(decoratedResolution);
frame.setMaximumSize(decoratedResolution);
frame.setResizable(false);
frame.setLocationRelativeTo(null); // Center the window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setFocusable(true);
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
char character = e.getKeyChar();
if (!keysDown.contains(character))
keysDown.add(character);
}
#Override
public void keyReleased(KeyEvent e) {
char character = e.getKeyChar();
keysDown.remove((Object)character);
}
});
frame.add(display);
frame.setVisible(true);
}
public boolean isMouseDown() {
return clicked;
}
public Vector2 getMousePosition() {
Point point = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(point, frame);
return new Vector2(point);
}
public LinkedList<Character> getKeysDown() {
return keysDown;
}
}
Edit: All the other code relevant is below
P.S. This is one of my first times using stack overflow so If I made a mistake in formatting the question, let me know.
Game.java
public class Game extends Canvas implements Runnable {
// General Settings
public static final String TITLE = "Game";
public static final Dimension RESOLUTION = new Dimension(800, 450);
public static final int FPS = 60;
// Do not modify
protected static final long NANO_SECOND = 1000000000;
public float timeScale = 1f;
public volatile boolean running = false; // Set to false to stop the game
public Thread thread;
public Window window;
public Renderer renderer;
public static void main(String[] args) {
new Game();
}
public Game() {
start();
}
public void start() {
init();
}
public void init() {
window = new Window(TITLE, RESOLUTION, this);
}
public void run() {
final float RENDER_INTERVAL = 1f / FPS;
long then = System.nanoTime();
long now = then;
float deltaTime = 0f;
int frames = 0;
while (running) {
now = System.nanoTime();
deltaTime = (float)(now - then) / NANO_SECOND;
update(deltaTime * timeScale);
if (!running)
break;
then = now;
Thread.onSpinWait();
}
}
public void update(float deltaTime) {
if (window.getKeysDown().contains('d'))
System.out.println("d pressed");
}
It turns out I had to call addKeyListener() in the Game class.
--WORKING ON A SHORTER VERSION OF THE QUESTION--
So, this is someting I can't really find that much information on online.
I am making a game together with my friend and we came accross a problem when we wanted to move some objects in a thread. We have one object, GroundBlocks, which is working fine and how it is supposed to.
Then we have the other object, Obstacles, that uses the same "method" of printing and processing but doesn't show up.
I did some troubleshooting myself and I noticed that the paintComponent block in Obstacles isn't beeing called by the .setLocation we added in the thread.
As I mentioned, I didn't find a whole lot online when searching myself but through testing, I know the numbers are correct but it is just not showing.
Any ideas on what the issue might be with the .setLocation not working?
--Relevant code from the thread class--
// Creating objects
public static GroundBlocks[] ground = {new GroundBlocks(), new GroundBlocks(), new GroundBlocks()};
public static Obstacles[] obstacle = {new Obstacles(), new Obstacles(), new Obstacles(), new Obstacles(), new Obstacles()};
// Creating block dimensions
final int GROUND_HEIGHT = resY - GroundBlocks.getGroundHeight();
final int GROUND_WIDTH = ground[1].getGroundWidth();
int[] groundX = {0, GROUND_WIDTH, GROUND_WIDTH*2};
final int OBSTACLE_HEIGHT = obstacle[0].getHeight();
final int OBSTACLE_WIDTH = obstacle[0].getWidth();
int[] obstacleX = {newCoord(0), newCoord(0), newCoord(0), newCoord(0), newCoord(0)};
int[] obstacleY = {newCoord(1), newCoord(1), newCoord(1), newCoord(1), newCoord(1)};
// Setting game animation movement
final int MOVEMENT_SPEED = 7;
// Setting timer object with preferred FPS
Timer time = new Timer(Init.getFps(0), this);
public void run() {
System.out.println("A new MainThread has been initiated");
time.start();
// Setting ground block size, starting location and image
for(int i = 0; i < ground.length; i++) {
ground[i].setLocation(groundX[i], GROUND_HEIGHT);
ground[i].setSize(GROUND_WIDTH, GROUND_HEIGHT);
ground[i].setGroundImage(pickRandomGroundImage());
}
// Setting background image for obstacles
for (int i = 0; i < obstacle.length; i++) {
obstacle[i].setSize(OBSTACLE_WIDTH, OBSTACLE_HEIGHT);
obstacle[i].setLocation(obstacleX[i], obstacleY[i]);
obstacle[i].setObstacleImage(img5);
// System.out.println(obstacle[i].getLocation());
}
}
#Override
public void actionPerformed(ActionEvent arg0) {
for(int i = 0; i < ground.length; i++) {
// Respawning ground block
if(groundX[i] <= -resX) {
groundX[i] = GROUND_WIDTH*2 - MOVEMENT_SPEED;
ground[i].setGroundImage(pickRandomGroundImage());
}
// Animating ground block
ground[i].setLocation(groundX[i] -= MOVEMENT_SPEED, GROUND_HEIGHT);
}
for (int i = 0; i < obstacle.length; i++) {
// Resetting obstacle block
if ((obstacleX[i] + OBSTACLE_WIDTH) <= -10) {
obstacleX[i] = newCoord(0);
obstacleY[i] = newCoord(1);
obstacle[i].setObstacleImage(img5);
}
// Animating obstacle block
obstacle[i].setLocation(obstacleX[i] -= MOVEMENT_SPEED, obstacleY[i]);
if (i == 0) {
System.out.println(obstacle[i].getLocation());
}
}
}
--GroundBlocks class--
public class GroundBlocks extends JPanel{
// Declarations
static int resX = Main._init.getResX();
static int resY = Main._init.getResY();
static String font = Main._init.getOurFont();
private static int groundWidth;
private static int groundHeight;
private Image chosenImage;
public GroundBlocks() {
System.out.println("GroundBlock created");
setScaleIndex();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Draw image background
g.drawImage(chosenImage, 0, 0, this);
}
// Applying the scaleIndex to the ground objects X and Y dimensions.
// Size changes can be made manually in Init.
public void setScaleIndex() {
groundWidth = (int) (Init.getGroundSize(0) * Init.getScaleIndex());
groundHeight = (int) (Init.getGroundSize(1) * Init.getScaleIndex());
}
public int getGroundWidth() {
return groundWidth;
}
public static int getGroundHeight() {
return groundHeight;
}
public void setGroundImage(Image image) {
chosenImage = image;
}
}
--Obstacles code--
public class Obstacles extends JPanel{
// Declarations
static int resX = Main._init.getResX();
static int resY = Main._init.getResY();
static String font = Main._init.getOurFont();
private static int obstacleHeight;
private static int obstacleWidth;
private Image chosenImage;
public Obstacles() {
System.out.println("New obstacle object created!");
setScaleIndex();
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Printed obstacle");
g.drawImage(chosenImage, 0, 0, this);
}
// Applying the scaleIndex to the ground objects X and Y dimensions.
// Size changes can be made manually in Init.
public void setScaleIndex() {
obstacleWidth = (int) (Init.getObstacleSize(0) * Init.getScaleIndex());
obstacleHeight = (int) (Init.getObstacleSize(1) * Init.getScaleIndex());
}
public int getObstacleHeight() {
return obstacleHeight;
}
public int getObstacleWidth() {
return obstacleWidth;
}
public void setObstacleImage(Image image) {
chosenImage = image;
}
}
I'm making a game in Swing and I'm running into an error where randomly, when opening the program, nothing displays. There's seemingly nothing that triggers it, but I have no idea what could possibly be causing it. And also this is everything in my program that seems to be the problem, Since when i tested the source of the problem, it seems to be that the problem is that it is not rendering anything. My update method is working, but the paint method is not running.
Here is the gameHandler class that loads everything and where I believe the problem could be occurring, if this isn't enough to locate the error, please ask me to add whatever it is you would like to see.
public class GameHandler
{
private GamePanel gp;
private Player p;
private StarManager sm;
private EnemyManager em;
private UI ui;
private BulletManager bm;
private PANEL state;
private MenuPanel mp;
public GameHandler(GamePanel gp, Core c)
{
this.gp = gp;
p = new Player(c.getWidth()/2 - 50/2, c.getHeight() - c.getHeight()/4, 25, 50, c);
sm = new StarManager(50, c.getWidth(), c.getHeight(), 15);
em = new EnemyManager(gp, c, p);
bm = new BulletManager(4, p, em);
new GameInput(c, p, bm);
ui = new UI(p);
mp = new MenuPanel(c);
}
public void update()
{
state = gp.getState();
sm.update();
if(state == PANEL.GAME)
{
p.update();
em.update();
bm.update();
}
}
public void render(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
sm.render(g);
if(state == PANEL.GAME)
{
p.render(g);
bm.render(g);
em.render(g);
ui.render(g);
}
else if(state == PANEL.MENU)
{
mp.render(g);
}
}
}
public class Core extends JComponent implements Runnable
{
private static final long serialVersionUID = 1L;
private int
WIDTH = 800,
HEIGHT = 800;
public boolean running;
public GamePanel gp;
public Core()
{
new Display(WIDTH, HEIGHT, "Geometric Space Invasion", this);
init();
}
public void init()
{
gp = new GamePanel(this);
setLayout(new BorderLayout());
add(gp, BorderLayout.CENTER);
Thread t = new Thread(this);
running = true;
t.start();
}
public static void main(String[] args)
{
new Core();
}
#Override
public void run()
{
while(running)
{
try
{
Thread.sleep(7);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
gp.update();
gp.repaint();
}
}
public int getWidth()
{ return WIDTH; }
public int getHeight()
{ return HEIGHT; }
}
public class GamePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private GameHandler gh;
private PANEL state = PANEL.MENU;
private boolean gameOver;
public GamePanel(Core c)
{
setBackground(Color.BLACK);
gameOver = false;
gh = new GameHandler(this, c);
}
public void update()
{
if(gameOver)
state = PANEL.MENU;
gh.update();
}
public enum PANEL
{
MENU,
GAME
/* THIS IS HOW TO CREATE A PANEL VAIRABLE AND CHECK
private PANEL test = PANEL.MENU;
if(test == PANEL.MENU)
//Do whatever.
*/
}
public enum DIFFICULTY
{
EASY,
MEDIUM,
HARD
}
public DIFFICULTY diff = DIFFICULTY.MEDIUM; //TODO : REMOVE
public void paintComponent(Graphics g)
{
super.paintComponent(g);
gh.render(g);
}
public DIFFICULTY getDifficulty()
{
return diff;
}
public PANEL getState()
{
return state;
}
public void setGameOver(boolean gameOver)
{
this.gameOver = gameOver;
}
}
EDIT: FIXED. I fixed it by switching the two lines in the constructor for the Core class.
public Core()
{
new Display(WIDTH, HEIGHT, "Geometric Space Invasion", this);
init();
}
became
public Core()
{
init();
new Display(WIDTH, HEIGHT, "Geometric Space Invasion", this);
}
So I'm trying to write a tile-grid based game and came up with a quite unusual solution. I filled a 2D JPanel Array with JLabels with an ImageIcon as tile. Everything works so far but I did not find any way to render this activly.
I've tryied some methods for active rendering I found on the Internet, but they did not work on my idea. Do you have some ideas how to realize this without rewrite everything to Canvas or something similar?
Here's my code:
Window
public class Win extends JFrame {
private static final long serialVersionUID = 1L;
private BufferStrategy bs;
public Win(int x, int y) {
this.setSize(x, y);
this.setVisible(true);
this.setResizable(false);
this.setIgnoreRepaint(true);
this.createBufferStrategy(2);
setBs(getBufferStrategy());
}
public BufferStrategy getBs() {
return bs;
}
public void setBs(BufferStrategy bs) {
this.bs = bs;
}
}
"Draw"
public class Field extends JPanel {
private static final long serialVersionUID = 5257799495742189076L;
private int x = 0;
private int y = 0;
private JPanel backPanel[][] = new JPanel[19][19];
private BufferedImage images[] = new BufferedImage[100];
private JLabel image[][] = new JLabel[19][19];
public Field() {
this.setLayout(new GridLayout(20, 20));
this.setIgnoreRepaint(true);
}
// Creates Panel Grid & Draws floor
public void setPanels() {
for (int h = 0; h < 19; h++) {
for (int w = 0; w < 19; w++) {
backPanel[h][w] = new JPanel();
backPanel[h][w].setLayout(new GridLayout(1, 1));
image[h][w] = new JLabel(new ImageIcon(images[0]));
backPanel[h][w].add(image[h][w]);
this.add(backPanel[h][w]);
}
}
}
// Loads the Textures
public void getTextures() throws IOException {
for (int i = 0; i < 1; i++) {
images[i] = ImageIO.read(new File("texture.png"));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images[1], 0, 0, null);
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
}
Game Loop
public class GameLoop implements Runnable {
private boolean runFlag = true;
#Override
public void run() {
Field field = new Field();
Win window = new Win(640, 640);
window.add(field);
try {
field.getTextures();
} catch (IOException e) {
e.printStackTrace();
}
while (runFlag) {
try {
field.setPanels();
window.getBs().show();
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop() {
runFlag = false;
}
}
Some alternatives:
Shuffle the components and do removeAll(), add(), and validate() as shown here.
Shuffle the contents and do setIcon(), as shown here.
In either case,
Use javax.swing.Timer to pace the animation, as shown here and here.
Consider TexturePaint to fill the icons, as shown here.
I'm making a small game in Java using an extension of Swing's JPanel as my drawing surface.
I draw everything inside panel's paintComponent()
The game runs smoothly until I start moving my mouse. When I do I get huge FPS drops, especially if i move it very fast, making the game unplayable.
That happens even when I stop drawing the mouse cursor.
Is this normal when drawing on JComponent objects?
P.S. I couldn't find any registered MouseListener or MouseMotionListener objects on any of my components.
EDIT:
MCVE
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class AnimationSlowDownOnMouse {
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame mainWindow = new JFrame("dotShoot");
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setExtendedState(JFrame.MAXIMIZED_BOTH);
final GamePanel gp = new GamePanel();
gp.setPreferredSize(new Dimension(1920, 1080));
mainWindow.add(gp);
mainWindow.pack();
gp.init();
Thread gameThread = new Thread(new Runnable() {
#Override
public void run() {
final int maxTicksPerSecond = 100;
final int optimalTimePerTick = 1000 / maxTicksPerSecond;
final int maxFrameSkips = 5;
long tickCount = 0L;
float AvgIES = 0f;
//int FPS = 0;
int DCPS = 0;
int TPS = 0;
long timeStarted = System.currentTimeMillis();
long timeElapsed = 0L;
int tickReset = 0;
int drawCallsReset = 0;
long timeReset = timeStarted;
float interpolationReset = 0f;
long nextLoop = timeStarted;
int frameSkips = 0;
float interpolation;
while (true) {
synchronized (this) {
frameSkips = 0;
while (System.currentTimeMillis() > nextLoop && frameSkips < maxFrameSkips) {
gp.update(tickCount);
nextLoop += optimalTimePerTick;
tickCount++;
tickReset++;
frameSkips++;
}
interpolation = (float) (System.currentTimeMillis() + optimalTimePerTick - nextLoop) / (float) optimalTimePerTick;
gp.setInterpolation(interpolation);
gp.repaint();
interpolationReset += interpolation;
drawCallsReset++;
timeElapsed = System.currentTimeMillis() - timeStarted;
if (System.currentTimeMillis() - timeReset >= 1000) {
AvgIES = interpolationReset / (float) drawCallsReset;
interpolationReset = 0f;
TPS = tickReset;
tickReset = 0;
DCPS = drawCallsReset;
drawCallsReset = 0;
timeReset = System.currentTimeMillis();
}
}
}
}
});
gameThread.start();
mainWindow.setVisible(true);
gp.requestFocus();
}
}
class GamePanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 3110478596996378903L;
public GamePanel() {
this.getInputMap().put(KeyStroke.getKeyStroke("pressed A"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released A"), "released Key");
this.getInputMap().put(KeyStroke.getKeyStroke("pressed D"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released D"), "released Key");
this.getInputMap().put(KeyStroke.getKeyStroke("pressed W"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released W"), "released Key");
this.getInputMap().put(KeyStroke.getKeyStroke("pressed S"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released S"), "released Key");
this.getActionMap().put("pressed Key", new AbstractAction() {
private static final long serialVersionUID = 1296609706338138539L;
#Override
public void actionPerformed(ActionEvent arg0) {
if (!pks.contains(arg0.getActionCommand())) {
pks += arg0.getActionCommand() + ", ";
}
}
});
this.getActionMap().put("released Key", new AbstractAction() {
private static final long serialVersionUID = 4364732373538162119L;
#Override
public void actionPerformed(ActionEvent arg0) {
pks = pks.replace(arg0.getActionCommand() + ", ", "");
}
});
this.setBackground(new Color(0x6495ed));
}
public void init() {
}
private String pks = "";
public void update(long currentTick) {
}
private float interpolation = 0;
public void setInterpolation(float interpolation) {
this.interpolation = interpolation;
}
private int frames = 0;
private long timeForFPS = 0;
private int ActualFPS = 0;
public int getFPS() {
return ActualFPS;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.drawString("FPS: " + ActualFPS, 0, 10);
frames++;
if (System.currentTimeMillis() - timeForFPS >= 1000) {
ActualFPS = frames;
frames = 0;
timeForFPS = System.currentTimeMillis();
}
}
}
EDIT 2:
http://tinypic.com/r/9bkf4k/8
http://tinypic.com/r/345m24i/8
As with the other comments, there is no problem with FPS when I tried the code above here in my computer. I also tried it on my virtual machine having one processor only. Still there is no dramatic drop of the FPS when the mouse is moving fast. Although the processor always shows 100% usage. Have you tried this with other computers? I suspect, you too won't see the FPS problem in there. So maybe the issue lies in your computer and not on your program code.