(Java 1.8, Eclipse) SNAKEGAME - Texture-Problems - java

i made a SnakeGame and its working in its basics, but i started to texture my snake with images.
i wanted the textures to change the direction whenever the snake changes directions aswell. and it is working, the problem i have is that every time the snake changes direction all of the snake body parts change direction at the same time which leads to texture bugs, how can i change the texture for the next bodyPart per one Timer tick?
And also how can i edit the Texture for the last bodyPart only for a tail
the code below is only the code from the important class "gamepanel"
the texture code is in the method draw(Graphics g)
thanks for the help i could not find any solutions to this.
package game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class gamepanel extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 42L;
static final int SCREEN_WIDTH = 600;
static final int SCREEN_HEIGHT = 600;
static final int UNIT_SIZE = 25;
static final int GAME_UNITS = (SCREEN_WIDTH*SCREEN_HEIGHT)/UNIT_SIZE;
int DELAY = 100;
final int x[] = new int[GAME_UNITS];
final int y[] = new int[GAME_UNITS];
int bodyParts = 6;
String str = String.valueOf(bodyParts);
int applesEaten;
int appleX;
int appleY;
char direction = 'R';
boolean running = false;
Timer timer;
Random random;
Image apple = new ImageIcon(this.getClass().getResource("/images/redapple.png")).getImage();
Image headup = new ImageIcon(this.getClass().getResource("/images/headup.png")).getImage();
Image headr = new ImageIcon(this.getClass().getResource("/images/headr.png")).getImage();
Image headl = new ImageIcon(this.getClass().getResource("/images/headl.png")).getImage();
Image headd = new ImageIcon(this.getClass().getResource("/images/headd.png")).getImage();
Image bodyup = new ImageIcon(this.getClass().getResource("/images/bodyup.png")).getImage();
Image bodyd = new ImageIcon(this.getClass().getResource("/images/bodyd.png")).getImage();
Image bodyr = new ImageIcon(this.getClass().getResource("/images/bodyr.png")).getImage();
Image bodyl = new ImageIcon(this.getClass().getResource("/images/bodyl.png")).getImage();
gamepanel(){
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
this.setBackground(new Color(33, 33, 33));
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
public void startGame() {
newApple();
running = true;
timer = new Timer(DELAY,this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
if(running) {
/* for(int i=0;i<SCREEN_HEIGHT/UNIT_SIZE;i++) {
g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
} */
//g.setColor(new Color(73, 235, 116));
//g.fillOval(appleX,appleY, UNIT_SIZE, UNIT_SIZE);
g.drawImage(apple, appleX,appleY, UNIT_SIZE, UNIT_SIZE, null, null);
for(int i = 0;i< bodyParts; i++) {
//HEAD TEXTURE
if(i==0 && direction=='U') {
g.drawImage(headup,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
} else if(i==0 && direction=='R') {
g.drawImage(headr,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
} else if(i==0 && direction=='L') {
g.drawImage(headl,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
} else if(i==0 && direction=='D') {
g.drawImage(headd,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
//BODY TEXTURE
} else if(i!=0 && direction=='U') {
g.drawImage(bodyup,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
} else if(i!=0 && direction=='R') {
g.drawImage(bodyr,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
} else if(i!=0 && direction=='L') {
g.drawImage(bodyl,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
} else if(i!=0 && direction=='D') {
g.drawImage(bodyd,x[i],y[i],UNIT_SIZE, UNIT_SIZE,null);
}
}
g.setColor(Color.red);
g.setFont(new Font("Arial",Font.BOLD,40));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Score: "+applesEaten, (SCREEN_WIDTH - metrics.stringWidth("Score: "+applesEaten))/2, g.getFont().getSize());
}else {
gameOver(g);
}
}
public void newApple() {
appleX = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
appleY = random.nextInt((int)(SCREEN_HEIGHT/UNIT_SIZE))*UNIT_SIZE;
}
public void move() {
for(int i = bodyParts;i>0;i--) {
x[i] = x[i-1];
y[i] = y[i-1];
}
switch(direction) {
case 'U' :
y[0] = y[0] - UNIT_SIZE;
break;
case 'D' :
y[0] = y[0] + UNIT_SIZE;
break;
case 'L' :
x[0] = x[0] - UNIT_SIZE;
break;
case 'R' :
x[0] = x[0] + UNIT_SIZE;
break;
}
}
public void checkApple() {
int i = bodyParts;
if((x[i] == appleX) && (y[i] == appleY)) {
newApple();
} else if((x[0] == appleX) && (y[0] == appleY)) {
bodyParts++;
applesEaten++;
DELAY--;
newApple();
}
}
public void checkCollisions() {
//checks if head collides with body
for(int i = bodyParts; i>0;i--) {
if ((x[0]==x[i]) && (y[0]==y[i])) {
running = false;
}
}
// checks if head touches left border
if(x[0] < 0) {
running = false;
}
// check right border collide
if(x[0] > SCREEN_WIDTH) {
running = false;
}
// check top border
if(y[0] < 0) {
running = false;
}
//checkk bottom border
if(y[0] > SCREEN_HEIGHT) {
running = false;
}
if(!running) {
timer.stop();
}
}
public void gameOver(Graphics g) {
//SCORE
g.setColor(Color.red);
g.setFont(new Font("Arial",Font.BOLD,40));
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString("Your Score: "+applesEaten, (SCREEN_WIDTH - metrics1.stringWidth("Your Score: "+applesEaten))/2, g.getFont().getSize());
//GAme Over Text
g.setColor(Color.red);
g.setFont(new Font("Arial",Font.BOLD,75));
FontMetrics metrics2 = getFontMetrics(g.getFont());
g.drawString("Game Over", (SCREEN_WIDTH - metrics2.stringWidth("Game Over"))/2, SCREEN_HEIGHT/2);
}
#Override
public void actionPerformed(ActionEvent e) {
if(running) {
move();
checkApple();
checkCollisions();
}
repaint();
}
public class MyKeyAdapter extends KeyAdapter{
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction != 'R') {
direction = 'L';
}
break;
case KeyEvent.VK_RIGHT:
if(direction != 'L') {
direction = 'R';
}
break;
case KeyEvent.VK_UP:
if(direction != 'D') {
direction = 'U';
}
break;
case KeyEvent.VK_DOWN:
if(direction != 'U') {
direction = 'D';
}
break;
}
}
}
}

maybe try updating the textures for each body part starting from the head 1 per game frame at a time? like 0 = head piece and will be updated first, 1 is the next body part in line so will be updated in the next frame when the snake has moved 1 unit and therefore lining up the timings

Related

Snake Game in Java - Snake leaving Spaces

I'm making a snake game and well It's done I can just export it and everything. Just one simple problem; For whatever reason the snake leaves spaces everytime the bodyParts increases. I didn't calculate by how much exactly but everytime the bodyParts increases, the tail leaves spaces more.
I've tried to look for the problem.
This is my first Game Project ever so please don't judge me xd.
These are the code.
import java.awt.Color;
import java.awt.Dimension;
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 java.sql.Time;
import java.util.Random;
import javax.swing.Timer;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements ActionListener {
static final int SCREEN_HEIGHT = 600;
static final int SCREEN_WIDTH = 600;
static final int UNIT_SIZE = 25;
static final int GAME_UNITS = (SCREEN_HEIGHT*SCREEN_WIDTH)/UNIT_SIZE;
static final int DELAY = 175;
final int x[] = new int [GAME_UNITS];
final int y[] = new int [GAME_UNITS];
int bodyParts = 1;
int applesEaten;
int appleX;
int appleY;
char direction = 'R';
boolean running = false;
Timer timer;
Random random;
private Image tail;
private Image apple;
private Image head;
GamePanel() {
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_HEIGHT,SCREEN_WIDTH));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
loadImages();
}
public void startGame() {
running = true;
newApple();
Timer timer = new Timer(DELAY,this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
private void loadImages() {
ImageIcon iid = new ImageIcon("src/res/tail.png");
tail = iid.getImage();
ImageIcon iia = new ImageIcon("src/res/apple.png");
apple = iia.getImage();
ImageIcon iih = new ImageIcon("src/res/head.png");
head = iih.getImage();
}
public void draw(Graphics g) {
g.setColor(Color.red);
for (int i = 0; i < SCREEN_HEIGHT/UNIT_SIZE; i++) {
//g.drawLine(i*UNIT_SIZE, 0 , i*UNIT_SIZE, SCREEN_HEIGHT);
// g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE); //grids
}
g.drawImage(apple, appleX, appleY, this); //apple
for (int z = 0; z < bodyParts; z++) {
if (z == 0) {
g.drawImage(head, x[z], y[z], this);
} else {
g.drawImage(tail, x[z], y[z], this);
}
}
Toolkit.getDefaultToolkit().sync();
}
public void newApple() {
appleX = random.nextInt((SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
appleY = random.nextInt((SCREEN_HEIGHT/UNIT_SIZE))*UNIT_SIZE;
}
public void move() {
for(int z = bodyParts;z>0;z--) {
x[z] = x[(z-1)];
y[z] = y[(z-1)];
switch(direction) {
case 'U':
y[0] -= UNIT_SIZE;
break;
case 'D':
y[0] += UNIT_SIZE;
break;
case 'L':
x[0] -= UNIT_SIZE;
break;
case 'R':
x[0] += UNIT_SIZE;
break;
}
}
}
public void checkApple() {
if((x[0] == appleX) && (y[0] == appleY)) {
bodyParts++;
applesEaten++;
newApple();
}
}
public void checkCollisions() {
//checks if head collides with body
for(int i = bodyParts;i<0;i--) {
if((x[0] == x[i])&& (y[0] == y[i])) {
running = false;
}
}
//checks if head touches left border
if(x[0] < 0) {
running = false;
}
//check if head touches right border
if(x[0] > SCREEN_WIDTH) {
running = false;
}
//check if head touches top border
if(y[0] < 0) {
running = false;
}
//check if head touches bottom border
if(y[0] > SCREEN_HEIGHT) {
running = false;
}
if(!running) {
timer.stop();
}
}
public void gameOver(Graphics g) {
}
#Override
public void actionPerformed(ActionEvent e) {
if(running) {
move();
checkApple();
checkCollisions();
loadImages();
}
repaint();
}
public class MyKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction != 'R') {
direction = 'L';
}
break;
case KeyEvent.VK_RIGHT:
if(direction != 'L') {
direction = 'R';
}
break;
case KeyEvent.VK_UP:
if(direction != 'D') {
direction = 'U';
}
break;
case KeyEvent.VK_DOWN:
if(direction != 'U') {
direction = 'D';
}
break;
}
}
}
}
This is when the bodyParts = 2 bodyParts = 2;
And, this is when the bodyParts = 3
bodyParts = 3;

Utilizing public variables

I have created a game similar to snake in which the user is first prompted with a jpanel asking which difficulty they want, and whatever JButton they pick influences the size of the map as well as the delay between the snake movements. I have the map size working just fine, but the delay variable never seems to change. I suspect it has something to do with the way the timer is being casted, but I have no idea how to fix it. I am also wondering how when the program is first ran it seems some of the variables don't update, but the second time it is ran all of them are updated. Here is my class with the original variables and collision detection:
import java.util.Random;
import javax.swing.JLabel;
public class GameEngine extends JPanel implements ActionListener{
//creates the size of the panel as well as creating the resolution for all objects, including the players and food.
static final int sWidth = 600;
static final int sHeight = 600;
public static int size = 24;
static int objectSize = (sHeight*sWidth) / size;
public static int delay = 100;
final int playerX[] = new int[objectSize];
final int playerY[] = new int[objectSize];
int bodySize = 4;
int score = 0;
int appleX;
int appleY;
char direction = 'D';
boolean started = false;
Random random;
Timer timer;
boolean easy;
JLabel score1;
public static String difficulty;
GameEngine(){
random = new Random();
this.setPreferredSize(new Dimension(sWidth,sHeight));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new UserMovement());
gameStart();
}
public void gameStart() {
newApple();
started = true;
timer = new Timer(delay,this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void drawHead(Graphics g) {
g.setColor(new Color(100,252,0));
g.fillRect(playerX[0], playerY[0], size, size);
}
public void draw(Graphics g) {
if(started) {
//draws the apples
g.setColor(Color.red);
g.fillOval(appleX, appleY, size, size);
for (int i = 0; i < bodySize; i++) {
if(i == 0) {
drawHead(g);
}
else {
g.setColor(new Color(60,180,0));
g.fillRect(playerX[i], playerY[i], size, size);
}
}
g.setColor(Color.white);
g.setFont(new Font("Bold", Font.BOLD, 20));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Score: " + score,(sWidth - metrics.stringWidth("Score: " + score))/2,g.getFont().getSize());
}
}
public void newApple(){
appleX = random.nextInt((int)(sWidth/size))*size;
appleY = random.nextInt((int)(sHeight/size))*size;
}
//moves the player by using and modifying their coordinates
public void move() {
for (int i = bodySize; i > 0; i--) {
playerX[i] = playerX[i-1];
playerY[i] = playerY[i-1];
}
switch(direction) {
case 'W':
playerY[0] = playerY[0] - size;
break;
case 'S':
playerY[0] = playerY[0] + size;
break;
case 'A':
playerX[0] = playerX[0] - size;
break;
case 'D':
playerX[0] = playerX[0] + size;
break;
}
}
public void checkFood() {
if(playerX[0] == appleX && playerY[0] == appleY)
{
bodySize++;
score++;
newApple();
}
}
public void checkCol() {
//checks for head collision with the body
for(int i = bodySize; i > 0; i--) {
if((playerX[0] == playerX[i]) && (playerY[0] == playerY[i])) {
started = false;
}
}
//checks if head touches any of the walls of the program
if(playerX[0] < 0) {
started = false;
}
if(playerX[0] > sWidth) {
started = false;
}
if(playerY[0] < 0) {
started = false;
}
if(playerY[0] > sHeight) {
started = false;
}
if(started != true) {
timer.stop();
}
}
public void actionPerformed(ActionEvent e){
if(started == true) {
move();
checkFood();
checkCol();
}
repaint();
}
public class UserMovement extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction != 'D') {
direction = 'A';
}
break;
case KeyEvent.VK_RIGHT:
if(direction != 'A') {
direction = 'D';
}
break;
case KeyEvent.VK_UP:
if(direction != 'S') {
direction = 'W';
}
break;
case KeyEvent.VK_DOWN:
if(direction != 'W') {
direction = 'S';
}
break;
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
}
and here is the code calling and changing the delay and size variables:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StartMenu extends JPanel {
StartMenu()
{
JButton easy = new JButton();
JButton hard = new JButton();
this.setPreferredSize(new Dimension(350,240));
this.setLayout(null);
this.setBackground(Color.black);
this.setFocusable(true);
easy.setBounds(75,40,200,40);
hard.setBounds(75,120,200,40);
this.add(easy);
this.add(hard);
easy.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setVisible(false);
new SnakeStart();
GameEngine.size = 48;
GameEngine.delay = 140;
}
});
hard.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setVisible(false);
new SnakeStart();
GameEngine.size = 24;
GameEngine.delay = 70;
}
});
}
}
I assume your GameEngine instance is created before the StartMenu action listeners are executed. If that assumption is correct, that means that GameEngine.timer with the default value of delay is created in the GameEngine constructor and is not updated after the delay is changed.
You need to make sure that you explicitly update your timer with the new delay value after StartMenu actions are called.

