I have started making slime volleyball. I have run into this problem where the image for the slime character flickers insanely. the image is disappeared just about the same amount of time that it is visible.
I tried removing the super.paint(g); in the paint method and that fixed the problem of flickering, but it created a new problem that wouldn't remove the image from previous locations.
Source Code:
package slimevolleyball.main;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
public static int x = 275;
public static int y = 300;
public static boolean right = false;
public static boolean left = false;
public static boolean jump = false;
public static int startjump = 0;
public static int low = 300;
public static double gravity = 0;
public static double time = 0;
public static int startVelocity = 0;
public static double velocity = 0;
public static BufferedImage slime1;
public static BufferedImage slime2;
public static BufferedImage background;
static Rectangle FrameSize;
static JFrame frame = new JFrame();
public Main() {
addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP:
break;
case KeyEvent.VK_DOWN:
break;
case KeyEvent.VK_LEFT:
left = false;
break;
case KeyEvent.VK_RIGHT:
right = false;
}
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP:
if (jump == false) {
jump = true;
startjump = 1;
}
break;
case KeyEvent.VK_DOWN:
break;
case KeyEvent.VK_LEFT:
left = true;
right = false;
break;
case KeyEvent.VK_RIGHT:
right = true;
left = false;
break;
}
}
});
setFocusable(true);
setTitle("Slime VolleyBall");
setSize(600, 400);
setResizable(true);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(slime1, x, y, null);
}
public static void main(String[] args) throws InterruptedException, IOException {
Main game = new Main();
slime1 = ImageIO.read(new File("red.png"));
while (true) {
MoveSlime1();
Update();
game.repaint();
Thread.sleep(2);
}
}
private static void Update() {
FrameSize = frame.getBounds();
}
private static void MoveSlime1() {
if (right == true && x <= FrameSize.getWidth() / 2) {
x += 1;
} else if (left == true && x >= 0) {
x -= 1;
}
if (jump == true) {
if (startjump == 1) {
low = 300;
gravity = -9.8;
time = 0;
startVelocity = 3;
velocity = 0;
startjump = 0;
} else {
velocity = startVelocity + (gravity * time);
y -= velocity;
time += 0.005;
if (time > 0.01 && y >= low) {
jump = false;
}
}
}
}
}
JFrame is not double buffered, hence the flicker, which is just one of a list of reasons why you should not be extending from JFrame and overriding it's paint method.
Instead, move all your logic over to a class which extends JPanel and then override it's paintComponent method, this way, you'll get double buffering for free.
Also, you should avoid using KeyListeners and favor the Key Bindings API which solves the focus related issues of KeyListener
Also, static is not your friend, you should learn to live without it
Related
I am trying to create a snake clone just as a practice. ive drawn the snake and added the movement patterns but the snake eats on it self when I press any key to move. but its not moving. the array retracts the reactacles on the starting point and does nothing.
here is my snake class I have removed my comments as they where more than the code and the posting system was not allowing me to post
Edit
If you need anything from the other classes please let me know. but I think my error is somewhere in here
EDIT 2
Added the entire code, you can just copy paste in inside a new project and you will reproduce my error.
public class Snake {
List<Point> sPoints;
int xDir,yDir;
boolean isMoving,addTail;
final int sSize = 20, startX = 150 , startY = 150;
public Snake(){
sPoints = new ArrayList<Point>();
xDir = 0;
yDir = 0;
isMoving = false;
addTail = false;
sPoints.add(new Point(startX,startY));
for(int i=1; i<sSize; i++) {
sPoints.add(new Point(startX - i * 4,startY));
}
}
public void draw(Graphics g){
g.setColor(Color.white);
for(Point p : sPoints) {
g.fillRect(p.getX(),p.getY(),4,4);
}
}
public void move(){
if (isMoving) {
Point temp = sPoints.get(0);
Point last = sPoints.get(sPoints.size() - 1);
Point newstart = new Point(temp.getX() + xDir * 4, temp.getY() + yDir * 4);
for (int i = sPoints.size() - 1; i >= 1; i--) {
sPoints.set(i, sPoints.get(i - 1));
}
sPoints.set(0, newstart);
}
}
public int getxDir() {
return xDir;
}
public void setxDir(int x) {
this.xDir = xDir;
}
public int getyDir() {
return yDir;
}
public void setyDir(int y) {
this.yDir = yDir;
}
public int getX(){
return sPoints.get(0).getX();
}
public int getY(){
return sPoints.get(0).getY();
}
public boolean isMoving() {
return isMoving;
}
public void setIsMoving(boolean b) {
isMoving = b;
}
}
The following is the point class. just some getters setters for the points ,for those i used the IntelliJ to auto generate them.. (again i removed comments )
public class Point {
private int x,y;
public Point() {
x = 0;
y = 0;
}
public Point(int x, int y) {
this.x =x;
this.y =y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
and finally my main class called game.
in here what I do is create my applet give it background color. create my threat for the runnable. and also add the movement patterns for up/right/down/left...
and use several classes to update my drawing patterns so it can simulate movement by updating each of state of my rect list.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Game extends Applet implements Runnable, KeyListener {
//setting up double buffering.
Graphics graphics;
Image img;
Thread thread;
Snake snake;
public void init() {
//setting the size of our Applet
this.resize(400,400);
//we gonna create the image just the same size as our applet.
img = createImage(400,400);
//this represents our offscreen image that we will draw
graphics = img.getGraphics();
this.addKeyListener(this);
snake = new Snake();
thread = new Thread(this);
thread.start();
}
public void paint(Graphics g) {
//Setting the background of our applet to black
graphics.setColor(Color.black);
//Fill rectangle 0 , 0 (starts from) for top left corner and then 400,400 to fill our entire background to black
graphics.fillRect(0,0,400,400);
snake.draw(graphics);
//painting the entire image
g.drawImage(img,0,0,null);
}
//Update will call on Paint(g)
public void update(Graphics g){
paint(g);
}
//Repaint will call on Paint(g)
public void repaint(Graphics g){
paint(g);
}
public void run() {
//infinite loop
for(;;) {
snake.move();
//drawing snake
this.repaint();
//Creating a time delay
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void keyTyped(KeyEvent keyEvent) {
}
public void keyPressed(KeyEvent keyEvent) {
if(!snake.isMoving()){ //this will allow the snake to start moving, but will disable LEFT for just the 1st move
if(keyEvent.getKeyCode() == KeyEvent.VK_UP || keyEvent.getKeyCode() == KeyEvent.VK_RIGHT ||
keyEvent.getKeyCode() == KeyEvent.VK_DOWN ) {
snake.setIsMoving(true);
}
}
//setting up Key mapping so when the user presses UP,RIGHT,DOWN,LEFT. the Snake will move accordingly
if(keyEvent.getKeyCode() == KeyEvent.VK_UP) {
if (snake.getyDir() != 1) {
snake.setyDir(-1);
snake.setxDir(0);
}
}
if(keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
if (snake.getxDir() != -1) {
snake.setxDir(1);
snake.setyDir(0);
}
}
if(keyEvent.getKeyCode() == KeyEvent.VK_DOWN) {
if (snake.getyDir() != -1) {
snake.setyDir(1);
snake.setxDir(0);
}
}
if(keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
if (snake.getxDir() != 1) {
snake.setxDir(-1);
snake.setyDir(0);
}
}
}
public void keyReleased(KeyEvent keyEvent) {
}
}
Here is some opinion I have reading your code.
The reason your snake won't move is because your snake.setyDir() and
snake.setxDir() didn't take the input to overwrite xDir and yDir. They are assigning to itself.
There is a Point2D class ready for you in JDK
When moving the snake, you just need to remove the tail and add one
more block before the head. You can keep the body tight (according
to my common knowledge to snake).
Consider a L shape snake on the left, the bottom end is the head and it is currently heading right. To move the snake, remove the tail (green block) and add one more to the head according to its direction (red block). It final state become the snake on the right. LinkedList suit the needs.
If using two int (xDir and yDir) to control the snake direction
is confusing, you can help your self by creating a enum. Those -1,
0, 1 with x and y may confuse you.
Declare constant instead of magic number. e.g. the width of block 4,
image size 400
Is Snake.addTail unnecessary?
Attribute should has accessibility modifier
End result:
Game.java
import java.applet.Applet;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;
public class Game extends Applet implements Runnable, KeyListener {
private final int GAMEBOARD_WIDTH = 400;
// setting up double buffering.
private Graphics graphics;
private Image img;
private Thread thread;
private Snake snake;
public void init() {
// setting the size of our Applet
this.resize(GAMEBOARD_WIDTH, GAMEBOARD_WIDTH);
// we gonna create the image just the same size as our applet.
img = createImage(GAMEBOARD_WIDTH, GAMEBOARD_WIDTH);
// this represents our offscreen image that we will draw
graphics = img.getGraphics();
this.addKeyListener(this);
snake = new Snake();
thread = new Thread(this);
thread.start();
}
public void paint(Graphics g) {
// Setting the background of our applet to black
graphics.setColor(Color.BLACK);
// Fill rectangle 0 , 0 (starts from) for top left corner and then 400,400 to
// fill our entire background to black
graphics.fillRect(0, 0, GAMEBOARD_WIDTH, GAMEBOARD_WIDTH);
snake.draw(graphics);
// painting the entire image
g.drawImage(img, 0, 0, null);
}
// Update will call on Paint(g)
public void update(Graphics g) {
paint(g);
}
// Repaint will call on Paint(g)
public void repaint(Graphics g) {
paint(g);
}
public void run() {
// infinite loop
for (;;) {
snake.move();
// drawing snake
this.repaint();
// Creating a time delay
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void keyTyped(KeyEvent keyEvent) {
}
public void keyPressed(KeyEvent keyEvent) {
int keyCode = keyEvent.getKeyCode();
if (!snake.isMoving()) {
// this will allow the snake to start moving, but will disable LEFT for just the
// 1st move
if (matchKey(keyCode, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN)) {
snake.setIsMoving(true);
}
}
// setting up Key mapping so when the user presses UP,RIGHT,DOWN,LEFT. the Snake
// will move accordingly
if (matchKey(keyCode, KeyEvent.VK_UP)) {
snake.setDirection(Direction.UP);
}
if (matchKey(keyCode, KeyEvent.VK_RIGHT)) {
snake.setDirection(Direction.RIGHT);
}
if (matchKey(keyCode, KeyEvent.VK_DOWN)) {
snake.setDirection(Direction.DOWN);
}
if (matchKey(keyCode, KeyEvent.VK_LEFT)) {
snake.setDirection(Direction.LEFT);
}
}
// return true if targetKey contains the provided keyCode
private boolean matchKey(int keyCode, int... targetKey) {
return Arrays.stream(targetKey).anyMatch(i -> i == keyCode);
}
public void keyReleased(KeyEvent keyEvent) {
}
}
Snake.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
import java.util.LinkedList;
public class Snake {
private final int sSize = 20, startX = 150, startY = 150;
private final int BLOCK_WIDTH = 4;
private LinkedList<Point2D.Float> sPoints;
private boolean isMoving;
private Direction direction;
public Snake() {
sPoints = new LinkedList<Point2D.Float>();
isMoving = false;
sPoints.add(new Point2D.Float(startX, startY));
for (int i = 1; i < sSize; i++) {
sPoints.add(new Point2D.Float(startX - i * BLOCK_WIDTH, startY));
}
}
public void draw(Graphics g) {
g.setColor(Color.white);
for (Point2D p : sPoints) {
g.fillRect((int) p.getX(), (int) p.getY(), BLOCK_WIDTH, BLOCK_WIDTH);
}
}
public void move() {
if (isMoving) {
sPoints.removeLast();
steer(sPoints.getFirst());
}
}
private void steer(Point2D head) {
Point2D.Float newHead = new Point2D.Float();
switch (this.getDirection()) {
case UP:
newHead.setLocation(head.getX(), head.getY() - BLOCK_WIDTH);
break;
case DOWN:
newHead.setLocation(head.getX(), head.getY() + BLOCK_WIDTH);
break;
case LEFT:
newHead.setLocation(head.getX() - BLOCK_WIDTH, head.getY());
break;
case RIGHT:
newHead.setLocation(head.getX() + BLOCK_WIDTH, head.getY());
break;
}
this.sPoints.addFirst(newHead);
}
public int getX() {
return (int) sPoints.get(0).getX();
}
public int getY() {
return (int) sPoints.get(0).getY();
}
public boolean isMoving() {
return isMoving;
}
public void setIsMoving(boolean b) {
isMoving = b;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction d) {
if (this.getDirection() == null) {
this.direction = d;
} else if (!this.getDirection().isOpposite(d)) {
this.direction = d;
}
}
}
Direction.java
public enum Direction {
UP(-1), DOWN(1), LEFT(-2), RIGHT(2);
int vector;
Direction(int i) {
this.vector = i;
}
public boolean isOpposite(Direction d) {
return this.vector + d.vector == 0;
}
}
Snack.java
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Snake extends JFrame {
public Snake() {
initUI();
}
private void initUI() {
add(new Board());
setResizable(false);
pack();
setTitle("Snake");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame ex = new Snake();
ex.setVisible(true);
});
}
}
Board.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Board extends JPanel implements ActionListener {
private final int B_WIDTH = 300;
private final int B_HEIGHT = 300;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 900;
private final int RAND_POS = 29;
private final int DELAY = 140;
private final int x\[\] = new int\[ALL_DOTS\];
private final int y\[\] = new int\[ALL_DOTS\];
private int dots;
private int apple_x;
private int apple_y;
private boolean leftDirection = false;
private boolean rightDirection = true;
private boolean upDirection = false;
private boolean downDirection = false;
private boolean inGame = true;
private Timer timer;
private Image ball;
private Image apple;
private Image head;
public Board() {
initBoard();
}
private void initBoard() {
addKeyListener(new TAdapter());
setBackground(Color.black);
setFocusable(true);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
loadImages();
initGame();
}
private void loadImages() {
ImageIcon iid = new ImageIcon("src/resources/dot.png");
ball = iid.getImage();
ImageIcon iia = new ImageIcon("src/resources/apple.png");
apple = iia.getImage();
ImageIcon iih = new ImageIcon("src/resources/head.png");
head = iih.getImage();
}
private void initGame() {
dots = 3;
for (int z = 0; z < dots; z++) {
x\[z\] = 50 - z * 10;
y\[z\] = 50;
}
locateApple();
timer = new Timer(DELAY, this);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
g.drawImage(apple, apple_x, apple_y, this);
for (int z = 0; z < dots; z++) {
if (z == 0) {
g.drawImage(head, x\[z\], y\[z\], this);
} else {
g.drawImage(ball, x\[z\], y\[z\], this);
}
}
Toolkit.getDefaultToolkit().sync();
} else {
gameOver(g);
}
}
private void gameOver(Graphics g) {
String msg = "Game Over";
Font small = new Font("Helvetica", Font.BOLD, 14);
FontMetrics metr = getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (B_WIDTH - metr.stringWidth(msg)) / 2, B_HEIGHT / 2);
}
private void checkApple() {
if ((x\[0\] == apple_x) && (y\[0\] == apple_y)) {
dots++;
locateApple();
}
}
private void move() {
for (int z = dots; z > 0; z--) {
x\[z\] = x\[(z - 1)\];
y\[z\] = y\[(z - 1)\];
}
if (leftDirection) {
x\[0\] -= DOT_SIZE;
}
if (rightDirection) {
x\[0\] += DOT_SIZE;
}
if (upDirection) {
y\[0\] -= DOT_SIZE;
}
if (downDirection) {
y\[0\] += DOT_SIZE;
}
}
private void checkCollision() {
for (int z = dots; z > 0; z--) {
if ((z > 4) && (x\[0\] == x\[z\]) && (y\[0\] == y\[z\])) {
inGame = false;
}
}
if (y\[0\] >= B_HEIGHT) {
inGame = false;
}
if (y\[0\] < 0) {
inGame = false;
}
if (x\[0\] >= B_WIDTH) {
inGame = false;
}
if (x\[0\] < 0) {
inGame = false;
}
if (!inGame) {
timer.stop();
}
}
private void locateApple() {
int r = (int) (Math.random() * RAND_POS);
apple_x = ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
apple_y = ((r * DOT_SIZE));
}
#Override
public void actionPerformed(ActionEvent e) {
if (inGame) {
checkApple();
checkCollision();
move();
}
repaint();
}
private class TAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
}
}
}
I am making a snake game, and I want my snake to be moving continuously once a key is pressed. So, I press the down key, and it keeps moving even if the key is released. Right now, it just moves while the key is being held down.
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
mySegment[0].moveSouth();
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_UP) {
mySegment[0].moveNorth();
repaint();
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT){
mySegment[0].moveWest();
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_RIGHT){
mySegment[0].moveEast();
repaint();
}
for (int a = 0; a < 10; a++) {
if (myFruit[a].distance (mySegment[0].getX(), mySegment[0].getY())
<= 20) {
myFruit[a].hide();
}
}
The "mySegment [0]" is the snake, and the "moveSouth" or whatever direction just moves it 5 pixels in that directin
Use a "game loop" to drive the animation. Since this looks to be possibly a Swing or AWT GUI, then your best bet is to use a Swing Timer -- please check out the tutorial. The gist is that within the Timer's ActionListener you increment the position of the snake, changing its direction depending on the state of your key press.
I would use an enum to indicate Direction {UP, DOWN, LEFT, RIGHT}:
public enum Direction {
UP,
DOWN,
LEFT,
RIGHT
}
AND then a Map<Direction, Boolean> to indicate which direction to head:
private Map<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
Elsewhere you would initialize the Map to hold false in all values:
// initialize the map to all false
for (Direction dir : Direction.values()) {
dirMap.put(dir, false);
}
Then change the state of the items in the Map within your code for listening to key presses and releases -- call map.put(Direction.UP, true) for instance when the up key is pressed, and likewise call map.put(Direction.UP, false) when it has been released, same for the other keys. Note that if yours is a Swing application, I'd use Key Bindings and not a KeyListener to do this. In the listener, I'd then call repaint() on the GUI.
Within the Swing Timer, iterate through the Map, setting the direction based on the state of the Map.
class fields:
private int spriteX = 0; // location of sprite
private int spriteY = 0;
private int directionX = 0; // direction sprite is heading
private int directionY = 0;
Within the ActionListener
// within the Swing Timer's ActionListener
if (dirMap.get(Direction.UP)) {
directionY -= 1;
}
if (dirMap.get(Direction.DOWN)) {
directionY += 1;
}
if (dirMap.get(Direction.RIGHT)) {
directionX += 1;
}
if (dirMap.get(Direction.LEFT)) {
directionY -= 1;
}
// here multiply directionX and directionY by some scale factor and use to place new snake head
// then call repaint();
For example (not a snake but a ball -- I'll leave the Snake to you)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.EnumMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.*;
#SuppressWarnings("serial")
public class DirTest extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 40;
private static final Color SPRITE_COLOR = Color.RED;
private static final int SPRITE_W = 20;
private static final Color BG = Color.BLACK;
public static final int SCALE = 1;
private Map<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
private int spriteX = 0;
private int spriteY = 0;
private int directionX = 0;
private int directionY = 0;
private Timer gameLoopTimer = new Timer(TIMER_DELAY, new TimerListener());
public DirTest() {
setKeyBindings();
setBackground(BG);
// initialize map to all 0;
for (Direction dir : Direction.values()) {
dirMap.put(dir, false);
}
gameLoopTimer.start();
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW; // bind to keys if component in active window
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
setKeyBinding(inputMap, actionMap, KeyEvent.VK_UP, Direction.UP);
setKeyBinding(inputMap, actionMap, KeyEvent.VK_DOWN, Direction.DOWN);
setKeyBinding(inputMap, actionMap, KeyEvent.VK_LEFT, Direction.LEFT);
setKeyBinding(inputMap, actionMap, KeyEvent.VK_RIGHT, Direction.RIGHT);
}
private void setKeyBinding(InputMap inputMap, ActionMap actionMap, int keyCode, Direction dir) {
KeyStroke press = KeyStroke.getKeyStroke(keyCode, 0, false);
KeyStroke released = KeyStroke.getKeyStroke(keyCode, 0, true);
Action pressAction = new PressedAction(dir, true);
Action releasedAction = new PressedAction(dir, false);
inputMap.put(press, press.toString());
inputMap.put(released, released.toString());
actionMap.put(press.toString(), pressAction);
actionMap.put(released.toString(), releasedAction);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(SPRITE_COLOR);
g2.fillOval(spriteX, spriteY, SPRITE_W, SPRITE_W);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class PressedAction extends AbstractAction {
private boolean pressed;
private Direction dir;
public PressedAction(Direction dir, boolean pressed) {
this.dir = dir;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
dirMap.put(dir, pressed);
}
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
for (Entry<Direction, Boolean> entry : dirMap.entrySet()) {
if (entry.getValue()) {
directionX += entry.getKey().getX();
directionY += entry.getKey().getY();
}
}
spriteX += SCALE * directionX;
spriteY += SCALE * directionY;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DirTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DirTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
enum Direction {
UP(0, -1),
DOWN(0, 1),
LEFT(-1, 0),
RIGHT(1, 0);
private int x;
private int y;
private Direction(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
If you want to keep the snake moving you need some kind of game-loop (as mentioned before). The easiest way is having a single field containing the current direction, and set it based on the input. So here are a few methods/classes you could use to set the correct direction/position
The Direction Enum
public enum Direction
{
NORTH, EAST, SOUTH, WEST;
public Direction oposite()
{
switch(this)
{
case NORTH: return SOUTH;
case SOUTH: return NORTH;
case EAST: return WEST;
case WEST: return EAST;
}
}
}
The method to set the current direction. (This assumes there is a field named 'currentDirection' which contains an enum (Direction) representing the current direction)
public void setDirection(Direction newDirection)
{
if(currentDirection != newDirection.oposite())
currentDirection = newDirection;
}
This is somewhere in your game loop (either an timer, or a while loop including a 'sleep' call to prevent CPU hugging)
switch(currentDirection)
{
case NORTH: mySegment[0].moveNorth(); break;
case EAST: mySegment[0].moveEast(); break;
case SOUTH: mySegment[0].moveSouth(); break;
case WEST: mySegment[0].moveWest(); break;
}
repaint();
And of course instead of calling 'mySegment[0].moveNorth();' or someting equalivant in the actionHandlers for the keyEvents, you should only call 'setDirection();' to make the snake move.
I hope this helped you out.
So I am trying to make a pinball game made as a applet load into a JFrame. The applet loads into it no problem but when i run it flickers and glitch out. Thanks in advance!
Jframe class:
import javax.swing.*;
import java.awt.*;
import java.applet.*;
public class PinBallGUI extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Pinball");
frame.setVisible(true);
frame.setSize(600,700);
int height = 700;
int width = 600;
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PinBallGame temp = new PinBallGame();
frame.add(temp);
temp.init(width,height);
temp.start();
temp.run();
}
}
Applet class:
import java.awt.*;
import javax.swing.*;
import java.applet.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class PinBallGame extends Applet implements Runnable
{
Thread runner;
private Image Buffer;
private Graphics gBuffer;
int width,height;
PinBallBall B1;
PinBallPaddle P1,P2;
PinBallRectangle R1,R2,R3,R4;
PinBallRectangle[] rArray;
boolean leftKey;
boolean rightKey;
boolean downKey;
boolean spaceKey;
int points;
Random gen = new Random();
public void init(int W,int H)
{
width=W;
height=H;
Buffer=createImage(width,height);
gBuffer=Buffer.getGraphics();
B1 = new PinBallBall(-1,width-57,645);
P1 = new PinBallPaddle(180,625,255,640);
P2 = new PinBallPaddle(300,640,375,625);
R1 = new PinBallRectangle(1,width-35,60,15,600);
R2 = new PinBallRectangle(1,width-80,60,15,600);
R3 = new PinBallRectangle(1,0,625,180,40);
R4 = new PinBallRectangle(1,375,625,140,40);
rArray = new PinBallRectangle[5];
for(int i=0; i<rArray.length; i++)
{
rArray[i] = new PinBallRectangle(-1,gen.nextInt(450),gen.nextInt(450),gen.nextInt(60),gen.nextInt(60));
}
int count = 0;
addKeyListener(new MyKeyListener());
points = 0;
}
private class MyKeyListener extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_LEFT:
leftKey = true;
break;
case KeyEvent.VK_RIGHT:
rightKey = true;
break;
case KeyEvent.VK_SPACE:
spaceKey = true;
break;
case KeyEvent.VK_DOWN:
downKey = true;
break;
}
}
public void keyReleased(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_LEFT:
leftKey = false;
break;
case KeyEvent.VK_RIGHT:
rightKey = false;
break;
case KeyEvent.VK_SPACE:
spaceKey = false;
break;
case KeyEvent.VK_DOWN:
downKey = false;
break;
}
}
}
public void start()
{
if (runner == null)
{
runner = new Thread (this);
runner.start();
}
}
public void stop()
{
runner = null;
}
public void run()
{
while(true)
{
update(gBuffer);
if(leftKey){P1.moveLeftPaddle();}
if(rightKey){P2.moveRightPaddle();}
if(downKey){B1.launchBall(width,height);}
repaint();
try {runner.sleep(25);}
catch (Exception e) { }
repaint();
gBuffer.setColor(Color.black);
gBuffer.fillRect(0,0,width,height);
if((B1.getX() != width-57)||(B1.getY() != 645))
{
B1.movePinBallBall(width,height);
B1.update();
}
R1.ballCollision(B1);
repaint();
R2.ballCollision(B1);
repaint();
R3.ballCollision(B1);
repaint();
R4.ballCollision(B1);
repaint();
P1.ballCollision(B1);
repaint();
P2.ballCollision(B1);
repaint();
for(int i=0; i<rArray.length; i++)
{
rArray[i].ballCollision(B1);
repaint();
}
for(int i=0; i<rArray.length; i++)
{
rArray[i].paint(gBuffer);
}
update(gBuffer);
B1.paint(gBuffer);
R1.paint(gBuffer);
R2.paint(gBuffer);
R3.paint(gBuffer);
R4.paint(gBuffer);
P1.paint(gBuffer);
P2.paint(gBuffer);
repaint();
update(gBuffer);
}//while(true)
} //run
public void update(Graphics g)
{
paint(g);
}
public void paint(Graphics g)
{
g.drawImage(Buffer,0,0, this);
}
}
I also have 3 other classes that are just for objects (ball, rectangle, paddle).
Thanks again in advance!
You're going to want to either use JFrame and JPanel or Frame and Canvas instead of using a JFrame and an Applet. You can definitely mix and match components, but you'll probably encounter less bugs if you don't.
I generally find flickering to happen when you aren't using double buffering. Fro a JPanel you'll want to enable double buffering and for a Canvas there is a way to implement triple buffering if you really need to, but stick with a JPanel for most cases.
I have a project due in a couple days, and my code in Eclipse shows no errors, and no warnings, how ever the game(JFrame) wont show up. I believe the error has to do with the way I've done the movement
this.addKeyListener(movement);
Any ideas are welcome!
Main.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Main extends JFrame implements Runnable {
private Movement movement = new Movement();
public int width = 800;
public int height = 600;
public int fps = 1000;
public int score;
public int charX;
public int charY;
public int charUp;
public int charDown;
public int charLeft;
public int charRight;
public int movementSpeed = 5;
public int movementFrame = 0;
public int movementDiagonal = 10;
public boolean bCharUp = false;
public boolean bCharDown = false;
public boolean bCharLeft = false;
public boolean bCharRight = false;
public Color cytoplasm = new Color(50,130,255);
public Image character;
public Thread game;
//Double Buffer
private Image dbImage;
private Graphics dbg;
public Main() {
//Images
ImageIcon characterImage = new ImageIcon("F:/workplace/com.thecellsells.lysosome/src/com/thecellsells/lysosome/Lysosome.gif");
character = (characterImage.getImage());
//Game Properties
setSize(width, height);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(cytoplasm);
this.addKeyListener(movement);
//Threads
game = new Thread(this);
game.start();
//Other
charY = height/2 - 10;
charX = width/2 - 16;
}
public void paint(Graphics g) {
//Double Buffer
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
g.drawImage(character, charX, charY, this);
repaint();
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Main Main = new Main();
}
#Override
public void run() {
while (true) {
fpsSetter();
}
}
//FPS -- set's how fast game runs
#SuppressWarnings("static-access")
public void fpsSetter() {
try {
game.sleep(fps/fps);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Movement.java
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
#SuppressWarnings("serial")
public class Movement extends Main implements KeyListener {
public int charUp;
public int charDown;
public int charLeft;
public int charRight;
public int movementSpeed = 5;
public int movementFrame = 0;
public int movementDiagonal = 10;
public boolean bCharUp = false;
public boolean bCharDown = false;
public boolean bCharLeft = false;
public boolean bCharRight = false;
public void keyPressed (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W ) {
bCharUp = true;
if (bCharUp) {
charY -= 1;
}
}
if (e.getKeyCode() == KeyEvent.VK_A) {
bCharLeft = true;
if (bCharLeft) {
charX -=1;
}
}
if (e.getKeyCode() == KeyEvent.VK_W ) {
bCharDown = true;
if (bCharDown) {
charY -=1;
}
}
if (e.getKeyCode() == KeyEvent.VK_D) {
bCharRight = true;
if (bCharRight) {
charX +=1;
}
}
}
#Override
public void keyReleased (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W ) {
bCharUp = false;
}
if (e.getKeyCode() == KeyEvent.VK_A) {
bCharLeft = false;
}
if (e.getKeyCode() == KeyEvent.VK_S) {
bCharDown = false;
}
if (e.getKeyCode() == KeyEvent.VK_D) {
bCharRight = false;
}
}
#Override
public void keyTyped(KeyEvent e) { }
}
Thomas
Try using setPreferredSize(width, height);.
EDIT:
The problem lies in that you extended the Main class in the Movement class. So when you start the program, the movement class calls the Main class and that initializes the Movement class again, making a race condition. Just dont extend the Main class and make variables charX and charY static. Thus you can access the variables anywhere using Main..
In your main() method, you are creating the Main object (which extends from JFrame) but you haven't set it visible.
I'm in dire need of help. I've spent 3 hours pulling my hair over the fact that I don't know how to make my collision with one single platform work!
I want the player to be able to jump on the platform and not glitch on it, or fall through it. However, there is also the case that if the player holds up and the left arrow key or right arrow key and comes in contact with the edge of the platform! I really need your help on how I can make the simple aspects of collision with a platform work with my code.
Here is my code:
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Form1 extends Applet implements Runnable, KeyListener
{
private Image dbImage;
private Graphics dbg;
Thread t1;
int x = 300;
int y = 300;
boolean jumping = false;
double yVel = 0;
double termVel = 10;
int loop_cnt = 0;
int start_cnt = loop_cnt;
boolean falling = false;
boolean left, right, up, down;
double counter2 = 4;
int counter;
int num = 7;
int prevY = y;
int prevX = x;
int d = 0;
Rectangle player;
Rectangle platform;
public void init()
{
setSize(600, 400);
}
public void start()
{
player = new Rectangle();
platform = new Rectangle();
addKeyListener(this);
t1 = new Thread(this);
t1.start();
}
public void stop()
{
}
public void destroy()
{
}
#Override
public void run()
{
while (true)
{
//this code will be used if the player is on a platform and then walks off it by pressing either right or left
if (y <= 300 && !up)
{
y += 10;
}
if (left)
{
prevX = x;
x -= 2;
}
if (right)
{
prevX = x;
x += 2;
}
if (up)
{
counter2 += 0.05;
prevY = y;
y = y + (int) ((Math.sin(counter2) + Math.cos(counter2)) * 5);
if (counter2 >= 7)
{
counter2 = 4;
up = false;
}
}
if (y >= 300)
{
falling = false;
y = 300;
}
repaint();
try
{
t1.sleep(17);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public Rectangle IntersectPlatform()
{
return platform;
}
public void update(Graphics g)
{
dbImage = createImage (this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics();
// initialize buffer
if (dbImage == null)
{
}
// clear screen in background
dbg.setColor(getBackground());
dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
dbg.setColor(getForeground());
paint(dbg);
// draw image on the screen
g.drawImage(dbImage, 0, 0, this);
}
public void paint(Graphics g)
{
String string = String.valueOf(y);
g.setColor(Color.RED);
g.fillRect(x, y, 40, 100);
player.setBounds(x, y, 40, 100);
g.setColor(Color.BLUE);
platform.setBounds(180, 300, 100, 40);
g.fillRect(180, 300, 100, 40);
g.drawString(string, 100, 100);
}
#Override
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_RIGHT:
right = true;
break;
case KeyEvent.VK_LEFT:
left = true;
break;
case KeyEvent.VK_UP:
up = true;
break;
case KeyEvent.VK_DOWN:
down = true;
break;
}
}
#Override
public void keyReleased(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_RIGHT:
right = false;
break;
case KeyEvent.VK_LEFT:
left = false;
break;
case KeyEvent.VK_UP:
break;
case KeyEvent.VK_DOWN:
down = false;
break;
}
}
#Override
public void keyTyped(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
}