Make this code more Object-Oriented? - java

I've been told by my friend that my code isn't very OO. How would I make this more OO and reusable?
I tried making a class called level, that printed the images in level, but noting printed, so that didn't work.
(code dump coming, I'm sorry)
public class Main extends Applet implements Runnable, KeyListener,
java.awt.event.MouseListener {
double x_pos = 300;
double y_pos = 200;
int radius = 20;
int appletsize_x = 640;
int appletsize_y = 440;
double speed = 3;
float speedModifier = 1f;
Image grass;
Image hero;
Image hero45;
Image hero90;
Image hero135;
Image hero180;
Image hero225;
Image hero270;
Image hero315;
Image sprite;
Image tree;
Image path;
private boolean leftPressed;
private boolean rightPressed;
private boolean downPressed;
private boolean upPressed;
private Image dbImage;
private Graphics dbg;
public void init() {
Dimension dim = getMaximumSize();
this.setSize(appletsize_x, appletsize_y);
MediaTracker mt = new MediaTracker(this);
tree = getImage(getCodeBase(), "tree_64.png");
grass = getImage(getCodeBase(), "grassTile.png");
path = getImage(getCodeBase(), "path.png");
hero = getImage(getCodeBase(), "hero.png");
hero45 = getImage(getCodeBase(), "hero45.png");
hero90 = getImage(getCodeBase(), "hero90.png");
hero135 = getImage(getCodeBase(), "hero135.png");
hero180 = getImage(getCodeBase(), "hero180.png");
hero225 = getImage(getCodeBase(), "hero225.png");
hero270 = getImage(getCodeBase(), "hero270.png");
hero315 = getImage(getCodeBase(), "hero315.png");
sprite = getImage(getCodeBase(), "hero.png");
mt.addImage(hero, 0);
mt.addImage(path, 0);
mt.addImage(tree, 0);
mt.addImage(grass, 0);
mt.addImage(hero45, 0);
mt.addImage(hero90, 0);
mt.addImage(hero135, 0);
mt.addImage(hero180, 0);
mt.addImage(hero225, 0);
mt.addImage(hero270, 0);
try {
mt.waitForID(0);
} catch (InterruptedException ie) {
}
}
public void start() {
this.addKeyListener(this);
this.addMouseListener(this);
Thread th = new Thread(this);
th.start();
}
public void stop() {
}
public void destroy() {
}
public void run() {
// lower ThreadPriority
this.requestFocusInWindow();
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) {
if (downPressed && leftPressed) {
double y_decr, x_incr;
y_decr = Math.sqrt(Math.pow(speed, 2)) / 1.5;
x_incr = Math.sqrt(Math.pow(speed, 2)) / 1.5;
y_pos += y_decr;
x_pos -= x_incr;
} else if (downPressed && rightPressed) {
y_pos += Math.sqrt(Math.pow(speed, 2)) / 1.5;
x_pos += Math.sqrt(Math.pow(speed, 2)) / 1.5;
} else if (upPressed && rightPressed) {
y_pos -= Math.sqrt(Math.pow(speed, 2)) / 1.5;
x_pos += Math.sqrt(Math.pow(speed, 2)) / 1.5;
} else if (upPressed && leftPressed) {
y_pos -= Math.sqrt(Math.pow(speed, 2)) / 1.5;
x_pos -= Math.sqrt(Math.pow(speed, 2)) / 1.5;
} else {
// Hitting (right)
if (x_pos > this.getSize().width - radius) {
// x_speed = -x_speed;
}
if (leftPressed == true) {
x_pos -= speed * speedModifier;
}
if (rightPressed == true) {
x_pos += speed * speedModifier;
}
if (upPressed == true) {
y_pos -= speed * speedModifier;
}
if (downPressed == true) {
y_pos += speed * speedModifier;
}
}
// Hitting right
if (x_pos > this.getSize().width - 32) {
x_pos = this.getSize().width - 32;
} // Hitting left
if (x_pos < 0) {
x_pos = 0;
}
// } // Hitting top
if (y_pos < 0) {
y_pos = 0;
}
// Hitting bottom
if (y_pos > this.getSize().height - 32) {
y_pos = this.getSize().height - 32;
}
repaint();
try {
// Stop thread for 1 milliseconds
Thread.sleep(20);
} catch (InterruptedException ex) {
// do nothing
}
// set ThreadPriority to maximum value
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
}
}
public void paint(Graphics g) {
int layout = 0;
int coll = 0;
while (coll <= 440) {
drawRows(layout, grass, g, coll);
coll = coll + 32;
}
drawCollums(0, path, g, 180);
g.drawImage(tree, 50, 40, this);
g.drawImage(tree, 300, 20, this);
g.drawImage(tree, 500, 300, this);
int x_posI = (int) x_pos;
int y_posI = (int) y_pos;
if (downPressed && leftPressed) {
this.sprite = hero225;
} else if (downPressed && rightPressed) {
this.sprite = hero135;
} else if (upPressed && rightPressed) {
this.sprite = hero45;
} else if (upPressed && leftPressed) {
this.sprite = hero315;
} else if (leftPressed == true) {
this.sprite = hero270;
} else if (rightPressed == true) {
this.sprite = hero90;
} else if (upPressed == true) {
this.sprite = hero;
} else if (downPressed == true) {
this.sprite = hero180;
}
// this.sprite will contain value set on last "movement"
g.drawImage(this.sprite, x_posI, y_posI, this);
}
public void update(Graphics g) {
if (dbImage == null) {
dbImage = createImage(this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics();
}
dbg.setColor(getBackground());
dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);
dbg.setColor(getForeground());
paint(dbg);
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
leftPressed = true;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
rightPressed = true;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
upPressed = true;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
downPressed = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
leftPressed = false;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
rightPressed = false;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
upPressed = false;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
downPressed = false;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("HIT!");
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void drawRows(int x, Image image, Graphics g, int coll) {
while (x <= appletsize_x) {
g.drawImage(image, x, coll, this);
x += 32;
}
}
public void drawCollums(int y, Image image, Graphics g, int coll) {
while (y <= appletsize_x) {
g.drawImage(image, coll, y, this);
y += 32;
}
}
}

You should ask your friend what he or she meant. If I were to guess, I would say that your Applet class is doing a lot of things: it's the animation loop; it's the key handler; it's the mouse handler; it's the UI. Those could be broken out into separate objects that were designed to work together.
Another improvement might be to translate your four ...Pressed flags into an integer from 0 through 7, representing the eight possible directions. For instance:
0 1 2
7 3
6 5 4
(You can assign the direction numbers any way you like.) Then you could use the direction number to index into an array of images. (This has nothing to do with being object-oriented, but it would simplify your code.)

Well for one thing, all those images should be in an array. And they should contain a filename so you can load them in a nice loop. You have over 3 pages of copy&paste code, that's absolutely horrible... What if you want to change the way they get loaded slightly?
Then, Math.sqrt(Math.pow(speed, 2)) jumps out at me. That's the equivalent of Math.abs(speed), and about 1/200x as fast.
This next part is particularly funny too. I won't comment on whether or not it's needed (and it most likely isn't, it's a design flaw on your part), but.. ya..
// Stop thread for 1 milliseconds
Thread.sleep(20);

I'd suggest you read books and article about OOP and in this particular case you should take a look at the MVC pattern (MVC article in wikipedia). For a good OO conception the events (keyPressed(KeyEvent e) for example) shouldn't be treated in the same class as the actual "graphics building" class.

Build a new package for your application and group all your data structures inside. Create a class for Your Hero, create classes for trees and grass. See how they can share attributes and create a class hierarchy, maybe with an abstract class.
These are just a few cues, it could be long to give you an Object Oriented course here ;)
But follows this tracks and read.
Also, you should learn how to stop threads elegantly.
And you could use inner classes for your listeners, even use a MouseAdater.
Regards,
Stéphane

