I am working on moving a shape along a "grid". I seem to have finally figured things out, but I'm having a slight problem; no matter how close i try to get the specific time interval in between each movement, is seems to still go off of the grid. I would like to use the current method I am using, as I understand how thigs are working this way. I know it is getting a random movement "glitch" sometimes, because if I move it back and fourth it should be locked onto the grid no matter what. Here is my code (Sorry for the lack of comments and weird placement of things I am just testing the code):
Main Class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JFrame;
public class WhyOhWhy {
public int x;
public int y;
public static void main(String[] args) {
JFrame f = new JFrame();
InputHandler input = new InputHandler();
f.add(input);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800,600);
input.doStuff();
}
}
InputHandler Class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class InputHandler extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(5, this);
int x = 0, y = 0, velX = 0, velY = 0;
int i = 0, j = 0;
TimeKeeper timeStart;
public void doStuff(){
velX = 0;
velY = 0;
}
public InputHandler() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 32, 32));
for(int i = 0;i <500;i+=32){
g2.drawRect(i, j, 32, 32);
for(int j=0;j<500;j+=32){
g2.drawRect(i, j, 32, 32);
}
}
}
public void actionPerformed(ActionEvent e) {
repaint();
x += velX;
y += velY;
if(TimeKeeper.isFinished() == true){
System.out.println("DONE");
TimeKeeper.resetTimer(false);
velX = 0;
velY = 0;
setEnabled(true);
}
}
public void up() {
//System.out.println("Moving up");
timeStart = new TimeKeeper(185);
velY = -1;
velX = 0;
setEnabled(false);
}
public void down() {
//System.out.println("Moving down");
setEnabled(false);
timeStart = new TimeKeeper(185);
velY = 1;
velX = 0;
}
public void left() {
//System.out.println("Moving left");
setEnabled(false);
timeStart = new TimeKeeper(185);
velY = 0;
velX = -1;
}
public void right() {
//System.out.println("Moving right");
setEnabled(false);
timeStart = new TimeKeeper(185);
velY = 0;
velX = 1;
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_W) {
up();
}
if (code == KeyEvent.VK_S) {
down();
}
if (code == KeyEvent.VK_A) {
left();
}
if (code == KeyEvent.VK_D) {
right();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
velX = 0;
velY = 0;
}
}
TimeKeeper Class:
import java.util.Timer;
import java.util.TimerTask;
public class TimeKeeper {
Timer timer;
public static boolean isDone = false;
public TimeKeeper(int seconds) {
timer = new Timer();
isDone = false;
timer.schedule(new RemindTask(), seconds );
}
class RemindTask extends TimerTask {
public void run() {
//System.out.println("Time's up!");
isDone = true;
timer.cancel(); //Terminate the timer thread
}
}
public static boolean isFinished() {
return isDone;
}
public static void resetTimer(boolean done) {
isDone = done;
}
}
Thank you!
Never mind, figured it out. Needed to use the % operator to see if the number that the shape moved was divisible by 32 each step, in both the x and y direction.
Related
I'm trying to create a square that can move by pressing keys. When I Compiled & Ran the code it wouldn't move. So I began debugging (as well as I'm capable of). The problem seems to be that the run() function isn't being called. Why is this ? My understanding was that when using the interface Runnable, the run method is called automatically. I posted all the code in action.
Why isn't run() being called automatically and how can I change my program so it will call ?
Game.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements Runnable{
private static final int WIDTH = 800, HEIGHT = WIDTH / 12 * 9; //Widescreen
private Thread game_thread;
private boolean running = false;
public int x_speed = 0, y_speed = 0;
public Square square;
public Game(){
game_thread = new Thread("GameThread");
square = new Square(this);
addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == e.VK_A){
x_speed = -1;
}
if(e.getKeyCode() == e.VK_D){
x_speed = 1;
}
if(e.getKeyCode() == e.VK_S){
y_speed = -1;
}
if(e.getKeyCode() == e.VK_W){
y_speed = 1;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
});
}
public void start(){
System.out.println("Started");
game_thread.start();
running = true;
System.out.println(running);
}
public void stop(){
try{
running = false;
game_thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, WIDTH, HEIGHT);
square.render(g2d);
}
public void update(){
square.move();
System.out.println(x_speed + ", " + y_speed);
}
public void run(){
System.out.println("run method started");
while(running){
System.out.println("Running");
//Update screen info
update();
//Re-render
repaint();
try{
game_thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String args[]){
JFrame frame = new JFrame("Moving Thangs");
Game game = new Game();
frame.setSize(game.WIDTH, game.HEIGHT);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(game);
frame.setVisible(true);
game.start();
}
}
Square.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class Square {
public static final int s_WIDTH = 80, s_HEIGHT = s_WIDTH;
public int x, y;
private Game game;
public Square(Game game){
x = 50;
y = 50;
this.game = game;
}
public void move(){
if(x >= 0 && x <= game.getWidth() - s_WIDTH){
x += game.x_speed;
}
if(y >= 0 && y <= game.getHeight() - s_HEIGHT){
y += game.y_speed;
}
}
public void render(Graphics2D g2d){
g2d.setColor(Color.ORANGE);
g2d.fillRect(x, y, s_WIDTH, s_HEIGHT);
}
}
When you create the thread using new Thread("GameThread") you don't pass this as a runnable to the thread. You need to pass it as the first argument in the constructor like new Thread(this, "GameThread") and then everything should work.
I should be able to move the rectangle with the arrow keys but after running the program a few times the rectangle does not move. To make the rectangle move I close Netbeans and reopen it. Then the rectangle is able to move but it stops moving after a couple tries. I want to solve this problem so I can make changes.
package project;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
//KeyListener is use with keyboard
public class main extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5, this); //for animation
int x = 50, y = 50, velX =0, velY = 0;
public main()
{
tm.start(); //starts timer
addKeyListener(this); //this refearing to KeyListener
setFocusable(true); //enable KeyListener
setFocusTraversalKeysEnabled(false); //shift or tab is not use so F
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(x,y,50,50);
}
public void actionPerformed(ActionEvent e)
{
if (x<0)
{
velX = 0;
x = 0;
}
if (x>500)
{
velX = 0;
x = 500;
}
if (y<0)
{
velY = 0;
y=0;
}
if (y>300)
{
velY = 0;
y = 300;
}
x = x + velX;
y = y + velY;
repaint(); // repaint rectangle
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode(); //get key
if (c == KeyEvent.VK_LEFT) // VK_Left is left arrow
{
velX = -3;
velY = 0;
}
if (c == KeyEvent.VK_UP) // VK_UP is up arrow
{
velX = 0;
velY = -3; // means up
}
if (c == KeyEvent.VK_RIGHT)
{
velX = 3;
velY = 0;
}
if (c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 3;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e) //when you stop pressing
{
velX = 0;
velY = 0;
}
public static void main(String[] args)
{
main m = new main();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(600,400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(m);
}
}
I have a very strange problem.
I am making a simple 2d platformer using Java.
The collision detection with the player and a platform, doesn't work.
But the strange thing is, when I print something to the screen to see if the collision if-statement is executed, the collision works o_O
Maybe it's a bit confusing, please see my code.
The Main class(which is good I think):
import javax.swing.*;
public class Main extends JFrame{
private static final long serialVersionUID = 1L;
GameClass gc = new GameClass();
public Main(){
setSize(gc.WIDTH,gc.HEIGHT);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Flying GoatZ!");
add(new GameClass());
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new Main();
}
}
GameClass class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class GameClass extends JPanel implements ActionListener, KeyListener, MouseListener{
//OBJECTS
Text text = new Text();
openImages open_img = new openImages();
Random ran = new Random();
//VARIABLES
static final long serialVersionUID = 1L;
final int WIDTH = 800;
final int HEIGHT = 600;
int goatx = WIDTH/2;
int goaty = 350;
int goatspeed = 0;
int fallspeed = 15;
int maxy = 150;
boolean up = false;
boolean flying = true;
ArrayList<Integer> xes = new ArrayList<Integer>();
ArrayList<Integer> yes = new ArrayList<Integer>();
//FPS SETTER AND KEYLISTENERS
public GameClass(){
Timer time = new Timer(15, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
open_img.openImage();
}
public void update(){
Collision();
goatx += goatspeed;
if(up){
if(goaty > maxy){
goaty -= 5;
}else{
up = false;
}
}else
if(goaty < 350)
goaty += fallspeed;
}
public void print(String msg){
System.out.println(msg);
}
public void platformDrawing(Graphics g,int x,int y,int x1,int y1, int x2, int y2){
g.setColor(Color.RED);
g.drawImage(open_img.block,x, y, null);
g.drawImage(open_img.block,x1, y1, null);
g.drawImage(open_img.block,x2, y2, null);
xes.addAll(Arrays.asList(x,x1,x2));
yes.addAll(Arrays.asList(y,y1,y2));
}
//HERE IS THE COLLISION METHOD(I NEED THE PLAYER TO STAND STILL WHEN IT IS ON THE PLATFORM.
public void Collision(){
for(int x : xes){
for(int y : yes){
if( ( (goatx > x-20) && (goatx < (x + 150)) ) && ( (goaty+open_img.goat.getHeight(null)) <= y ) ){
//print("TEST");
fallspeed = 0;
}else{
fallspeed = 10;
}
}
}
}
//ALL TEH DRAWING
public void paintComponent(Graphics g){
//MAP
g.setColor(Color.CYAN);
g.fillRect(0,0,WIDTH,HEIGHT);
g.setColor(Color.ORANGE);
g.fillRect(0, HEIGHT-100, WIDTH, 100);
g.setColor(Color.GREEN);
g.fillRect(0, HEIGHT-125, WIDTH, 25);
//PLAYER & PLATFORMS
platformDrawing(g,50,350,300,350,600,350);
g.drawImage(open_img.goat, goatx, goaty, null);
g.dispose();
}
//THIS IS EXECUTED EVERYTIME
public void actionPerformed(ActionEvent e){
update();
repaint();
}
//KEY DETECTION
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT){
goatspeed = -5;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
goatspeed = 5;
}
if(e.getKeyCode() == KeyEvent.VK_SPACE){
if(flying){
flying = false;
up = true;
}
}
}
public void keyReleased(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT){
goatspeed = 0;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
goatspeed = 0;
}
if(e.getKeyCode() == KeyEvent.VK_SPACE){
flying = true;
}
}
//SOME STUFF THAT YOU HAVE TO IGNORE LEL
public void keyTyped(KeyEvent e){}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
}
I don't understand why a print statement can make the difference...
Any help is appreaciated, thanks!
Oh, and sorry for bad English or unclear question.
I have the following code to show you:
public class Test extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5, this);
int x = 0, y = 0, velX = 0, velY = 0;
public Test()
{
tm.start(); //starts the timer
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paint(Graphics g)
{
super.paint(g);
ImageIcon s = new ImageIcon("C:\\Users\\Owner\\Pictures\\Stick.jpg");
s.paintIcon(this,g,x,y);
}
public void actionPerformed(ActionEvent e)
{
if (x < 0)
{
velX = 0;
x = 0;
}
if (x > 630)
{
velX = 0;
x = 630;
}
if(y < 0)
{
velY = 0;
y = 0;
}
if(y > 430)
{
velY = 0;
y = 430;
}
x = x + velX;
y = y + velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if (c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if(c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if(c == KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e)
{
velX = 0;
velY = 0;
}
public static void main(String[] args)
{
Test t = new Test();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(700, 600);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
jf.setVisible(true);
}
My problem is I whenever the user holds the right arrow on the keyboard it changes an image, when the user lets go it goes back the the default image. Please tell me how to do that. I think it is a series of if statements in the Graphics class then calling them to the key input but I'm not quite sure. I am also using Eclipse. Thank You.
Override paintComponent instead of paint. See Performing Custom Painting and Painting in AWT and Swing for more details
Use the key bindings API instead of KeyListener, it will cause you less issues. See How to Use Key Bindings for more details
Essentially, you could just have a Image as a class instance field, which was painted by the paintComponent method. When the key was pressed, you would change the image to the "move image" and when it was released, change it back to the "default image"
Updated with example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Mover {
public enum Direction {
LEFT, RIGHT, NONE;
}
public void setDirection(Direction direction);
public Direction getDirection();
}
public class TestPane extends JPanel implements Mover {
private BufferedImage left;
private BufferedImage right;
private BufferedImage stand;
private BufferedImage current;
private Direction direction = Direction.NONE;
private int xPos;
private int yPos;
public TestPane() {
try {
left = ImageIO.read(getClass().getResource("/Left.png"));
right = ImageIO.read(getClass().getResource("/Right.png"));
stand = ImageIO.read(getClass().getResource("/Stand.png"));
current = stand;
xPos = 100 - (current.getWidth() / 2);
yPos = 100 - (current.getHeight() / 2);
} catch (IOException exp) {
exp.printStackTrace();
}
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(this, Direction.LEFT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), new MoveAction(this, Direction.NONE));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(this, Direction.RIGHT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), new MoveAction(this, Direction.NONE));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updatePosition();
repaint();
}
});
timer.start();
}
protected void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(condition);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
public Direction getDirection() {
return direction;
}
#Override
public void setDirection(Direction direction) {
this.direction = direction;
}
protected void updatePosition() {
switch (getDirection()) {
case LEFT:
current = left;
xPos -= 1;
break;
case RIGHT:
current = right;
xPos += 1;
break;
case NONE:
current = stand;
break;
}
if (xPos < 0) {
xPos = 0;
current = stand;
} else if (xPos + current.getWidth() > getWidth()) {
current = stand;
xPos = getWidth() - current.getWidth();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(current, xPos, yPos, this);
g2d.dispose();
}
}
public class MoveAction extends AbstractAction {
private Mover mover;
private Mover.Direction direction;
public MoveAction(Mover mover, Mover.Direction direction) {
this.mover = mover;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
mover.setDirection(direction);
}
}
}
can you see the problem. the thread runs fine but the brick does not want to respond to the key listener. I try to test if the keylistener was at last getting an event but it does not even do the system.out.println
import java.awt.*;//imports
import java.util.*;
import java.applet.*;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class Start extends Applet implements Runnable, KeyListener// where i put the keylistener in
{
DrawBackground dbg = new DrawBackground();
Brick brick = new Brick();
Thread gameLoop;
public void init() {
addKeyListener(this);// i add the key listener
}
public void start() {
Thread gameLoop = new Thread(this);
gameLoop.start();
}
public void run() {
while (true) {
brick.update(1);
repaint();
try {
Thread.sleep(17);
}
catch (InterruptedException e) {
}
}
}
public void stop() {
}
public void paint(Graphics g)// with out any paint it works if im changing
// somthing like a lable
{
dbg.paint(g, this);
brick.paint(g, this);
}
public void keyPressed(KeyEvent e)// test to see if it works
{
System.out.println("why");
if (e.getKeyCode() == 37) {
brick.left();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
this is the Brick class the thing i'm trying to move
import java.awt.*;
import java.util.*;
import java.applet.*;
public class Brick {
public int dy = 40;
public int yStart = -20;
public int time = 0;
public int dx = 0;
public int xStart = 0;
public int start = 1;
public void paint(Graphics g, Start sp) {
Dimension screenSize = sp.getSize();
int sheight = screenSize.height;
int swidth = screenSize.width;
if (start == 1) {
xStart = swidth - (int) (swidth / 2.5);
start = 0;
}
int bWidth = swidth / 15;
int bHeight = swidth / 15;
int time = 0;
g.setColor(Color.red);
g.fillRect(xStart, yStart, bWidth, bHeight);
}
public void update(int x) {
if (time == 60) {
time = 0;
yStart += dy;
}
else {
time += x;
}
}
public void left() {
xStart -= dx;
}
}
It doesn't look like you have set the keyboard focus. See this question.
I've always used setFocusable(true) after adding the keyListener and its worked for me, but the answer to that question has a better solution.