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;
Related
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.
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
I try running this program and I get a static void error. I am new to this and I have no idea how to fix this problem so any input would be helpful, thank you!
package johnbarthelmes.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() {
addKeyListener(new TAdapter());
setBackground(Color.black);
setFocusable(true);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
loadImages();
initGame();
}
private void loadImages() {
ImageIcon iid = new ImageIcon("dot.png");
ball = iid.getImage();
ImageIcon iia = new ImageIcon("apple.png");
apple = iia.getImage();
ImageIcon iih = new ImageIcon("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;
}
}
}
}
If it helps at all this is the code for the snake game that I got from a Dr Java tutorial in which I followed all the steps correctly as far as I know. There was no errors compiling but when I ran the program I got that error message.
In order to run an application, your class needs a main method with a certain signature, so Java knows what to do. Probably you want to start up the program by showing your JFrame:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Board b = new Board();
b.setVisible(true);
}
});
}
You need to add a main method. It's the entry point to every Java application. It looks like it should have this implementation, based on your code sample.
public static void main(String[] args) {
Board board = new Board();
// need to do something else with board here maybe?
}
I have never tried to implement shooting in any kind of game before and when I try to remove and element of the ArrayList I'm using it throws and index out of bounds exception. I want to be able to press the enter key, store the current direction that the player is facing and then shoot a projectile in that current direction. Then, once a projectile has reached its destination to remove itself from the ArrayList and not be rendered anymore. However, when it reaches the end of the map (x == Map.mapSizeX), the bullet freezes and that's when the exception is thrown. (Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1).
Code for the shooting class (Projectile.java)
package Engine;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Random;
public class Projectile {
public static ArrayList<Integer> bullets = new ArrayList<Integer>(3);
private static DirectionalVector dir = new DirectionalVector();
private static int index = 0;
private static int x,y;
public Projectile(int direction, int x, int y){
dir.applyDirection(direction);
bullets.add(index);
index += 1;
this.x = x;
this.y = y;
}
public void updatePos(){
if (dir.right){
x += 1;
dir.left = false;
dir.down = false;
}
if (dir.left){
x -= 1;
dir.right = false;
dir.down = false;
}
if (dir.down){
y += 1;
dir.left = false;
dir.right = false;
}
if (dir.down){
System.out.println("DOWN");
}
if (dir.right){
System.out.println("RIGHT");
}
if (dir.left){
System.out.println("LEFT");
}
if (x > Map.mapSizeX){
bullets.remove(index);
}
if (x < 0){
bullets.remove(index);
}
if (y > Map.mapSizeY){
bullets.remove(index);
}
if (y < 0){
bullets.remove(index);
}
}
public static void render(Graphics2D g2){
int r = new Random().nextInt(256);
int g = new Random().nextInt(256);
int b = new Random().nextInt(256);
if (r < 50){
r = new Random().nextInt(256);
}
if (g < 50){
g = new Random().nextInt(256);
}
if (b < 50){
b = new Random().nextInt(256);
}
g2.setColor(new Color(r,g,b));
g2.fillRect(x * Map.tileSize, y * Map.tileSize, Map.tileSize, Map.tileSize);
}
Code for the DirectionalVector class
package Engine;
public class DirectionalVector {
public boolean left = false, right = true, down = false;
public DirectionalVector(){
}
public void applyDirection(int id){
if (id == 0){
right = true;
}
if (id == 1){
left = true;
}
if (id == 2){
down = true;
}
}
}
Code for the Player class
package Engine;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Player implements KeyListener, Runnable{
public static int x = 0,y = 0;
private static boolean right = false, left = false, falling = false, jumping = false;
private Thread thread = new Thread(this, "GAME LOOP");
private static int lastDirectionPressed = 0;
public static Projectile bullet;
public Player(){
thread.start();
}
public void renderPlayer(boolean value, Graphics2D g2){
if (value){
g2.setColor(Color.blue);
g2.fillRect(x * Map.tileSize, y * Map.tileSize, Map.tileSize, Map.tileSize);
}
}
#Override
public void keyPressed(KeyEvent e) {
int c = e.getKeyCode();
if (c == KeyEvent.VK_RIGHT && right){
x += 1;
lastDirectionPressed = 0;
}
if (c == KeyEvent.VK_LEFT && left){
x -= 1;
lastDirectionPressed = 1;
}
if (c == KeyEvent.VK_SPACE && jumping){
y -= 1;
}
if (c == KeyEvent.VK_ENTER){
bullet = new Projectile(lastDirectionPressed, x, y);
}
}
public void update(){
if (x != Map.mapSizeX){
right = Map.getTile(x + 1, y) == 0;
}
if (x > 0){
left = Map.getTile(x - 1, y) == 0;
}
if (x == 0){
left = false;
}
if (x == Map.mapSizeX){
right = false;
}
if (y != Map.mapSizeY){
falling = Map.getTile(x, y + 1) == 0;
}
if (y == Map.mapSizeY){
falling = false;
}
if (falling){
y += 1;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void run(){
while (true){
try{
Thread.sleep(100);
update();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
Code for the ContentPane class (Where all the rendering occurs)
package Engine;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
#SuppressWarnings({"serial", "static-access"})
public class ContentPane extends JPanel{
private Map map = new Map();
public Player player = new Player();
public ContentPane(){
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g2);
map.renderMap(true, g2);
player.renderPlayer(true, g2);
if (player.bullet.bullets.size() > 0){
player.bullet.updatePos();
}
for (int i = 0; i < player.bullet.bullets.size(); i++){
player.bullet.render(g2);
}
System.out.println(player.bullet.bullets.size());
repaint();
}
}
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.