I'm making a game, and I have the following main classes
Main controller class:
public class Manager implements Runnable {
private boolean running;
private Thread thread;
private MasterRenderer window;
private PlayerCharacter player;
private Map map;
public Manager() {
window = new MasterRenderer();
player = new PlayerCharacter(0, 0, Entity.FACING_DOWN, "Pepe", 0, 1, 2);
map = new Map();
}
public void initialize() {
window.setPlayerRenderer(new PlayerRenderer(player));
window.setMapRenderer(new MapRenderer(map));
window.setTerrainRenderer(new TerrainRenderer(new Terrain(0, 0, Entity.FACING_DOWN, "arbol", false)));
running = true;
thread = new Thread(this);
thread.start();
}
public void run() {
long timer = System.currentTimeMillis();
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60.0;
double delta = 0;
int frames = 0;
int ticks = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick(delta);
ticks++;
delta--;
frames++;
render();
}
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("Frames: " + frames + "\tTicks: " + ticks);
frames = ticks = 0;
}
}
}
public void tick(double delta) {
}
public void render() {
window.render();
}
public static void main(String[] args) {
Manager manager = new Manager();
manager.initialize();
}
}
Main view class:
public class MasterRenderer extends Canvas implements KeyListener {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 640;
public static final int HEIGHT = WIDTH * 3 / 4;
public static final String TITLE = "The legend of Finn";
private JFrame frame;
private BufferStrategy bs;
private Graphics g;
private PlayerRenderer playerR;
private MapRenderer mapR;
private TerrainRenderer terrainR;
public MasterRenderer() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
frame = new JFrame();
addKeyListener(this);
frame.setTitle(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
requestFocus();
}
public void render() {
bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
playerR.render(g);
mapR.render(g);
terrainR.render(g);
bs.show();
g.dispose();
}
public void setMapRenderer(MapRenderer mapR) {
this.mapR = mapR;
}
public void setPlayerRenderer(PlayerRenderer playerR) {
this.playerR = playerR;
}
public void setTerrainRenderer(TerrainRenderer terrainR) {
this.terrainR = terrainR;
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int i=e.getKeyCode();
System.out.println("Key pressed!!");
}
#Override
public void keyReleased(KeyEvent e) {
}
}
I've organize the code this way, because I'm trying to really stick to MVC (besides, putting the keyListener in the manager class now is a bit of a pain in the butt). Is there any simple way to notify Manager when MasterRenderer registers a key press?
Your View has no Control reference within it, and no methods for registering listeners, and without this, I don't see how the view will communicate with the control. I see you have two possible solutions:
Pass the Control reference into the view, and have the view call methods of the control when it wants to notify it of a state change, or
set up a mechanism, such as a SwingPropertyChangeSupport mechanism, that will allow the control to listener for state changes. If you go this route, then you have to call the approprate fireXxx(...) methods of the support.
Luckily many Swing and AWT components already have mechanisms for number 2 above, and I suggest that you do just this: have your control register a PropertyChangeListener with your Canvas object (better if it were a JPanel!), and then in your KeyListener a firePropertyChange(...) method notifying the control of the state change.
For example:
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class MyControl implements Runnable, PropertyChangeListener {
public MyControl() {
// TODO finish
}
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
// this is only one of potentially many properties that the control can listen to
if (MyView.KEY_PRESSED.equals(pcEvt.getPropertyName())) {
// respond to the key pressed code
System.out.println("KeyCode is: " + pcEvt.getNewValue());
}
}
#Override
public void run() {
// TODO Finish!
}
private static void createAndShowGui() {
// create both view and control
MyControl control = new MyControl();
MyView view = new MyView();
// now wire the control to listen to the view
view.addPropertyChangeListener(MyView.KEY_PRESSED, control);
JFrame frame = new JFrame("MyControl");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(view);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyView extends JPanel {
// constant for PropertyChangeListener use:
public static final String KEY_PRESSED = "key pressed";
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
public MyView() {
setFocusable(true);
requestFocusInWindow();
addKeyListener(new MyKeyListener());
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyKeyListener extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
// get the keycode pressed
int newValue = e.getKeyCode();
// ** notify any listeners that this key has been pressed **
firePropertyChange(KEY_PRESSED, null, newValue);
}
}
}
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.
What I'm trying to do
Making a Pong game where the Y axis gets the value from my cursor according to the application
What did I tried
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This way I get the Y value according to my monitor instead of the application.
I also tried to use the MouseEvent.getY(), but I get the error when trying to call this method from the main.
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This is how my code looks like, I think the problem lies in how I'm using my main and methods but I'm not sure.
public class MyFirst extends JPanel {
public int x = 500, y = 300, border = 30;
public boolean goingDown = true;
public int ycur, cursor;
public void moveBall() {
x++;
if (goingDown == true) {
y++;
} else if (goingDown == false) {
y--;
}
if (y == getHeight() - border) {
goingDown = false;
} else if (y == 0) {
goingDown = true;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 30, 30);
g.fillRect(30, ycur, 15, 100);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Pong");
frame.pack();
frame.setSize(1000, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
MyFirst game = new MyFirst();
frame.add(game);
while (true) {
game.pallet(e);
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
public void pallet(MouseEvent e) {
ycur=e.getY();
}
}
Problems with your code:
As already mentioned, you're fighting against Swing's event-driven architecture. Instead of a while true loop, use listeners, including a MouseMotionListener ot track the changes in the mouse location, and an ActionListener tied to a Swing Timer to move the ball.
Avoid using Thread.sleep(...) in Swing GUI's except with great care as this can put the entire application to sleep.
Avoid putting too much logic within the main method. This method should be short, should create the key objects, connect them, set the program in motion and that's it.
Paint with the paintComponent method, not the paint method. It results in smoother animation with its double buffering.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveBallTest extends JPanel{
private static final int PREF_W = 1000;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 12;
private static final int SPRITE_WIDTH = 30;
private static final Color OVAL_SPRITE_COLOR = Color.RED;
private static final Color RECT_SPRITE_COLOR = Color.BLUE;
private static final int DELTAY_Y = 1;
private boolean goingDown = true;
private Timer timer = new Timer(TIMER_DELAY, this::timerActionPerformed);
private int ovalSpriteY;
private int rectSpriteY;
public MoveBallTest() {
timer.start();
MyMouse myMouse = new MyMouse();
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(OVAL_SPRITE_COLOR);
g.fillOval(SPRITE_WIDTH, ovalSpriteY, SPRITE_WIDTH, SPRITE_WIDTH);
g.setColor(RECT_SPRITE_COLOR);
g.fillRect(SPRITE_WIDTH, rectSpriteY, SPRITE_WIDTH / 2, SPRITE_WIDTH * 3);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void timerActionPerformed(ActionEvent e) {
if (ovalSpriteY <= 0) {
goingDown = true;
} else if (ovalSpriteY >= getHeight() - SPRITE_WIDTH) {
goingDown = false;
}
ovalSpriteY += goingDown ? DELTAY_Y : -DELTAY_Y;
repaint();
}
private class MyMouse extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
rectSpriteY = e.getY();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MoveBallTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MoveBallTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm trying to learn Java and game programming by myself by just playing around with some different things. But now I have come across this problem, when my java app goes fullscreen via GraphicsDevice, the KeyListeners don't work. It's like it doesn't register anything when I press the buttons on my keyboard. When the app isn't fullscreen, everything works as it is supposed to.
I am using Mac.
The code is a bit messy, but it should be somewhat easy to navigate etc.
Game.class
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
// Render Vars
public static final int WIDTH = 1280;
public static final int HEIGHT = 800; //WIDTH / 16 *
public static final int SCALE = 1;
public final static String TITLE = "Test Game - inDev 1.0.0";
public static boolean fullscreen = false;
public static JFrame window = new JFrame(TITLE);
public static Font defaultFont = new Font("Dialog", Font.PLAIN, 12);
public static Color defaultColor = Color.gray;
// Thread Vars
public static boolean running = false;
private static Thread thread;
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
// Mechanic Vars
public static boolean mouseDown;
public static int mouseX;
public static int mouseY;
// Game Vars
public static GameState gameState = new Play();
public static boolean keyPressed;
public static Game game = new Game();
public static void main(String arghs[]) {
game.setSize(new Dimension(WIDTH, HEIGHT));
game.setPreferredSize(new Dimension(WIDTH, HEIGHT));
fullscreen = true;
window.add(game);
window.setUndecorated(true);
window.pack();
window.setLocationRelativeTo(null);
window.setResizable(false);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setVisible(true);
// HERE I GO FULLSCREEN
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(window);
game.addKeyListener(new KeyEventListener());
game.addMouseListener(new MouseEventListener());
game.start();
}
public void run() {
init();
long lastTime = System.nanoTime();
final double numTicks = 100.0;
double ns = 1000000000 / numTicks;
double delta = 0;
int updates = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1) {
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(updates + " Ticks, FPS: " + frames);
updates = 0;
frames = 0;
}
}
stop();
}
private synchronized void start() {
if (running) {
return;
}
running = true;
thread = new Thread(this);
thread.setName("My Game");
thread.start();
}
public synchronized static void stop() {
if (!running) {
return;
}
running = false;
thread = null;
System.exit(1);
}
private void init() {
gameState.init();
}
private void update() {
gameState.update();
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setColor(defaultColor);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
// Draw Content
gameState.render(g);
// Draw to Screen;
g.dispose();
bs.show();
}
public static void setGameState(GameState state) {
gameState = state;
gameState.init();
}
}
KeyEventListener.class
public class KeyEventListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (!Game.keyPressed) {
Game.gameState.keyPressed(e);
}
Game.keyPressed = true;
}
public void keyReleased(KeyEvent e) {
Game.gameState.keyReleased(e);
Game.keyPressed = false;
}
}
MouseEventListener.class (Just for recording the mouse position)
public class MouseEventListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Game.mouseDown = true;
}
public void mouseReleased(MouseEvent e) {
Game.mouseDown = false;
}
public void mouseMoved(MouseEvent e) {
Game.mouseX = e.getX();
Game.mouseY = e.getY();
}
public void mouseDragged(MouseEvent e) {
Game.mouseX = e.getX();
Game.mouseY = e.getY();
}
}
GameState.class
public abstract class GameState {
public abstract void init();
public abstract void update();
public abstract void render(Graphics g);
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
And my Play.class which is the current gameState
public class Play extends GameState {
public static int key;
public void init() {
}
public void update() {
}
public void render(Graphics g) {
g.drawString("Key: " + key, 100, 100);
}
public void keyPressed(KeyEvent e) {
key = e.getKeyCode();
}
public void keyReleased(KeyEvent e) {
}
}
KeyListener will only respond to key events when the component is registered to is focusable and has focus.
After you have set the window to full screen, try adding...
game.requestFocusInWindow();
You may also need to use game.setFocusable(true)
If it wasn't for the fact that you're using a Canvas, I'd suggest using the key bindings API to over all these focus issues
Updated
I added...
window.addWindowFocusListener(new WindowAdapter() {
#Override
public void windowGainedFocus(WindowEvent e) {
System.out.println("gainedFocus");
if (!game.requestFocusInWindow()) {
System.out.println("Could not request focus");
}
}
});
To the window after it was visible but before it was made full screen
Updated
Oh, you're going to love this...
Based on this question: FullScreen Swing Components Fail to Receive Keyboard Input on Java 7 on Mac OS X Mountain Lion
I added setVisible(false) followed by setVisible(true) after setting the window to full screen mode and it seems to have fixed it...
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(window);
window.setVisible(false);
window.setVisible(true);
Verified running on Mac, using Java 7
Hey guys I'm new to Java game programming and I'm working with the Runnable interface right now. For some reason, my run() method never gets called and I'm not sure why. I've tried putting many System.out.println statements in there but they never get printed. Any help would be greatly appreciated!
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 javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable
{
private final int WIDTH = 160;
private final int HEIGHT = WIDTH/12 *9;
private final int RATIO = 3;
private Thread animator;
private volatile boolean running;
private volatile boolean gameOver;
private double FPS = 60D;
private double period = 1000/FPS;
private Image dbImage;
private Graphics dbg;
public GamePanel()
{
setPreferredSize(new Dimension(WIDTH *3, HEIGHT*3));
setBackground(Color.WHITE);
setFocusable(true);
requestFocus();
terminate();
}
public void addNotify()
{
super.addNotify();
startGame();
}
public void startGame()
{
System.out.println("Thread started");
animator = new Thread();
animator.start();
}
public void stopGame()
{
System.out.println("Thread stopped");
running = false;
}
public void run()
{
long beforeTime, timeDiff, sleepTime;
beforeTime = System.currentTimeMillis();
System.out.println(beforeTime);
running = true;
while (running)
{
System.out.println("Running");
gameUpdate();
gameRender();
paintScreen();
timeDiff = System.currentTimeMillis() - beforeTime;
sleepTime = (long) period - timeDiff;
if(sleepTime <= 0)
sleepTime = 5;
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
beforeTime = System.currentTimeMillis();
}
System.exit(0);
}
public void gameRender()
{
if (dbImage == null)
{
dbImage = createImage(WIDTH, HEIGHT);
}
else
dbg = dbImage.getGraphics();
dbg.setColor(Color.WHITE);
dbg.fillRect(0, 0, WIDTH, HEIGHT);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(dbImage, 0, 0, null);
}
public void gameUpdate()
{
}
private void paintScreen()
{
Graphics g;
try
{
g = this.getGraphics();
if (g!= null && dbImage!= null)
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
catch (Exception e)
{
System.out.println("Error: " + e.getMessage());
}
}
public void terminate()
{
addKeyListener (new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_ESCAPE)
{
stopGame();
}
}
});
}
}
import javax.swing.JFrame;
public class GameFrame extends JFrame
{
private final int WIDTH = 160;
private final int HEIGHT = WIDTH/12*9;
private final int RATIO = 3;
public GameFrame()
{
setTitle("User Input Game");
setSize(WIDTH*3,HEIGHT*3);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
GamePanel mainPanel = new GamePanel();
add(mainPanel);
}
}
public class Main
{
public static void main(String[] args)
{
new GameFrame().setVisible(true);
}
}
You need to change your startGame() method:
animator = new Thread(new GamePanel());
You need to pass a Runnable (of which GamePanel is one) into the Thread constructor. The thread then runs the runnable when it starts.
You don't seem to have a main method anywhere. Either in this class or an external class you need a main method that creates an instance of GamePanel and pass it as an argument to a Thread class. Like so:
public class Test
{
public static void main(String[] args)
{
Thread t = new Thread(new GamePanel()).start();
}
}
I've been experimenting with creating a java game but I've hit a roadblock, I can't get java to listen to any of my keys even when I'm just using print statements to test it out. From what I understand I've implemented KeyListener correctly and added the key listener to the Applet but it still isn't working.
My main class:
import java.awt.*;
import javax.swing.*;
public class Container extends JApplet implements Runnable {
private static final long serialVersionUID = 1L;
public static Dimension size = new Dimension(720,560); //Size of Screen
private static final int PIXELSIZE = 2;
public static Dimension pixel = new Dimension(size.width/PIXELSIZE,
size.height/PIXELSIZE); // Dimesions of screen in terms of pixels
public static final String NAME = "Game";
public static boolean isRunning = false;
private Image screen;
public static Level level;
public static MainCharacter p1;
public Container(){
setPreferredSize(size);
addKeyListener(p1);
}
public void start(){
new Tile();
level = new Level();
p1 = new MainCharacter(20,40);
isRunning = true;
new Thread(this).start();
}
public void tick(){
p1.tick();
}
public void render(){
Graphics g = screen.getGraphics();
g.setColor(new Color(130,160,255));
g.fillRect(0, 0, pixel.width, pixel.height);
level.render(g);
p1.render(g);
g = getGraphics();
g.drawImage(screen, 0, 0, size.width, size.height,
0, 0, pixel.width, pixel.height, null);
g.dispose();
}
public void run() {
screen = createVolatileImage(pixel.width,pixel.height);
while(isRunning){
tick();
render();
try{
Thread.sleep(5);
}catch(InterruptedException e){}
}
}
public static void main(String[] args){
Container container = new Container();
JFrame frame = new JFrame();
frame.add(container);
frame.pack();
frame.setTitle(NAME);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
container.start();
}
public static void right(){
p1.right();
}
public static void left(){
p1.left();
}
}
My character class:
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class MainCharacter extends Tall implements KeyListener{
public double fallSpeed = 1.5;
public double moveSpeed = 1.0;
public double xSpeed = 1;
public MainCharacter(int width, int height){
setBounds(Container.pixel.width/2 - width/2,
Container.pixel.height/2 - height/2,
width, height);
}
public void tick(){
if(Container.level.space[(int)(x+width)][(int)(y+height)] &&
Container.level.space[(int)(x)][(int)(y+height)] &&
Container.level.space[(int)(x+width)][(int)(y)] &&
Container.level.space[(int)(x)][(int)(y)])
y += fallingSpeed;
}
public void render(Graphics g){
g.drawImage(Tile.tileset_terrain, (int)x, (int)y,
(int)(x+width),(int)(y+height),
Tile.CHARACTER[0]*Tile.TILE_SIZE,
Tile.CHARACTER[1]*Tile.TILE_SIZE,
Tile.CHARACTER[0]*Tile.TILE_SIZE +(int)width,
Tile.CHARACTER[1]*Tile.TILE_SIZE + (int)height, null);
}
public void right(){
x += xSpeed;
}
public void left(){
x -= xSpeed;
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("hey");
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("hey");
}
#Override
public void keyTyped(KeyEvent e) {
System.out.println("hey");
}
}
It looks like p1 is null when you add it as a KeyListener.
You add it as a KeyListener here:
public Container(){
setPreferredSize(size);
System.out.println(p1); // try this...
addKeyListener(p1);
}
But instantiate it here:
public void start(){
new Tile();
level = new Level();
p1 = new MainCharacter(20,40);
isRunning = true;
new Thread(this).start();
}
KeyListeners are fickle. They require that the component they are registered to are not only focusable, but have keyboard focus.
It's recommend that instead, you should use Key Bindings instead