You might like to study this game that also moves a player around a grid using the keyboard.

Related

Graphics not moving automatically and also makes copies instead of moving when pressing arrow keys

I'm working on a snake game, and I'm trying to make the snake move to the right. The issue here is the snake isn't actually moving, it just seems to copy itself to the right and also it's not going to the right automatically you have to keep pressing the key.
I am really not sure what the issue is, I made some code without any images. That should make the code run able for testing as it is.
public class Game{
static Graphics g;
public static void main(String[] args) {
JFrame b = new JFrame("Snake");
b.setBounds(300,60,905,700);
b.setBackground(Color.DARK_GRAY);
b.setResizable(false);
Snake snake = new Snake();
b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.add(snake);
b.setVisible(true);
}
}
public class Snake extends JPanel implements KeyListener,ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private int[] snakeXlength = new int [750];
private int[] snakeYlength = new int [750];
private boolean right = true;
private boolean left = false;
private boolean up = false;
private boolean down = false;
private ImageIcon rightmouth;
private ImageIcon snakeimage;
private ImageIcon leftmouth;
private ImageIcon downmouth;
private ImageIcon upmouth;
private ImageIcon enemy;
private Timer timer;
private int snakeDelay = 100;
private int moves = 1;
private int lengtOfSnake = 3;
public Snake(){
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
timer = new Timer(snakeDelay, this);
timer.start();
}
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.drawRect (20, 24, 851, 612);
g.setColor(Color.BLACK);
g.fillRect (21, 25, 850, 610);
if (moves == 0) {
snakeXlength[2]= 63;
snakeXlength[1]= 83;
snakeXlength[0]= 100;
snakeYlength[2]= 100;
snakeYlength[1]= 100;
snakeYlength[0]= 98;
rightmouth = new ImageIcon("rightmouth.png");
rightmouth.paintIcon(this, g, snakeXlength[0], snakeYlength[0]);
}
for(int a = 0; a < lengtOfSnake; a++) {
if (a == 0 && right) {
if (a == 0 && right) {
g.setColor(Color.RED);
g.drawRect(5,10,snakeXlength[a],snakeYlength[a]);
g.fillRect (snakeXlength[a],snakeYlength[a],21,21);
g.drawRect(5,10,snakeXlength[a],snakeYlength[a]);
// rightmouth = new ImageIcon("rightmouth.png");
//rightmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a == 0 && left) {
leftmouth = new ImageIcon("leftmouth.png");
leftmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a == 0 && down) {
downmouth = new ImageIcon("downmouth.png");
downmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a == 0 && up) {
upmouth = new ImageIcon("uptmouth.png");
upmouth.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
if (a != 0) {
g.setColor(Color.GREEN);
g.fillOval(snakeXlength[a],snakeYlength[a],17,17);
//snakeimage = new ImageIcon("snakeimage.png");
//snakeimage.paintIcon(this, g, snakeXlength[a], snakeYlength[a]);
}
}
g.dispose();
}
public void keyPressed(KeyEvent e) {
timer.start();
if(right) {
for (int r = lengtOfSnake-1; r >= 0;r--) {
snakeYlength[r+1] = snakeYlength[r];
}
for(int r = lengtOfSnake;r >=0;r--) {
if(r==0) {
snakeXlength[r] = snakeXlength[r] +25;
}
else {
snakeXlength[r] = snakeXlength[r-1];
}
if(snakeXlength[r] > 850){
snakeXlength[r] = 25;
}
}
repaint();
}
if(left) {
}
if(up) {
}
if(down) {
}
}
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
moves++;
right = true;
if(left != true) {
right = true;
}
else
{
right = false;
left = true;
}
down = false;
up = false;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
moves++;
left = true;
if(right != true) {
left = true;
}
else
{
left = false;
right = true;
}
down = false;
up = false;
} if(e.getKeyCode() == KeyEvent.VK_UP) {
moves++;
up = true;
if(down != true) {
up = true;
}
else
{
up = false;
down = true;
}
left = false;
right = false;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
moves++;
down = true;
if(up != true) {
down = true;
}
else
{
up = true;
down = false;
}
left = false;
right = false;
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
it just seems to copy itself to the right
public void paint(Graphics g)
{
g.setColor(Color.WHITE);
Custom painting should be done by overriding paintComponent(...) and then you need to invoke super.paintComponent(...):
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.WHITE);
This will make sure the background of the panel is cleared before doing the custom painting.
it's not going to the right automatically you have to keep pressing the key.
Well, that is usually the way a game is designed. You only have motion when the key is pressed as this will keep generating events. Then if you don't want motion you just don't press any keys.
If you want animation then you use a Swing Timer. Each time the Timer fires you invoke a move(...) method. This method would need to look at your "direction" variable to determine whether to move the snake left, right, up or down.
Check out:
Motion Using the Keyboard for animation when a key is pressed and held and
get width and height of JPanel outside of the class for continuous animation

How can I create a start screen for my java game? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
How can I make my applet so it goes to a start page and then to the game? So there is a Start Button, a Exit Button, and when I click the Start only then the game starts. Please answer in simple terms if possible since I am a beginner. Thanks :)
Main.java
import java.awt.Graphics;
public class Main extends GameLoop {
/**
*
*/
private static final long serialVersionUID = 1L;
public void init(){
setSize(960,540);
Thread th = new Thread(this);
th.start();
offscreen = createImage(960,540);
c = offscreen.getGraphics();
addKeyListener(this);
}
public void paint(Graphics g)
{
c.clearRect(0,0,960,480);
c.drawImage(background, 0, 0, this);
c.drawImage(mario, x, y, 100, 100, this);
c.drawImage(goomba, ax, ay, 30, 30, this);
c.drawImage(foreground, 0, 0 , this );
c.drawImage(pipes, 0, 0, this);
c.drawImage(block1, 0, 0, this);
c.drawImage(block2, 0, 0, this);
c.drawImage(block3, 0, 0, this);
c.drawImage(block4, 0, 0, this);
c.drawImage(block5, 0, 0, this);
c.drawImage(block6, 0, 0, this);
c.drawImage(block7 , 0, 0, this);
//c.drawImage(blocks, 0, 0, this);
g.drawImage(offscreen, 0 , 0 ,this);
}
#Override
public void update(Graphics g){
paint(g);
}
}
GameLoop.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class GameLoop extends Applet implements Runnable, KeyListener {
/**
*
*/
private static final long serialVersionUID = 1L;
public int x,y,ax,ay;
public Image offscreen;
public Graphics c;
public boolean jump,down,right,left;
public BufferedImage background, foreground, pipes, blocks, block1, block2, block3, block4, block5, block6, block7, walk2, walk3, walk4, walk5, walk6, jumpR,jumpL, mario, goomba, deadMario, money, block;
public BufferedImage Bblock1, Bblock2, Bblock3;
public int wow;
public int wow2;
public double counter = 4;
public int MaxH, MidH, MinH, delta;
#Override
public void run() {
x = 60;
y = 440;
ax = x +5;
ay = 493;
MinH = 440;
try {
background = ImageIO.read(new File("resources/background1.png"));
foreground = ImageIO.read(new File("resources/foreground1.png"));
blocks = ImageIO.read(new File("resources/blocks1.png"));
pipes = ImageIO.read(new File("resources/pipes1.png"));
walk2 = ImageIO.read(new File("resources/walk2.png"));
walk3 = ImageIO.read(new File("resources/walk3.png"));
walk4 = ImageIO.read(new File("resources/walk4.png"));
walk5 = ImageIO.read(new File("resources/walk5.png"));
walk6 = ImageIO.read(new File("resources/walk6.png"));
jumpR = ImageIO.read(new File("resources/jumpR.png"));
jumpL = ImageIO.read(new File("resources/jumpL.png"));
goomba = ImageIO.read(new File("resources/goomba.gif"));
deadMario = ImageIO.read(new File("resources/deadmario.png"));
money = ImageIO.read(new File("resources/money.png"));
block = ImageIO.read(new File("resources/Block.png"));
block1 = ImageIO.read(new File("resources/block1.png"));
block2 = ImageIO.read(new File("resources/block2.png"));
block3 = ImageIO.read(new File("resources/block3.png"));
block4 = ImageIO.read(new File("resources/block4.png"));
block5 = ImageIO.read(new File("resources/block5.png"));
block6 = ImageIO.read(new File("resources/blocks6.png"));
block7 = ImageIO.read(new File("resources/block7.png"));
Bblock1 = ImageIO.read(new File("resources/Bblock1.png"));
Bblock2 = ImageIO.read(new File("resources/Bblock2.png"));
Bblock3 = ImageIO.read(new File("resources/Bblock3.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
mario = walk2;
while(true)
{
if (y <=440&& jump != true){
y += 5;
}
if (y <=175){
y = MinH;
}
if(ax != 475 && ax < 475){
ax++;
}
if(ax >= 475 && ax != 60){
ax = ax - 475;
repaint();
}
if(x >= 468 && x <= 546){
y=385;
}
if(x >= 736 && x <= 826){
y=355;
}
if(x >= 160 && x <= 200 && y < 440 && y > 400){
y = MinH;
block1 = block;
}
if(x >= 264 && x <= 338 && y < 440 && y > 400){
y = MinH;
block3 = Bblock1;
}
if(x >= 339 && x <=410 && y < 440 && y > 400){
y = MinH;
block5 = Bblock2;
}
if (block1 == block && y >= 440){
c.drawImage(money, 210, 332,30,20, this);
}
if (block3 == Bblock1 && y >= 440){
c.drawImage(money, 337, 332,30,30, this);
}
if (block5 == Bblock2 && y >= 440){
c.drawImage(money, 395, 332,30,30, this);
}
wow++;
wow2++;
if(wow >= 20){
wow = 0;
}
if(wow <= 5 && right == true){
mario = walk2;
}
if(wow >= 5 && wow <=10 && right == true){
mario = walk2;
}
if(wow <= 10 && wow >=5 && right == true){
mario = walk5;
}
if(wow >= 10 && wow <=5 &&right == true){
mario = walk2;
}
if(wow2 >= 20){
wow2 = 0;
}
if(wow2 <= 5 && left == true){
mario = walk3;
}
if(wow2 >= 5 && left == true){
mario = walk6;
}
if(wow2 <= 10 && wow >=5 && left == true){
mario = walk6;
}
if(wow2 >= 10 && wow <=5 && left == true){
mario = walk3;
}
if(left == true){
x-=2;
}
if(right == true){
x+=2;
}
if(jump == true){
counter += 0.1;
y = y + (int) ((Math.sin(counter ) + Math.cos(counter))*15.5);
}
if(counter == 7){
counter = 4;
}
if(down == true){
y+=2;
}
if(y >= MinH ){
y = MinH;
}
System.out.println("(" + x + "," + y + ")");
repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void keyTyped(KeyEvent e) {
// don't use
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 37 ){
left = true;
}
if(e.getKeyCode() == 38){
jump = true;
mario = jumpR;
}
if(e.getKeyCode() == 39){
right = true;
}
if(e.getKeyCode() == 40){
down = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 37){
left = false;
mario = walk3;
}
if(e.getKeyCode() == 38){
jump = false;
mario = walk2;
counter = 4;
}
if(e.getKeyCode() == 39){
right = false;
mario = walk2;
}
if(e.getKeyCode() == 40){
down = false;
mario = walk2;
}
}
}
You need to keep up with states. For example you would have a START state and a RUNNING state. If the game is in the START state then you would draw the start screen, if it's in the RUNNING state you would draw your game. Later you may have a PAUSE state and a GAME_OVER state so you can show different screens there.
So to do this you will need a State enum like this:
public enum State
{
START, RUNNING, PAUSE, GAME_OVER;
}
Then in your GameLoop class create a variable to hold the current state.
private State state = State.START;
Then in your draw code and anywhere else necessary you can check the current state variable and draw the appropriate screen.
public void run()
{
switch(state)
{
case START:
//DRAW THE START SCREEN
break;
case RUNNING:
//DRAW THE GAME
break;
case PAUSE:
//DRAW THE PAUSE SCREEN
break;
case GAME_OVER:
//DRAW THE GAME OVER SCREEN
break;
default:
throw new RuntimeException("Unknown state: " + state);
}
}
A more clean solution would be to have a Screen class that has a draw method. Then your GameLoop just looks up the Screen associated with a given State and calls the draw method on it. This way your drawing code stays neatly tucked in to each Screen instead of all blobbed into one place. As your number of Screens grow you just add another Screen implementation. Here is some code to show what I mean:
Here is a Screen interface. You will have a Screen implementation for each State.
public interface Screen
{
void update();
void draw();
void handleInput();
}
Here is an empty example of a RunningScreen.
public class RunningScreen implements Screen
{
#Override
public void update()
{
//UPDATE LOGIC, MOVE ENTITIES OR WHATEVER
}
#Override
public void draw()
{
//DRAW THE RUNNING SCREEN
}
#Override
public void handleInput()
{
//CHECK FOR USER INPUT AND UPDATE THE SCREEN STATE
}
}
Here is an empty example of a StartScreen.
public class StartScreen implements Screen
{
#Override
public void update()
{
//UPDATE THE START SCREEN
}
#Override
public void draw()
{
//DRAW THE START SCREEN
}
#Override
public void handleInput()
{
//CHECK FOR INPUT, TRANSITION TO THE RUNNING SCREEN WHEN THE USER CLICKS START
}
}
Your game loop looks up the Screen that is registered to handle the current state, then calls the appropriate methods.
public class GameLoop
{
private State state = State.START;
private Map<State, Screen> screens = new HashMap<>();
public void addScreen(State state, Screen screen)
{
screens.put(state, screen);
}
public void run()
{
Screen screen = screens.get(state);
screen.handleInput();
screen.update();
screen.draw();
}
}
Then your Main might look something like this. It creates a new GameLoop and registers the Screens for each state.
public class Main
{
public static void main(String[] args)
{
GameLoop game = new GameLoop();
game.addScreen(State.START, new StartScreen());
game.addScreen(State.RUNNING, new RunningScreen());
//Add other states here
game.run();
}
}
I hope this gives you some ideas about how to implement the functionality you want.

Java call function in a loop without stackoverflowerror

I know I have asked a question like this before, but none of the answers in the old question worked for me. I am trying to make a little single-player pong game (It is in a Java applet). I already have a moveBall() function, as you can see below. But I don't know where to call it. I can't call it in the paint() method because it is double buffered.
public class Main extends Applet implements KeyListener, MouseListener {
private Rectangle paddle;
private Rectangle ball;
private ArrayList<Integer> keysDown;
private Image dbImage;
private Graphics dbg;
public int time = 300000;
Random randomGenerator = new Random();
int speed = 10;
int level = 1; // change to 0 once start menu works
int xpos, ypos;
int ballx, bally;
int width = 1024;
int height = 768;
int paddleWidth = 96;
int ballSize = 16;
String version = "0.0.1";
public static final int START_X_POS = 160;
public static final int START_Y_POS = 160;
public static final int START_WIDTH = 256;
public static final int START_HEIGHT = 64;
boolean startClicked;
boolean falling = true;
public void init() {
setSize(width, height);
addKeyListener(this);
addMouseListener(this);
setBackground(Color.black);
Frame c = (Frame)getParent().getParent();
c.setTitle("Asteroid Attack - Version " + version);
keysDown = new ArrayList<Integer>();
paddle = new Rectangle(getWidth()/2-paddleWidth, getHeight()-96, paddleWidth, 12);
ball = new Rectangle(getWidth()/2-ballSize, 96, ballSize, ballSize);
}
public void update(Graphics g) {
dbImage = createImage(getSize().width, getSize().height);
dbg = dbImage.getGraphics ();
if (dbImage == null) {}
dbg.setColor(getBackground ());
dbg.fillRect(0, 0, getSize().width, getSize().height);
dbg.setColor(getForeground());
paint(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
if (level != 0) {
g2.setPaint(Color.gray);
g2.fill(paddle);
g2.setPaint(Color.darkGray);
g2.fill(ball);
moveBall();
}
}
public void moveBall() {
bally = ball.y;
ballx = ball.x;
if (bally < paddle.y-32 && falling) {
bally += 12;
}
if (bally < paddle.y-32 && falling && paddle.x <= ballx && paddle.getMaxX() >= ball.x) { // collides with paddle
falling = false;
}
else { // does not collide with paddle
}
ball.setLocation(ballx, bally);
}
#Override
public void keyPressed(KeyEvent e) {
if (!keysDown.contains(e.getKeyCode()))
keysDown.add(new Integer(e.getKeyCode()));
key();
}
#Override
public void keyReleased(KeyEvent e) {
keysDown.remove(new Integer(e.getKeyCode()));
}
public void key() {
if (level != 0) {
int x = paddle.x;
int y = paddle.y;
if (keysDown.contains(KeyEvent.VK_ESCAPE)) {System.exit(0);}
if (x > 0 && x+paddleWidth < this.getWidth()) {
if (keysDown.contains(KeyEvent.VK_LEFT)) {x -= speed;}
if (keysDown.contains(KeyEvent.VK_RIGHT)) {x += speed;}
}
else { // so paddle doesn't exit room
if (x <= 0) {x += 4;}
else {x -= 4;}
}
paddle.setLocation(x, y);
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void mouseClicked(MouseEvent me) {
if (level == 0) {
xpos = me.getX();
ypos = me.getY();
if (xpos >= START_X_POS && ypos >= START_Y_POS && xpos <= START_X_POS + START_WIDTH && ypos <= START_X_POS + START_HEIGHT ) {
level = 1;
}
}
}
#Override
public void mouseEntered(MouseEvent me) {}
#Override
public void mouseExited(MouseEvent me) {}
#Override
public void mouseReleased(MouseEvent me) {}
#Override
public void mousePressed(MouseEvent me) {}
}
Any help would be greatly appreciated!
You'll probably want a separate Thread to move the ball which keeps track of time while in a in a loop - that way if frame rates drop, or speed up, you can try ensure consistency in the ball movement speed.
e.g. here on using a thread in a applet http://www.realapplets.com/tutorial/threadexample.html

SubKiller game not firing properly when press my fire key

I have the following program, it's a SubKiller game and I have one question. How do I make the boat launch the bomb anytime I press the down key? So far I have made to launch it multiple times. I can launch the first bomb but when I'm trying to launch the second one, the first one disappears and it doesn't continue it's way. I am stuck on this matter for almost two days, help me please.
I am going to provide you the SSCCE code.
This is the class called SubKillerPanel, basically everything is here, the boat is here, the bomb is here, the submarine is here.
import java.awt.event.*;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Color;
public class SubKillerPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Timer timer;
private int width, height;
private Boat boat;
private Bomb bomb;
private Submarine sub;
public SubKillerPanel() {
setBackground(Color.WHITE);
ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (boat != null) {
boat.updateForNewFrame();
bomb.updateForNewFrame();
sub.updateForNewFrame();
}
repaint();
}
};
timer = new Timer( 20, action );
addMouseListener( new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
requestFocus();
}
}
);
addFocusListener( new FocusListener() {
public void focusGained(FocusEvent evt) {
timer.start();
repaint();
}
public void focusLost(FocusEvent evt) {
timer.stop();
repaint();
}
}
);
addKeyListener( new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
int code = evt.getKeyCode(); // ce tasta a fost apasata
if (code == KeyEvent.VK_LEFT) {
boat.centerX -= 15;
}
else
if (code == KeyEvent.VK_RIGHT) {
boat.centerX += 15;
}
else
if (code == KeyEvent.VK_DOWN) {
if (bomb.isFalling == false)
bomb.isFalling = true;
bomb.centerX = boat.centerX;
bomb.centerY = boat.centerY;
}
}
}
);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (boat == null) {
width = getWidth();
height = getHeight();
boat = new Boat();
sub = new Submarine();
bomb = new Bomb();
}
if (hasFocus())
g.setColor(Color.CYAN);
else {
g.setColor(Color.RED);
g.drawString("CLICK TO ACTIVATE", 20, 30);
g.setColor(Color.GRAY);
}
g.drawRect(0,0,width-1,height-1);
g.drawRect(1,1,width-3,height-3);
g.drawRect(2,2,width-5,height-5);
boat.draw(g);
sub.draw(g);
bomb.draw(g);
}
private class Boat {
int centerX, centerY;
Boat() {
centerX = width/2;
centerY = 80;
}
void updateForNewFrame() {
if (centerX < 0)
centerX = 0;
else
if (centerX > width)
centerX = width;
}
void draw(Graphics g) {
g.setColor(Color.blue);
g.fillRoundRect(centerX - 40, centerY - 20, 80, 40, 20, 20);
}
}
private class Bomb {
int centerX, centerY;
boolean isFalling;
Bomb() {
isFalling = false;
}
void updateForNewFrame() {
if (isFalling) {
if (centerY > height) {
isFalling = false;
}
else
if (Math.abs(centerX - sub.centerX) <= 36 && Math.abs(centerY - sub.centerY) <= 21) {
sub.isExploding = true;
sub.explosionFrameNumber = 1;
isFalling = false; // Bomba reapare in barca
}
else {
centerY += 10;
}
}
}
void draw(Graphics g) {
if ( !isFalling ) {
centerX = boat.centerX;
centerY = boat.centerY + 23;
}
g.setColor(Color.RED);
g.fillOval(centerX - 8, centerY - 8, 16, 16);
}
}
private class Submarine {
int centerX, centerY;
boolean isMovingLeft;
boolean isExploding;
int explosionFrameNumber;
Submarine() {
centerX = (int)(width*Math.random());
centerY = height - 40;
isExploding = false;
isMovingLeft = (Math.random() < 0.5);
}
void updateForNewFrame() {
if (isExploding) {
explosionFrameNumber++;
if (explosionFrameNumber == 30) {
centerX = (int)(width*Math.random());
centerY = height - 40;
isExploding = false;
isMovingLeft = (Math.random() < 0.5);
}
}
else {
if (Math.random() < 0.04) {
isMovingLeft = ! isMovingLeft;
}
if (isMovingLeft) {
centerX -= 5;
if (centerX <= 0) {
centerX = 0;
isMovingLeft = false;
}
}
else {
centerX += 5;
if (centerX > width) {
centerX = width;
isMovingLeft = true;
}
}
}
}
void draw(Graphics g) {
g.setColor(Color.BLACK);
g.fillOval(centerX - 30, centerY - 15, 60, 30);
if (isExploding) {
g.setColor(Color.YELLOW);
g.fillOval(centerX - 4*explosionFrameNumber, centerY - 2*explosionFrameNumber,
8*explosionFrameNumber, 4*explosionFrameNumber);
g.setColor(Color.RED);
g.fillOval(centerX - 2*explosionFrameNumber, centerY - explosionFrameNumber/2,
4*explosionFrameNumber, explosionFrameNumber);
}
}
}
}
The SubKiller class, where the main method is located.
import javax.swing.JFrame;
public class SubKiller {
public static void main(String[] args) {
JFrame window = new JFrame("Sub Killer Game");
SubKillerPanel content = new SubKillerPanel();
window.setContentPane(content);
window.setSize(700, 700);
window.setLocation(0,0);
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
window.setResizable(false);
window.setVisible(true);
}
}
You only have a single Bomb being tracked by the graphics at any time. You should build a collection of Bombs and instantiate a new one whenever the down key is pressed, then iterate through all the collection of Bombs and draw them as needed.
So, instead of private Bomb bomb;
You would have private List<Bomb> bombs;
Afterwards, anywhere you update the single bomb you can use a for loop to go through the list of bombs and have them all update, and then if they are no longer being drawn, remove them from the list.