Java Graphics Rectangle Size Changing

I have just started to learn Java, so excuse my messy code. Looking all over the internet, I have not found a solution to this question yet. This is the game pong. I have to padels that I am controlling ith the keys, 'w', 's', up, and down. When I draw the panels in my graphics section, I use the padelY for Y1 and use padelY + padelLength(A constant) for Y2. I cannot seem to understand why when I rut the program the padels change size as I move them up and down. Also, the padel on the right is named panel1, when I draw the padel I use the screen size - the padel spacing for X1 yet the padel appears to be stuck on the side.
I would really appreciate any advice that anyone could give on those issues or how to clean up my code in general!
Thanks!
package Pong;
//Import Libraries
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
#SuppressWarnings("serial")
public class Pong extends JPanel implements KeyListener{
int padel1y = 150;
int padel2y = 150;
static final int padelLength = 100;
int padelWidth = 10;
int padelSpeed = 2;
int padel2Speed = 0;
int padel1Speed = 0;
int ballX = BOX_WIDTH/2;
int ballY= BOX_HEIGHT/2;
int ballXSpeed = 2;
int ballYSpeed = 1;
int ballRadius = 10;
int ballCount = 0;
public final static int ballSpeedIncrease = 500;
public final static int BOX_WIDTH = 600;
public final static int BOX_HEIGHT = 600;
public final static int UPDATE_RATE = 100;
public final static int padelSpace = 10;
public Pong() {
setPreferredSize(new Dimension(BOX_WIDTH,BOX_HEIGHT));
Thread gameThread = new Thread() {
public void run(){
while(true){
ballCount = ballCount + 1;
if(ballCount%ballSpeedIncrease == 0){
if(ballXSpeed < 0){
ballXSpeed = ballXSpeed - 1;
}
if(ballYSpeed < 0){
ballYSpeed = ballYSpeed - 1;
}
if(ballXSpeed > 0){
ballXSpeed++;
}
if(ballYSpeed > 0){
ballYSpeed++;
}
}
if(ballX-ballRadius <= 10+padelWidth){
if(ballY<padel2y || ballY>padel2y+padelLength){
System.exit(0);
}
else{
ballXSpeed = -ballXSpeed;
}
}
else if(ballX+ballRadius >= 590-padelWidth){
if(ballY<padel1y || ballY>padel1y+padelLength){
System.exit(0);
}
else{
ballXSpeed = -ballXSpeed;
}
}
if(ballY-ballRadius <= 0){
ballYSpeed = -ballYSpeed;
}
else if(ballY+ballRadius >= BOX_HEIGHT){
ballYSpeed = -ballYSpeed;
}
padel1y = padel1y +padel1Speed;
padel2y = padel2y +padel2Speed;
ballX = ballX + ballXSpeed;
ballY = ballY+ ballYSpeed;
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
}
catch (InterruptedException ex) {}
}
}
};
gameThread.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0,0,BOX_WIDTH,BOX_HEIGHT);
g.setColor(Color.blue);
g.fillRect(padelSpace,padel2y,padelSpace + padelWidth,padel2y+padelLength);
g.fillRect(BOX_WIDTH-padelSpace,padel1y,BOX_WIDTH-padelSpace-padelWidth,padel1y+padelLength);
g.setColor(Color.green);
g.fillOval(ballX, ballY, ballRadius*2, ballRadius*2);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Create Frame
JFrame frame = new JFrame("PONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONGPONG");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Pong pong = new Pong();
frame.setContentPane(pong);
frame.setSize(BOX_WIDTH,BOX_HEIGHT);
frame.pack();
frame.addKeyListener(pong);
frame.setVisible(true);
}
});
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP){
padel1Speed = -padelSpeed;
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
padel1Speed = padelSpeed;
}
else if(e.getKeyCode() == KeyEvent.VK_W){
padel2Speed = -padelSpeed;
}
else if(e.getKeyCode() == KeyEvent.VK_S){
padel2Speed = padelSpeed;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
padel1Speed = 0;
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
padel1Speed = 0;
}
else if(e.getKeyCode() == KeyEvent.VK_W){
padel2Speed = 0;
}
else if(e.getKeyCode() == KeyEvent.VK_S){
padel2Speed = 0;
}
}
#Override
public void keyTyped(KeyEvent e) {}
}
See this for documentation on how to use the fillRect() method: https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html#fillRect(int,%20int,%20int,%20int)
The arguments are: x position, y position, width and height.
You use it like this: g.fillRect(padelSpace,padel2y,padelSpace + padelWidth,padel2y+padelLength);
The second and third arguments are wrong. You should only be passing the width and height. Like this: g.fillRect(padelSpace, padel2y, padelWidth, padelLength);
More generally, when something is going wrong (drawing the paddle) read the documentation on the methods you use to do that.

