So I'm trying to awnser this question for like 2-3 hours now, but I can't quite find an fix or resolution for my problem. Like there are no Video tutorials. And because I am new to programming, especially with Java, I just don't know, how to rewrite code, that it matches my code and perfectly works. Here is what I have right now:
Also my project is all based on 2D and you only see your player for right above. So I dont really need Animation for the Player and Entity models, just in case you wondered.
Class: GamePanel
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import entity.Player;
public class GamePanel extends JPanel implements Runnable{
// SCREEN SETTINGS
final int originalTitleSize = 16; // 16x16 title
final int scale = 3; //16x3(scale) = 48
public final int tileSize = originalTitleSize * scale; //48x48 title
final int maxScreenCol = 16;
final int maxScreenRow = 12;
final int screenWidth = tileSize * maxScreenCol; // 768 pixels
final int screenHeight = tileSize * maxScreenRow; // 576 pixels
//FPS
int FPS = 60;
KeyHandler keyH = new KeyHandler();
Thread gameThread;
Player player = new Player(this,keyH);
// Set player's default position
int playerX = 100;
int playerY = 100;
int playerSpeed = 4;
public GamePanel() {
this.setPreferredSize(new Dimension(screenWidth, screenHeight));
this.setBackground(Color.BLACK);
this.setDoubleBuffered(true);
this.addKeyListener(keyH);
this.setFocusable(true);
}
public void startGameThread() {
gameThread = new Thread(this);
gameThread.start();
}
@Override
// public void run() {
//
// double drawInterval = 1000000000/FPS; // 0.0166666... seconds
// double nextDrawTime = System.nanoTime() drawInterval;
//
//
//
// while(gameThread != null) {
//
// // System.out.println("The game loop is running");
//
// // 1 UPDATE: update information such as character positions
// update();
//
//
//
// // 2 DRAW: draw the screen with the updated information
// repaint();
//
// try {
// double remainingTime = nextDrawTime - System.nanoTime();
// remainingTime = remainingTime/1000000;
//
// if(remainingTime < 0) {
// remainingTime = 0;
// }
//
// Thread.sleep((long) remainingTime);
//
// nextDrawTime = drawInterval;
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
public void run() {
double drawInterval = 1000000000/FPS;
double delta = 0;
long lastTime = System.nanoTime();
long currentTime;
long timer = 0;
int drawCount = 0;
while(gameThread != null) {
currentTime =System.nanoTime();
delta = (currentTime - lastTime) / drawInterval;
timer = (currentTime -lastTime);
lastTime = currentTime;
if(delta >=1) {
update();
repaint();
delta--;
drawCount ;
}
if(timer >= 1000000000) {
System.out.println("FPS:" drawCount);
drawCount = 0;
timer = 0;
}
}
}
public void update() {
player.update();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
player.draw(g2);
g2.dispose();
}
}
Class: KeyHandler
package main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyHandler implements KeyListener{
public boolean upPressed, downPressed, leftPressed, rightPressed;
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_W) {
upPressed = true;
}
if(code == KeyEvent.VK_S) {
downPressed = true;
}
if(code == KeyEvent.VK_A) {
leftPressed = true;
}
if(code == KeyEvent.VK_D) {
rightPressed = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_W) {
upPressed = false;
}
if(code == KeyEvent.VK_S) {
downPressed = false;
}
if(code == KeyEvent.VK_A) {
leftPressed = false;
}
if(code == KeyEvent.VK_D) {
rightPressed = false;
}
}
}
Class: Main
package main;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.setTitle("Zombio 0.0.0.01");
GamePanel gamePanel = new GamePanel();
window.add(gamePanel);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
gamePanel.startGameThread();
}
}
I also have an Player:
package entity;
import java.awt.Color;
import java.awt.Graphics2D;
import main.GamePanel;
import main.KeyHandler;
public class Player extends Entity{
GamePanel gp;
KeyHandler keyH;
public Player(GamePanel gp, KeyHandler keyH) {
this.gp = gp;
this.keyH = keyH;
setDefaultValues();
}
public void setDefaultValues() {
x = 100;
y = 100;
speed = 4;
}
public void update() {
if(keyH.upPressed == true) {
y -= speed;
}
else if(keyH.downPressed == true) {
y = speed;
}
else if(keyH.leftPressed == true) {
x -= speed;
}
else if(keyH.rightPressed == true) {
x = speed;
}
}
public void draw(Graphics2D g2) {
g2.setColor(Color.yellow);
g2.fillRect(x, y, gp.tileSize, gp.tileSize); //(x, y, width, height)
}
}
And this Player is based on the normal-entity:
package entity;
public class Entity {
public int x, y;
public int speed;
}
I know, this is a lot you need to look through, but I really don't know, what exaclty you need. I would like to implement the rotation in the Player Class, if this is possible for you. Also please not only write Code and set it as awnser, I really have no expirience, so take my by the hand :)
Thanks for your help, appreciate it!
CodePudding user response:
You will want to have a look at:
- Key bindings - these will solve all the focus related issues with
KeyListener
- Concurrency in Swing and probably switch over to using a Swing
Timer
. Swing is NOT thread safe, it's not a good idea to useThread
as your "main loop".
So your basic problem is a "simple" trigonometry problem (I as say simple, but I'm an idiot). You have two points in space and need to calculate the angle between them, for example...
// Radians
-Math.atan2(startX - endX, startY - endY)
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame();
frame.add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.startGameThread();
}
});
}
public class GamePanel extends JPanel { //implements Runnable {
// SCREEN SETTINGS
final int originalTitleSize = 16; // 16x16 title
final int scale = 3; //16x3(scale) = 48
public final int tileSize = originalTitleSize * scale; //48x48 title
final int maxScreenCol = 16;
final int maxScreenRow = 12;
final int screenWidth = tileSize * maxScreenCol; // 768 pixels
final int screenHeight = tileSize * maxScreenRow; // 576 pixels
//FPS
int FPS = 60;
Player player = new Player(this);
private Timer timer;
private Set<KeyAction.Direction> movementState = new HashSet<>();
private Point lastKnownMousePoint;
public GamePanel() {
this.setBackground(Color.BLACK);
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
lastKnownMousePoint = e.getPoint();
}
});
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
ActionMap am = getActionMap();
am.put("Pressed.up", new KeyAction(KeyAction.Direction.UP, true, movementState));
am.put("Released.up", new KeyAction(KeyAction.Direction.UP, false, movementState));
am.put("Pressed.down", new KeyAction(KeyAction.Direction.DOWN, true, movementState));
am.put("Released.down", new KeyAction(KeyAction.Direction.DOWN, false, movementState));
am.put("Pressed.left", new KeyAction(KeyAction.Direction.LEFT, true, movementState));
am.put("Released.left", new KeyAction(KeyAction.Direction.LEFT, false, movementState));
am.put("Pressed.right", new KeyAction(KeyAction.Direction.RIGHT, true, movementState));
am.put("Released.right", new KeyAction(KeyAction.Direction.RIGHT, false, movementState));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(screenWidth, screenHeight);
}
public void startGameThread() {
if (timer == null) {
timer = new Timer((int) Math.floor(1000f / FPS), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
});
}
timer.start();
}
public void update() {
if (movementState.contains(KeyAction.Direction.UP)) {
player.y -= player.speed;
} else if (movementState.contains(KeyAction.Direction.DOWN)) {
player.y = player.speed;
} else if (movementState.contains(KeyAction.Direction.LEFT)) {
player.x -= player.speed;
} else if (movementState.contains(KeyAction.Direction.RIGHT)) {
player.x = player.speed;
}
if (lastKnownMousePoint != null) {
// This assumes that character is facing "UP" by default
// That is, 0 has the character entity facing towards to the
// top of the sceen. If the character is facing in a different
// direction, then you will need to offset this calculation
// to compenstate, but that might be better done in the player
// entity
double angle = -Math.toDegrees(Math.atan2(player.x - lastKnownMousePoint.x, player.y - lastKnownMousePoint.y));
player.angleInDegrees = angle;
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
player.draw(g2);
g2.dispose();
}
}
public class KeyAction extends AbstractAction {
enum Direction {
UP, DOWN, LEFT, RIGHT
}
private Direction direction;
private boolean activate;
private Set<Direction> inputState;
public KeyAction(Direction direction, boolean activate, Set<Direction> inputState) {
this.direction = direction;
this.activate = activate;
this.inputState = inputState;
}
@Override
public void actionPerformed(ActionEvent e) {
if (activate) {
inputState.add(direction);
} else {
inputState.remove(direction);
}
}
}
public class Entity {
public int x;
public int y;
public int speed;
}
public class Player extends Entity {
GamePanel gp;
double angleInDegrees = 0;
public Player(GamePanel gp) {
this.gp = gp;
setDefaultValues();
}
public void setDefaultValues() {
x = 100;
y = 100;
speed = 4;
}
public void draw(Graphics2D g2) {
g2 = (Graphics2D) g2.create();
g2.translate(x, y);
g2.rotate(Math.toRadians(angleInDegrees), (gp.tileSize / 2), (gp.tileSize / 2));
g2.setColor(Color.yellow);
g2.fillRect(0, 0, gp.tileSize, gp.tileSize);
g2.setColor(Color.RED);
g2.drawLine((gp.tileSize / 2), (gp.tileSize / 2), (gp.tileSize / 2), 0);
g2.dispose();
}
}
}