Created
May 29, 2019 22:56
-
-
Save cjgunnar/6b998207fa78df46ff887ca230534d44 to your computer and use it in GitHub Desktop.
Move a dot around the screen over an image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Graphics; | |
import java.awt.Image; | |
import java.awt.Rectangle; | |
import java.awt.event.KeyAdapter; | |
import java.awt.event.KeyEvent; | |
import java.awt.image.ImageObserver; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.ConcurrentModificationException; | |
import javax.imageio.ImageIO; | |
import javax.swing.ImageIcon; | |
import javax.swing.JPanel; | |
/** | |
* Contains sprites and game logic | |
* @author cjgunnar | |
* | |
*/ | |
@SuppressWarnings("serial") | |
public class GameBoard extends JPanel implements Runnable | |
{ | |
//CAMERA RELATED VARS | |
int WORLD_SIZE_X; | |
int WORLD_SIZE_Y; | |
int MAX_OFFSET_X; | |
int MAX_OFFSET_Y; | |
/** Time between frames (ms) */ | |
final static int FRAME_DELAY = 2; | |
private Thread thread; | |
/** List of all the sprites */ | |
ArrayList<Sprite> sprites; | |
/** The background of the game */ | |
Image bg; | |
/** The player */ | |
Player player; | |
/** Create the Board */ | |
public GameBoard() | |
{ | |
createSprites(); | |
// D:\\workspace\\TopDownScroller\\Images\\maze_1.png | |
bg = new ImageIcon(this.getClass().getResource("/maze_1.png")).getImage(); | |
bg = bg.getScaledInstance(4004, 4004, Image.SCALE_FAST); | |
WORLD_SIZE_X = bg.getWidth(new ImageObserver() | |
{ | |
@Override | |
public boolean imageUpdate(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5) | |
{ | |
// TODO Auto-generated method stub | |
return false; | |
}}); | |
WORLD_SIZE_Y = bg.getHeight(new ImageObserver() | |
{ | |
@Override | |
public boolean imageUpdate(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5) | |
{ | |
// TODO Auto-generated method stub | |
return false; | |
}}); | |
//add the input handler to listen for keys | |
addKeyListener(new InputHandler()); | |
//allow the board to listen to key events | |
setFocusable(true); | |
} | |
/** Create all the sprites */ | |
private void createSprites() | |
{ | |
sprites = new ArrayList<Sprite>(); | |
player = new Player(50, 50); | |
sprites.add(player); | |
} | |
@Override | |
public void paintComponent(Graphics g) | |
{ | |
super.paintComponent(g); | |
//CALCULATE CAM POSITION | |
int camX = player.getX() - getWidth() / 2; | |
int camY = player.getY() - getHeight() / 2; | |
MAX_OFFSET_X = WORLD_SIZE_X - getWidth(); | |
MAX_OFFSET_Y = WORLD_SIZE_Y - getHeight(); | |
//adjust cam position to not go off screen | |
if(camX > MAX_OFFSET_X) | |
camX = MAX_OFFSET_X; | |
else if(camX < 0) | |
camX = 0; | |
if(camY > MAX_OFFSET_Y) | |
camY = MAX_OFFSET_Y; | |
else if (camY < 0) | |
camY = 0; | |
//center viewport with cam data | |
g.translate(-camX, -camY); | |
//draw background | |
g.drawImage(bg, 0, 0, null); | |
try | |
{ | |
//draw all the sprites | |
for(Sprite sprite: sprites) | |
if(sprite.isVisible()) | |
sprite.draw(g); | |
} | |
catch(ConcurrentModificationException e) | |
{ | |
//do nothing | |
} | |
} | |
/** Checks all sprites in sprite list for intersections and calls onCollision on them */ | |
private void checkCollisions() | |
{ | |
if(sprites == null) {System.out.println("null sprites");} | |
for(Sprite a: sprites) | |
{ | |
Rectangle boundA = a.getBounds(); | |
for(Sprite b: sprites) | |
{ | |
//if is is the same sprite, skip it | |
if(a.equals(b)) | |
continue; | |
Rectangle boundB = b.getBounds(); | |
//if they intersect, call the collision function | |
if(boundA.intersects(boundB)) | |
a.onCollision(b); | |
} | |
} | |
} | |
public void cycle() | |
{ | |
//move everything | |
player.move(); | |
checkCollisions(); | |
//perform game logic | |
} | |
/** | |
* Handles keyboard input to move sprites | |
* @author cjgunnar | |
* | |
*/ | |
private class InputHandler extends KeyAdapter | |
{ | |
/** | |
* CONTROLS | |
* W - UP | |
* A - LEFT | |
* S - DOWN | |
* D - RIGHT | |
*/ | |
final static int UP = KeyEvent.VK_W; | |
final static int DOWN = KeyEvent.VK_S; | |
final static int LEFT = KeyEvent.VK_A; | |
final static int RIGHT = KeyEvent.VK_D; | |
@Override | |
public void keyPressed(KeyEvent e) | |
{ | |
int key = e.getKeyCode(); | |
int speed = 2; | |
//respond to keypress | |
if(key == UP) | |
{ | |
player.setDY(-speed); | |
} | |
else if(key == DOWN) | |
{ | |
player.setDY(speed); | |
} | |
else if(key == LEFT) | |
{ | |
player.setDX(-speed); | |
} | |
else if(key == RIGHT) | |
{ | |
player.setDX(speed); | |
} | |
} | |
@Override | |
public void keyReleased(KeyEvent e) | |
{ | |
int key = e.getKeyCode(); | |
//stop moving when key released | |
if(key == UP) | |
{ | |
player.setDY(0); | |
} | |
else if(key == DOWN) | |
{ | |
player.setDY(0); | |
} | |
else if(key == LEFT) | |
{ | |
player.setDX(0); | |
} | |
else if(key == RIGHT) | |
{ | |
player.setDX(0); | |
} | |
} | |
} | |
@Override | |
public void addNotify() | |
{ | |
super.addNotify(); | |
thread = new Thread(this); | |
thread.start(); | |
} | |
@Override | |
public void run() | |
{ | |
/* | |
* Thread based time allows for the most accurate frame rates | |
* It runs on a infinite loop, but sleeps based on calculated | |
* running times of cycle (the main loop) and | |
* repaint (redraws graphics) | |
* Ends when frame is closed | |
*/ | |
//JOptionPane.showMessageDialog(null, "Press OK to Begin"); | |
long beforeTime, timeDiff, sleep; | |
beforeTime = System.currentTimeMillis(); | |
//broken when Board destroyed (X Button) | |
while(true) | |
{ | |
//run logic proccesses and redraw graphics | |
//may cause ConcurrentModification errors, because the cycle method | |
//will change the sprites list, and the repaint method uses that sprite list | |
//and the repaint method isn't called instatenously | |
cycle(); | |
repaint(); | |
//calculate time between frames | |
timeDiff = System.currentTimeMillis() - beforeTime; | |
sleep = FRAME_DELAY - timeDiff; | |
//catch negative problems | |
if (sleep < 0) | |
{ | |
sleep = 2; | |
} | |
try | |
{ | |
//sleep extra time | |
Thread.sleep(sleep); | |
} | |
catch (InterruptedException e) | |
{ | |
System.out.println("Interrupted: " + e.getMessage()); | |
} | |
//reset before time | |
beforeTime = System.currentTimeMillis(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.EventQueue; | |
import javax.swing.JFrame; | |
import javax.swing.JOptionPane; | |
@SuppressWarnings("serial") | |
public class GameWindow extends JFrame | |
{ | |
static final int WIDTH = 700; | |
static final int HEIGHT = 615; | |
static final String GIT_HUB_REPO = "[none]"; | |
static final String author = "Caden"; | |
static final String title = "Game Window"; | |
static final String instructions = "Click OK to start game.\n" | |
+ "Source code for this project is available at " + GIT_HUB_REPO | |
+ "\nCreated by " + author; | |
public GameWindow() | |
{ | |
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
setSize(WIDTH, HEIGHT); | |
//setResizable(false); | |
setTitle(title); | |
add(new GameBoard()); | |
} | |
public static void main(String[] args) | |
{ | |
//for thread safety | |
EventQueue.invokeLater(new Runnable() | |
{ | |
@Override | |
public void run() | |
{ | |
if(JOptionPane.showConfirmDialog(null, instructions, title, | |
JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) | |
{ | |
return; | |
} | |
JFrame app = new GameWindow(); | |
app.setVisible(true); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Color; | |
import java.awt.Graphics; | |
public class Player extends Sprite | |
{ | |
public Player(int startX, int startY) | |
{ | |
super(startX, startY); | |
this.height = 10; | |
this.width = 10; | |
this.name = "Player"; | |
} | |
@Override | |
public void draw(Graphics g) | |
{ | |
//draw player as red square | |
g.setColor(Color.red); | |
g.fillRect(x, y, width, height); | |
} | |
@Override | |
public void onCollision(Sprite other) | |
{ | |
// TODO Auto-generated method stub | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Graphics; | |
import java.awt.Rectangle; | |
/** | |
* Abstract class of sprites | |
* @author cjgunnar | |
* | |
*/ | |
public abstract class Sprite | |
{ | |
/** Used to identify in collisions */ | |
protected String name; | |
/** Current x pos */ | |
int x; | |
/** Current y pos */ | |
int y; | |
/** Direction of x */ | |
int dx; | |
/** Direction of y */ | |
int dy; | |
/** Height of the sprite */ | |
int height; | |
/** Width of the sprite */ | |
int width; | |
/** Allows sprites do have different "color schemes" that can be set */ | |
int colorMode; | |
/** How fast the Sprite is moving in pixels per frame */ | |
int speed; | |
/** Is the sprite visible? */ | |
protected boolean visible; | |
/** | |
* Create a new Sprite with starting positions (x, y) | |
* @param startX X | |
* @param startY Y | |
*/ | |
public Sprite(int startX, int startY) | |
{ | |
x = startX; | |
y = startY; | |
name = "none"; | |
visible = true; | |
speed = 0; | |
} | |
/** | |
* Draw what the Sprite looks like | |
* @param g Graphics | |
*/ | |
public abstract void draw(Graphics g); | |
/** | |
* Called when this sprite collides with something | |
* @param other the sprite this collided with | |
*/ | |
public abstract void onCollision(Sprite other); | |
public void move() | |
{ | |
//update position | |
x += dx; | |
y += dy; | |
} | |
/** Sets motion to 0 */ | |
public void stop() | |
{ | |
dx = 0; | |
dy = 0; | |
} | |
/** | |
* returns a rectangle representing space taken up by this sprite | |
* @return | |
*/ | |
public Rectangle getBounds() | |
{ | |
return new Rectangle(x, y, width, height); | |
} | |
/** | |
* Set the direction and speed of x | |
* @param dx neg for reverse, use as speed | |
*/ | |
public void setDX(int dx) | |
{ | |
this.dx = dx; | |
} | |
/** | |
* Returns the direction the sprite is moving in on the x-axis | |
* @return direction sprite is moving (x) | |
*/ | |
public int getDX() | |
{ | |
return dx; | |
} | |
/** | |
* Set the direction and speed of y | |
* @param dy neg for reverse, use as speed | |
*/ | |
public void setDY(int dy) | |
{ | |
this.dy = dy; | |
} | |
/** | |
* Gets the direction the sprite is moving on the y-axis | |
* @return direction sprite moving (y) | |
*/ | |
public int getDY() | |
{ | |
return dy; | |
} | |
/** | |
* @return the x | |
*/ | |
public int getX() | |
{ | |
return x; | |
} | |
/** | |
* @param x the x to set | |
*/ | |
public void setX(int x) | |
{ | |
this.x = x; | |
} | |
/** | |
* @return the y | |
*/ | |
public int getY() | |
{ | |
return y; | |
} | |
/** | |
* @param y the y to set | |
*/ | |
public void setY(int y) | |
{ | |
this.y = y; | |
} | |
/** | |
* @return the speed | |
*/ | |
public int getSpeed() | |
{ | |
return speed; | |
} | |
/** | |
* @param speed the speed to set | |
*/ | |
public void setSpeed(int speed) | |
{ | |
this.speed = speed; | |
} | |
/** | |
* @return the height | |
*/ | |
public int getHeight() | |
{ | |
return height; | |
} | |
/** | |
* @param height the height to set | |
*/ | |
public void setHeight(int height) | |
{ | |
this.height = height; | |
} | |
/** | |
* @return the width | |
*/ | |
public int getWidth() | |
{ | |
return width; | |
} | |
/** | |
* @param width the width to set | |
*/ | |
public void setWidth(int width) | |
{ | |
this.width = width; | |
} | |
/** | |
* @return the visible | |
*/ | |
public boolean isVisible() | |
{ | |
return visible; | |
} | |
/** | |
* @param visible the visible to set | |
*/ | |
public void setVisible(boolean visible) | |
{ | |
this.visible = visible; | |
} | |
/** | |
* Sets the name of the sprite | |
* @param name Name to set | |
*/ | |
public void setName(String name) | |
{ | |
this.name = name; | |
} | |
/** | |
* Gets the name of the sprite | |
* @return the name of the sprite | |
*/ | |
public String getName() | |
{ | |
return name; | |
} | |
/** | |
* @return the colorMode | |
*/ | |
public int getColorMode() | |
{ | |
return colorMode; | |
} | |
/** | |
* @param colorMode the colorMode to set | |
*/ | |
public void setColorMode(int colorMode) | |
{ | |
this.colorMode = colorMode; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment