Skip to content

Instantly share code, notes, and snippets.

@cjgunnar
Created May 29, 2019 22:56
Show Gist options
  • Save cjgunnar/6b998207fa78df46ff887ca230534d44 to your computer and use it in GitHub Desktop.
Save cjgunnar/6b998207fa78df46ff887ca230534d44 to your computer and use it in GitHub Desktop.
Move a dot around the screen over an image
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();
}
}
}
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);
}
});
}
}
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
}
}
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