PacMan game movement

I am creating a pacman game in Java and I have 1 problem I can't get rid of.. The problem is as follows:
I have 4 buttons in the game screen for each way: up, down, left, right. The problem is that I can not use the buttons in the same time in x position as in the y position because I always get a value of 0 ( you understand this if you see my code below )
Below you can find my class for the pacman that i think is related to the problem ( see setBesturing(int besturing) method )
package h04PacMan;
/*
* PacMan laten bewegen
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PacMan extends JPanel implements ActionListener {
private int horizontalePlaats = 250; // x location
private int verticalePlaats = 150; // y location
private int richtingEnSnelheid = +10; // speed
private final int WACHTTIJD = 500; // DELAY
int diameter;
int waarde;
public PacMan() {
// create timer and start timer
javax.swing.Timer autoKlik = new javax.swing.Timer(WACHTTIJD, this);
autoKlik.start();
}
public int getHorPlaats() {
return horizontalePlaats;
}
// current y positie
public int getVerPlaats() {
return verticalePlaats;
}
// speed and way;
public int getRichtingEnSnelheid() {
return richtingEnSnelheid;
}
// new x position
public void setHorPlaats(int nieuweHorPlaats) {
if(nieuweHorPlaats > getWidth()) {
nieuweHorPlaats = 0;
}
else if(nieuweHorPlaats < 0) {
nieuweHorPlaats = getWidth();
}
horizontalePlaats = nieuweHorPlaats;
}
// new y position
public void setVerPlaats(int nieuweVerPlaats) {
if(nieuweVerPlaats > getHeight()) {
nieuweVerPlaats = 0;
}
else if(nieuweVerPlaats < 0) {
nieuweVerPlaats = getHeight();
}
verticalePlaats = nieuweVerPlaats;
}
public void setRichtingEnSnelheid(int nieuweRichtingEnSnelheid) {
richtingEnSnelheid = nieuweRichtingEnSnelheid;
}
//movement
public void setBesturing(int besturing) {
besturing = waarde;
if(waarde == 0) {
setVerPlaats( getVerPlaats() + richtingEnSnelheid);
}
else if(waarde == 1){
setHorPlaats( getHorPlaats() + richtingEnSnelheid);
}
}
#Override
public void actionPerformed(ActionEvent e) {
setBesturing(waarde);
System.out.println(waarde);
repaint();
}
DrawPacMan pacman = new DrawPacMan();
DrawPacMan ghost1 = new DrawPacMan();
DrawPacMan ghost2 = new DrawPacMan();
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 75;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, Color.yellow);
// ghosts movement
int g1x;
for(g1x = 0; g1x < 10; g1x++) {
pacman.drawGhost(g, g1x, 40, diameter, Color.red);
}
pacman.drawGhost(g, 170, 70, diameter, Color.blue);
}
}
and this is the actionListener in my gamecontrol class
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == links) {
pacman.setRichtingEnSnelheid( -10 );
pacman.setBesturing(1);
System.out.println("links");
}
else if(e.getSource() == rechts) {
pacman.setRichtingEnSnelheid( +10 );
pacman.setBesturing(1);
System.out.println("rechts");
}
else if(e.getSource() == boven) {
pacman.setRichtingEnSnelheid( -10);
pacman.setBesturing(0);
System.out.println("boven");
}
else {
pacman.setRichtingEnSnelheid( +10);
pacman.setBesturing(0);
System.out.println("beneden");
}
}
Here is your problem:
//movement
public void setBesturing(int besturing) {
besturing = waarde; <-- THIS LINE
if(waarde == 0) {
setVerPlaats( getVerPlaats() + richtingEnSnelheid);
}
else if(waarde == 1){
setHorPlaats( getHorPlaats() + richtingEnSnelheid);
}
}
You are overwriting the value of besturing with the old value waarde. It should be the other way around.
//movement
public void setBesturing(int besturing) {
waarde = besturing; <-- THIS LINE
if(waarde == 0) {
setVerPlaats( getVerPlaats() + richtingEnSnelheid);
}
else if(waarde == 1){
setHorPlaats( getHorPlaats() + richtingEnSnelheid);
}
}
I think inside the method setBesturing(int besturing) should be:
waarde = besturing;
In your setBesturing method: -
besturing = waarde;
This line never changes the value of your waarde.. It is always zero.
You should do the assignment the other way : -
this.waarde = besturing;
You'll need to keep track of whether the button is pressed or not indepentently. Also, you're model doesn't support a diagonal movement at all (I'm not sure what your nederlands names exactly mean, i can interprete snelheid=Schnelligkeit=speed and some more).
You'll need to put diagonal movement into the model (e.g. give him an x and y velocity indepent from each other)

Categories

Resources