Java continue movement right away after key pressed?

Well when I am pressing any of the key arrows, the red box moves, yes it moves 10px and then stops for 1 second & continues moving, instead of move right away without stopping.
example of the occurring issue:
(source: gyazo.com)
Can you see how it stopped for 1 or 0.5 secs and continued?
How can I fix it?
I am using KeyEventDispatcher
My key detecting:
Whole src:
public class Game extends Frame {
private class Keyboard implements KeyEventDispatcher {
private Game game;
public Keyboard(Game game) {
this.game = game;
}
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
this.movement(e);
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
} else if (e.getID() == KeyEvent.KEY_TYPED) {
}
return false;
}
public void movement(KeyEvent e) {
int keyCode = e.getKeyCode();
switch( keyCode ) {
case KeyEvent.VK_UP:
game.movePlayer(0, -10);
break;
case KeyEvent.VK_DOWN:
game.movePlayer(0, 10);
break;
case KeyEvent.VK_LEFT:
game.movePlayer(-10, 0);
break;
case KeyEvent.VK_RIGHT :
game.movePlayer(10, 0);
break;
}
}
}
private static final long serialVersionUID = 1L;
private int coordinateX = 1;
private int coordinateY = 1;
public int width = 300;
public int height = width / 16 * 9;
public int scale = 3;
public int mouseY = MouseInfo.getPointerInfo().getLocation().y;
public int mouseX = MouseInfo.getPointerInfo().getLocation().x;
private Player player = new Player(0, 0);
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame.setSize(width, height);
frame.setResizable(false);
frame.setTitle("First game");
JPanel j = new JPanel();
j.setVisible(true);
JLabel text = new JLabel("coords");
j.add(text);
frame.add(this);
frame.pack();
frame.add(j);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new Keyboard(this));
}
private void movePlayer(int x, int y) {
/**
* Main region area
*/
int pX = 0, pY = 0;
if (y == 0) { // x
if (player.getX() + x + 100 > frame.getContentPane().getWidth() || player.getX() + x < 0) {
if (player.getX() + x < 0) {
player.setX(0);
return;
}
if (player.getX() + x > 0) {
player.setX(frame.getContentPane().getWidth() - 100);
return;
}
return;
}
pX = x;
}
else if (x == 0) { // y
if (player.getY() + y + 100 > frame.getContentPane().getHeight() || player.getY() + y < 0) {
if (player.getY() + y < 0) {
player.setY(0);
return;
}
if (player.getY() + y > 0) {
player.setY(frame.getContentPane().getHeight() - 100);
return;
}
return;
}
pY = y;
}
player.updatePosition(pX, pY);
}
public void update() {
}
public void render() {
bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.fillRect(player.getX(), player.getY(), 100, 100);
g.dispose();
bs.show();
}
}
Frame.java:
public class Frame extends Canvas {
public static final long serialVersionUID = 8L;
public static JFrame frame = new JFrame();
public static Threads thread;
public static Game game;
public Graphics g;
public BufferStrategy bs;
/**
* #param args
*/
public static void main(String[] args) {
thread = new Threads(new Game());
thread.start();
}
}
The problem is the repeat rate for KeyStrokes. This is controlled by the OS.
The solution is to use a Swing Timer to schedule the animation as soon as the key is pressed.
See Motion Using the Keyboard for more information and a complete working example.
Also, you should NOT be using a KeyListener but intead should be using KeyBindings.

How do I make an infinite tiled map? (java)

I'm making a tiled map and I came across this problem:
When i'm moving my character it's going off the map and then falls (due to gravity)
How do I make this map infinite?
And also, how do I store which blocks are destroyed and which not? So that i can repaint the screen with the same map and when you walk back to the starting point the brocken blocks are still there.
Just Tell me if I need to provide Code.
I'll give you my world.java
package game.test.src;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.ImageIcon;
public class World {
public Rectangle[] blocks;
public boolean[] isSolid;
public Image[] blockImg;
public final int arrayNum = 500;
//Block Images
public Image BLOCK_GRASS, BLOCK_DIRT, BLOCK_STONE, BLOCK_SKY;
private int x, y, xDirection, yDirection;;
//map navigation
static final int PAN_UP = 0, PAN_DOWN = 1, PAN_LEFT= 2, PAN_RIGHT = 3;
public World(){
BLOCK_GRASS = new ImageIcon("H:/2D game test/Game test 2/src/game/test/src/images/tile_grass.png").getImage();
BLOCK_DIRT = new ImageIcon("H:/2D game test/Game test 2/src/game/test/src/images/tile_dirt.png").getImage();
BLOCK_STONE = new ImageIcon("H:/2D game test/Game test 2/src/game/test/src/images/tile_stone.png").getImage();
BLOCK_SKY = new ImageIcon("H:/2D game test/Game test 2/src/game/test/src/images/tile_sky.png").getImage();
blocks = new Rectangle[500];
blockImg = new Image[500];
isSolid = new boolean[arrayNum];
loadArrays();
}
private void loadArrays(){
for(int i = 0; i < arrayNum; i++){
if(x >= 500){
x = 0;
y += 20;
}
if(i >= 0 && i < 100){
blockImg[i] = BLOCK_SKY;
isSolid[i] = false;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if(i >= 100 && i < 125){
blockImg[i] = BLOCK_GRASS;
isSolid[i] = true;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if(i >= 125 && i < 225){
blockImg[i] = BLOCK_DIRT;
isSolid[i] = true;
blocks[i] = new Rectangle(x, y, 20, 20);
}
if(i >= 225 && i < 500){
blockImg[i] = BLOCK_STONE;
isSolid[i] = true;
blocks[i] = new Rectangle(x, y, 20, 20);
}
x += 20;
}
}
public void draw(Graphics g){
for(int i = 0; i < arrayNum; i++){
g.drawImage(blockImg[i], blocks[i].x, blocks[i].y, null);
}
}
public void moveMap(){
for(Rectangle r : blocks){
r.x += xDirection;
r.y += yDirection;
}
}
public void stopMoveMap(){
setXDirection(0);
setYDirection(0);
}
private void setXDirection(int dir){
xDirection = dir;
}
private void setYDirection(int dir){
yDirection = dir;
}
public void navigateMap(int nav){
switch(nav){
default:
System.out.println("default case entered... Doing nothing.");
break;
case PAN_UP:
setYDirection(-1);
break;
case PAN_DOWN:
setYDirection(1);
break;
case PAN_LEFT:
setXDirection(-1);
break;
case PAN_RIGHT:
setXDirection(1);
break;
}
}
}
here is my Player.java
package game.test.src;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
public class Player {
static final int MOVE_UP = 0, MOVE_DOWN = 1, MOVE_LEFT= 2, MOVE_RIGHT = 3;
private World world;
private Rectangle playerRect;
private Image playerImg;
//Block Variables
private int hoverX, hoverY;
private boolean hovering = false;
protected static int xDirection;
protected static int yDirection;
private Weapon weapon;
public Player(World world){
this.world = world;
playerImg = new ImageIcon("H:/2D game test/Game test 2/src/game/test/src/images/Character.png").getImage();
playerRect = new Rectangle(50, 0, 10, 36);
weapon = new Weapon(weapon.PICKAXE);
}
private static void setXDirection(int d){
xDirection = d;
}
private static void setYDirection(int d){
yDirection = d;
}
public void update()
{
move();
checkForCollision();
}
private void checkForCollision() {
}
private void move()
{
playerRect.x += xDirection;
playerRect.y += yDirection;
gravity();
}
private void gravity()
{
for(int i=0;i<world.arrayNum; i++)
{
if(!world.isSolid[i])
{
setYDirection(1);
}
else if(world.isSolid[i] && playerRect.intersects(world.blocks[i]))
{
setYDirection(0);
}
}
}
//MotionEvents
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseClicked(MouseEvent e)
{
}
public void mouseMoved(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
int px = playerRect.x;
int py = playerRect.y;
for(int i = 0; i < world.arrayNum; i++)
{
if(weapon.isEquipped(Weapon.PICKAXE) &&
x > world.blocks[i].x && x < world.blocks[i].x + world.blocks[i].width &&
y > world.blocks[i].x && y < world.blocks[i].y + world.blocks[i].height && world.isSolid[i] &&
(world.blocks[i].x + (world.blocks[i].width / 2) ) <= (px + playerRect.width/2) + weapon.WEAPON_RADIUS &&
(world.blocks[i].x + (world.blocks[i].width / 2) ) >= (px + playerRect.width/2) - weapon.WEAPON_RADIUS &&
(world.blocks[i].y + (world.blocks[i].height / 2) ) <= (py + playerRect.height/2) + weapon.WEAPON_RADIUS &&
(world.blocks[i].y + (world.blocks[i].height / 2) ) >= (py + playerRect.height/2) - weapon.WEAPON_RADIUS)
{
hovering = true;
hoverX = world.blocks[i].x;
hoverY = world.blocks[i].y;
break;
}
else
hovering = false;
}
}
public void mouseDragged(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
//Drawing Methods
public void draw(Graphics g)
{
g.drawImage(playerImg, playerRect.x, playerRect.y, null);
if(hovering)
drawBlockOutline(g);
}
private void drawBlockOutline(Graphics g)
{
g.setColor(Color.black);
g.drawRect(hoverX, hoverY, world.blocks[0].width,world.blocks[0].height);
}
private class Weapon
{
public static final int UNARMED = 0;
public static final int PICKAXE = 1;
public static final int GUN = 2;
public int CURRENT_WEAPON;
public int WEAPON_RADIUS;
public Weapon(int w)
{
switch(w)
{
default:
System.out.println("No weapon selected");
break;
case UNARMED:
CURRENT_WEAPON = UNARMED;
WEAPON_RADIUS = 100;
break;
case PICKAXE:
CURRENT_WEAPON = PICKAXE;
WEAPON_RADIUS = 100;
break;
case GUN:
CURRENT_WEAPON = GUN;
WEAPON_RADIUS = 100;
break;
}
}
public void selectWeapon(int w)
{
switch(w)
{
default:
System.out.println("No weapon selected");
break;
case UNARMED:
CURRENT_WEAPON = UNARMED;
WEAPON_RADIUS = 100;
break;
case PICKAXE:
CURRENT_WEAPON = PICKAXE;
WEAPON_RADIUS = 100;
break;
case GUN:
CURRENT_WEAPON = GUN;
WEAPON_RADIUS = 100;
break;
}
}
public boolean isEquipped(int w)
{
if(w == CURRENT_WEAPON)
{
return true;
}
else
return false;
}
}
public void moveMap(){
for(Rectangle r : world.blocks){
r.x += xDirection;
r.y += yDirection;
}
}
public static void stopMoveMap(){
setXDirection(0);
setYDirection(0);
}
private static void setXDirection1(int dir){
xDirection = dir;
}
private static void setYDirection1(int dir){
yDirection = dir;
}
public static void navigatePlayer(int nav){
switch(nav){
default:
System.out.println("default case entered... Doing nothing.");
break;
case MOVE_UP:
setYDirection1(-1);
break;
case MOVE_DOWN:
setYDirection1(1);
break;
case MOVE_LEFT:
setXDirection1(-1);
break;
case MOVE_RIGHT:
setXDirection1(1);
break;
}
}
}
Thanks for the help!
At a basic level you need a 3 dimensional array to store every single block. The problem is, that won't get you an "Infinite" world, it will get you one limited to memory.
Notch solved it by using "Chunks"--which are 3D arrays of a fixed size that can be swapped to disk when necessary.
You should also learn about how bits can be used to pack storage, for anything large you will need it--For your example, each block can be held in 3 bits, 2 for the blocks and one more for "broken". If you used this instead of a byte array you would use less than 1/2 the storage, which means you could maybe go twice as far in your world before needing to read another chunk from disk.
If you want an easier introduction to writing this kind of app, look into writing a minecraft mod using Bukkit--much of the detail work is handled for you and you can actually pick up a lot of knowledge about how stuff is done before trying to write a Minecraft clone from scratch.
So what you need is essentially a two-dimensional data structure which can be extended indefinitely (or until memory runs out) into both dimensions.
There are myriads of ways to solve this problem.
One way would be a two dimensional double-linked list (double-linked net?) where each map tile has a reference to the four adjacent tiles. That means you keep track of the tile in the center of the viewport and render the scene by iterating into all four directions until you leave the screen. When you hit an un-initialized tile, it's time to generate it.

Categories