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.
Related
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;
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 made a program to display interference patterns for light waves. I did this by using the paint method on a JPanel to draw 2 sources and then drawing concentric circles around them. This would be double slit interference, so I allowed one of the sources to move around to experiment with the slit width.
The problem is that when I run this, my computer says it is using 80% of my CPU! There's really not much to it. Circle in the middle, circles around it, and it moves. My code follows.
main class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class main {
static final int UP = -1;
static final int DOWN = 1;
static final int RIGHT = 1;
static final int LEFT = -1;
static final int NOMOVEMENT = 0;
static int verticalMovement = NOMOVEMENT;
static int horizontalMovement = NOMOVEMENT;
public static void main(String[] args) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Point s1 = new Point((int)(screenSize.getWidth()/3), 50);
Point s2 = new Point((int)(2*screenSize.getWidth()/3), 50);
JFrame frame = new JFrame("Physics Frame");
frame.setPreferredSize(screenSize);
PhysicsPane pane = new PhysicsPane(screenSize, 15, s1, s2);
pane.setPreferredSize(screenSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
Timer time = new Timer(1000 / 20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
switch (verticalMovement){
case UP:
s2.changeY(UP);
break;
case DOWN:
s2.changeY(DOWN);
break;
default:
break;
}
switch (horizontalMovement){
case RIGHT:
s2.changeX(RIGHT);
break;
case LEFT:
s2.changeX(LEFT);
break;
default:
break;
}
pane.repaint();
}
});
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==37){
horizontalMovement = LEFT;
} else if (e.getKeyCode()==38){
verticalMovement = UP;
} else if (e.getKeyCode()==39){
horizontalMovement = RIGHT;
} else if (e.getKeyCode()==40){
verticalMovement = DOWN;
}
if(e.getKeyChar()=='a'){
pane.setWaveLength(2);
}
if(e.getKeyChar()=='s'){
pane.setWaveLength(-2);
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()){
case 37:
horizontalMovement = NOMOVEMENT;
break;
case 38:
verticalMovement = NOMOVEMENT;
break;
case 39:
horizontalMovement = NOMOVEMENT;
break;
case 40:
verticalMovement = NOMOVEMENT;
break;
}
}
});
frame.setVisible(true);
time.start();
}
}
Panel class. If there's an inefficiency with the drawing method, it would be here.
import javax.swing.*;
import java.awt.*;
public class PhysicsPane extends JPanel {
private Dimension size;
private Point[] pointArray = new Point[2];
private double waveLength;
public PhysicsPane(Dimension size, double wavelength, Point source1, Point source2) {
this.size = size;
pointArray[0] = source1;
pointArray[1] = source2;
setPreferredSize(size);
this.waveLength = wavelength;
}
#Override
public void paintComponent(Graphics g){
for (int i = 0; i < 2; i++) {
g.setColor(Color.black);
double x = this.pointArray[i].getX();
double y = this.pointArray[i].getY();
g.fillOval((int)x, (int)y, 2, 2);
for (int j = (int)waveLength; j < 1500; j+=waveLength) {
g.setColor(Color.red);
g.drawOval((int)x-(j/2+1), (int)y-(j/2+1), 2 + j, 2 + j);
}
}
}
public void setWaveLength(double increment){
this.waveLength+=increment;
}
}
Point Class: Really just puts x and y coordinates into one construct. Not important particularly
public class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public void changeX(double dX){
this.x+=dX;
}
public void changeY(double dY){
this.y+=dY;
}
}
So what is wrong with my program? Why is such a simple animation consuming so much of my processor?
UPDATED CODE SECTION:
#Override
public void paintComponent(Graphics g){
BufferedImage bi = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = bi.getGraphics();
for (int i = 0; i < 2; i++) {
graphics.setColor(Color.black);
double x = this.pointArray[i].getX();
double y = this.pointArray[i].getY();
graphics.fillOval((int)x, (int)y, 2, 2);
for (int j = (int)waveLength; j < 1500; j+=waveLength) {
graphics.setColor(Color.red);
graphics.drawOval((int)x-(j/2+1), (int)y-(j/2+1), 2 + j, 2 + j);
}
}
g.drawImage(bi, 0, 0, new ImageObserver() {
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
return false;
}
});
}
The improvement that I recommend is removal of unnecessary tasks being performed, notably how your code updates the pane being drawn on, even when there aren't changes.
The following update reduced CPU usage from 12% to 0% (static frame):
Timer time = new Timer(1000 / 20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean refresh = false;
switch (verticalMovement) {
case UP:
s2.changeY(UP);
refresh = true;
break;
case DOWN:
s2.changeY(DOWN);
refresh = true;
break;
default:
break;
}
switch (horizontalMovement) {
case RIGHT:
s2.changeX(RIGHT);
refresh = true;
break;
case LEFT:
s2.changeX(LEFT);
refresh = true;
break;
default:
break;
}
if (refresh == true) {
pane.repaint();
}
}
});
I transferred a few programs from a computer at my school(a mac) at school to my home pc. Once on my computer, I noticed the keys now do not work in each program. I've spent hours try to figure out why KeyPressed isn't working. Both computers used Eclipse
Is it because of different Java version or because of a different OS?
Thank you!
example of code:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.text.DecimalFormat;
import java.util.Random;
import javax.swing.JApplet;
public class Skeleton extends JApplet implements Runnable, MouseMotionListener, MouseListener, KeyListener {
Random generator = new Random();
boolean GameRunning = true, PlayAgain = true;
int width, height;
int score = 0;
Image offscreenImage;
int XX;
int XY;
Image Cart;
Image candy[];
int candyX[];
int candyY[];
boolean up = false, down = false, left = false, right = false;
boolean candyRemaining[];
Graphics offscr;
Random r;
Thread t;
boolean inBounds = true;
boolean onScreen = true;
Image Title;
boolean hasStarted = false;
public Skeleton() {
r = new Random();
t = new Thread(this);
t.start();
}
public void init() {
XX = 0;
XY = 0;
candy = new Image[3];
candyRemaining = new boolean[3];
candyY = new int[3];
candyX = new int[3];
addKeyListener(this);
addMouseMotionListener(this);
addMouseListener(this);
setVisible(true);
setSize(500, 500);
width = getSize().width;
height = getSize().height;
Title = getImage(getCodeBase(), "BKG.png");
offscreenImage = createImage(width, height);
// offscr = offscreenImage.getGraphics();
Cart = getImage(getCodeBase(), "Untitled-1.png");
candy[0] = getImage(getCodeBase(), "candy1.png");
candy[1] = getImage(getCodeBase(), "candy2.png");
candy[2] = getImage(getCodeBase(), "candy3.png");
candyRemaining[0] = true;
candyRemaining[1] = true;
candyRemaining[2] = true;
candyX[0] = 100;
candyX[1] = 300;
candyX[2] = 400;
candyY[0] = 425;
candyY[1] = 0;
candyY[2] = 210;
}
public void paint(Graphics g) {
super.paint(g);
DecimalFormat df = new DecimalFormat("0.00");
Random generator = new Random();
if (hasStarted) {
if (inBounds) {
g.drawImage(Cart, XX, XY, this);
this.Candy(g);
if (left) {
XX -= 5;
if (XX < 0) {
XX += 5;
}
}
if (right) {
XX += 5;
if (XX > 500) {
XX -= 5;
}
}
if (down) {
XY += 5;
if (XX > 500) {
XY -= 5;
}
}
if (up) {
XY -= 5;
if (XY < 0) {
XY += 5;
}
}
} else {
GameRunning = false;
}
} else {
g.drawImage(Title, 0, 0, this);
}
}
public void Candy(Graphics g) {
for (int count = 0; count < 3; count++) {
if (candyRemaining[count]) {
g.drawImage(candy[count], candyX[count], candyY[count], this);
if (candyX[count] < XX + 50 && candyX[count] + 50 > XX) {
if (candyY[count] < XY + 50 && candyY[count] + 50 > XY) {
System.out.println(count);
candyRemaining[count] = false;
}
}
}
}
}
public void update(Graphics g) {
paint(g);
}
public void run() {
while (PlayAgain == true) {
while (GameRunning == true) {
repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
};
}
if (GameRunning == false) {
}
}
}
public void mouseDragged(MouseEvent ev) {
}
public void mouseMoved(MouseEvent ev) {
}
public void mouseClicked(MouseEvent ev) {
if (!hasStarted) {
hasStarted = true;
}
if (GameRunning == false) {
if (ev.getX() > 0 && ev.getX() < 1000 && ev.getY() > 0 && ev.getY() < 1000) {
GameRunning = true;
}
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
onScreen = true;
inBounds = true;
}
public void mouseExited(MouseEvent ev) {
onScreen = false;
inBounds = false;
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Pressed");
int key = e.getKeyCode();
if (key == e.VK_A) {
left = true;
}
if (key == e.VK_D) {
right = true;
}
if (key == e.VK_S) {
down = true;
}
if (key == e.VK_W) {
up = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("Released");
int key = e.getKeyCode();
if (key == e.VK_A) {
left = false;
}
if (key == e.VK_D) {
right = false;
}
if (key == e.VK_S) {
down = false;
}
if (key == e.VK_W) {
up = false;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Don't use the object e for your keycodes, use the static KeyEvent class. In addition your code will look prettier if you use a switch statement instead of if statements:
switch (e.getKeyCode()) {
case KeyEvent.VK_A: // here's the change
left = true;
break;
For comparing the keypressed or released you are using the current KeyEvent class's object.
As everytime the key is pressed the new KeyEvent object is created and for keypressed you are checking with the current object which doesn't hold the keyvalue, it just hold's that which key was pressed.
So to check refer to the static variables of the KeyEvent Class.
switch(e.getKeyCode){
case: KeyEvent.VK_A;
Left =false;
break;
case: KeyEvent.VK_D;
right=false;
break;
.
.
.
.
}
KeyListener is nutritiously fickle about focus. A KeyListener can only be notified of key events when the component is focusable and has focus
The short answer would be to use
setFocusable(true);
requestFocusInWindow();
at the end of the init method
The more appropriate answer would be to use key bindings API, which provides you with the ability to control the level of focus required in order to generate key events
As a side note, it would be more appropriate to use something like a JPanel and override it's paintComponent and use it as the primary gaming component instead of the JApplet, which isn't double buffered and can flash when it's updated...
You should also move you gaming logic out of your paint method and probably into you main gaming loop (or called from your gaming loop). A paint cycle could be called at any time, many times outside of your control, which could effect your output.
I also doubt you need 500fps, Thread.sleep(40); or even Thread.sleep(16); will probably give you far more stable results
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.