Add second year

This commit is contained in:
2023-12-07 01:19:12 +00:00
parent 3291e5c79e
commit 3d12031ab8
1168 changed files with 431409 additions and 0 deletions

View File

@ -0,0 +1,56 @@
// package MyApplication;
import java.awt.*;
import javax.swing.*;
public class MyApplication extends JFrame {
private static final Dimension WindowSize = new Dimension(600,600);
public MyApplication() {
// create & set up the window
this.setTitle("Pacman, or something...");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2;
int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
}
public static void main(String[] args) {
MyApplication w = new MyApplication();
}
public void paint(Graphics g) {
int height = 50, width = 50; // defining the height & width of the rectangle
int x = 10, y = 10; // defining the vertical & horizontal position between rectangles
// looping for each of the 10 rows in the window
for (int row = 0; row < 10; row++) {
// looping for each of the 10 columns in the window
for (int column = 0; column < 10; column++) {
// randomly generating an RGB colour & setting the graphic to use it
Color c = new Color((int)(Math.random()*255), (int)(Math.random()*255), (int)(Math.random()*255));
g.setColor(c);
// make a filled rectangle with the specified dimensions at the specified x, y co-ordinates
g.fillRect(x, y, height, width);
// increasing the x by adding the size of a square plus the desired padding
x += width + 10;
}
// resetting the x value to 10 for the next row
x = 10;
// increasing the y by adding the height of a square plus the desired padding
y += height + 10;
}
}
}

View File

@ -0,0 +1,41 @@
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class GameObject {
// member data
private int x, y;
private int height = 50, width = 50;
private Color c;
private int stepSize = 10; // how many pixels the object will move at a time
// constructor
public GameObject() {
// randomly generating colour
c = new Color((int)(Math.random()*255), (int)(Math.random()*255), (int)(Math.random()*255));
// randomly generating initial x y co-ordinates
x = (int)(Math.random()*600);
y = (int)(Math.random()*600);
}
// public interface
public void move() {
// generating either a 1 or a 0 to determine if the square should move left or right and up or down - 1 = left/up, 0 = right/down
int xDirection = (int)(Math.random()*2);
int yDirection = (int)(Math.random()*2);
// changing the x & y co-ordinates by either plus or minus the stepSize, depending on the direction
x += (xDirection == 1) ? -stepSize : + stepSize;
y += (yDirection == 1) ? -stepSize : + stepSize;
}
public void paint(Graphics g) {
// setting colour
g.setColor(c);
// make a filled rectangle with the specified dimensions at the specified x, y co-ordinates
g.fillRect(x, y, height, width);
}
}

View File

@ -0,0 +1,76 @@
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class MovingSquaresApplication extends JFrame implements Runnable {
// window dimensions
private static final Dimension WindowSize = new Dimension(600,600);
// array of gameobjects (squares)
private GameObject gameobjects[] = new GameObject[100];
// constructor
public MovingSquaresApplication() {
// create & set up the window
this.setTitle("Moving Squares Apllication");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2;
int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
// create array of game objects.
//Arrays.fill(gameobjects, 100);
for (int i = 0; i < 100; i++) {
gameobjects[i] = new GameObject();
}
// creating a new thread & starting it
Thread t = new Thread(this);
t.start();
}
// run method called by thread
public void run() {
while (true) {
// iterating over array of gameobjects & calling move() on each object
for (GameObject go : gameobjects) {
go.move();
}
try {
// sleeping
Thread.sleep(100);
// catching exception
} catch (InterruptedException e) {
e.printStackTrace();
}
// repainting now that every object has been moved
this.repaint();
}
}
// paint method
public void paint(Graphics g) {
// filling the screen with a white square between "frames" of animation to get rid of trails caused by moving objects
Color c = new Color(255, 255, 255);
g.setColor(c);
g.fillRect(0, 0, 1000, 1000);
// iterating over each GameObject and calling paint on it
for (GameObject go : gameobjects) {
go.paint(g);
}
}
public static void main(String[] args) {
// instantiating class in main method to begin application
MovingSquaresApplication w = new MovingSquaresApplication();
}
}

View File

@ -0,0 +1,22 @@
import java.awt.*;
import javax.swing.*;
public class Alien extends Sprite2D {
private int stepSize = 5;
public Alien(Image image) {
super(image);
}
// method to randomly move the alien
public void move() {
// generating either a 1 or a 0 to determine if the square should move left or right and up or down - 1 = left/up, 0 = right/down
int xDirection = (int)(Math.random()*2);
int yDirection = (int)(Math.random()*2);
// changing the x & y co-ordinates (inherited from superclass) by either plus or minus the stepSize, depending on the direction
x += (xDirection == 1) ? -stepSize : + stepSize;
y += (yDirection == 1) ? -stepSize : + stepSize;
}
}

View File

@ -0,0 +1,125 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class InvadersApplication extends JFrame implements Runnable, KeyListener {
// member data
private static String workingDirectory = System.getProperty("user.dir");
private Image alienImage;
private Image playerImage;
private static final Dimension WindowSize = new Dimension(600, 600);
private static final int NUMALIENS = 30;
private Alien[] AliensArray = new Alien[NUMALIENS];
private Player player;
// variable to hold how far the player should be moving in the x axis per frame - default 0.
private int dx = 0;
// constructor
public InvadersApplication() {
// set up window
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
// adding a key listener
addKeyListener(this);
// load image from disk
ImageIcon alienIcon = new ImageIcon(workingDirectory + "/alien_ship_1.png");
ImageIcon playerIcon = new ImageIcon(workingDirectory + "/player_ship.png");
alienImage = alienIcon.getImage();
playerImage = playerIcon.getImage();
// instantiating an alien for each index in the aliens array
for (int i = 0; i < NUMALIENS; i++) {
AliensArray[i] = new Alien(alienImage);
// generating a random starting position for the alien
AliensArray[i].setPosition((int) (Math.random()*600), (int) (Math.random()*600));
}
// creating a player icon & setting it's position
player = new Player(playerImage);
player.setPosition(270, 550);
setVisible(true);
// create a new thread & start it
Thread t = new Thread(this);
t.start();
}
// thread's entry point
public void run() {
while (true) {
// repainting
this.repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void keyPressed(KeyEvent e) {
// getting the keycode of the event
int key = e.getKeyCode();
// if right key pressed, making the distance to be moved 10px to the right
if (key == KeyEvent.VK_RIGHT) {
dx = 5;
}
// if left key pressed, making the distance to be moved 10px to the left
if (key == KeyEvent.VK_LEFT) {
dx = -5;
}
}
@Override
public void keyReleased(KeyEvent e) {
// getting the keycode of the event
int key = e.getKeyCode();
// if the key released was the left or right arrow, setting dx back to 0
if (key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_LEFT) {
dx = 0;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
// application's paint method
public void paint(Graphics g) {
// draw a black rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0, 0, 600, 600);
// iterating through each sprite, moving it, and calling it's paint method
for (Alien a : AliensArray) {
a.move();
a.paint(g);
}
// moving the player dx pixels - should be 0 if no key is being pressed
player.move(dx);
// calling the Player's paint method
player.paint(g);
}
// application entry point
public static void main(String[] args) {
InvadersApplication ia = new InvadersApplication();
}
}

View File

@ -0,0 +1,13 @@
import java.awt.*;
import javax.swing.*;
public class Player extends Sprite2D {
public Player(Image image) {
super(image);
}
// method to move the player by the supplied distance
public void move(int distance) {
x += distance; // x is inherited from the Sprite2D superclass
}
}

View File

@ -0,0 +1,24 @@
import java.awt.*;
import javax.swing.*;
public class Sprite2D {
// member data
public int x,y; // public so that it can be inherited
private Image image;
public Sprite2D(Image image) {
this.image = image;
}
// paint method
public void paint(Graphics g) {
// draw the image
g.drawImage(image, x, y, null);
}
// set the position of the object
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,31 @@
import java.awt.*;
import javax.swing.*;
public class Alien extends Sprite2D {
private int stepSize = 2;
public Alien(Image image) {
super(image);
}
// method to randomly move the alien
public void move(boolean right) {
// changing the x & y co-ordinates (inherited from superclass) by either plus or minus the stepSize, depending on the direction
if (right) {
x += stepSize;
}
else {
x -= stepSize;
}
}
// method to move aliend down
public void moveDown() {
y += 10;
}
// getter method for the alien's x coordinate
public int getx() {
return x;
}
}

View File

@ -0,0 +1,173 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
public class InvadersApplication extends JFrame implements Runnable, KeyListener {
// member data
private static String workingDirectory = System.getProperty("user.dir");
private Image alienImage;
private Image playerImage;
private static final Dimension WindowSize = new Dimension(800, 600);
private static final int NUMALIENS = 30;
private Alien[] AliensArray = new Alien[NUMALIENS];
boolean right = true; // boolean to tell which direction the aliens are moving
private Player player;
private BufferStrategy strategy;
// variable to hold how far the player should be moving in the x axis per frame - default 0.
private int dx = 0;
// constructor
public InvadersApplication() {
// set up window
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// adding a key listener
addKeyListener(this);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
// load image from disk
ImageIcon alienIcon = new ImageIcon(workingDirectory + "/alien_ship_1.png");
ImageIcon playerIcon = new ImageIcon(workingDirectory + "/player_ship.png");
alienImage = alienIcon.getImage();
playerImage = playerIcon.getImage();
// initial x and y coordinates for the aliens
int alienx = 200;
int alieny = 25;
int column = 0; // keeps track of which column the alien is in
for (int i = 0; i < NUMALIENS; i++) {
AliensArray[i] = new Alien(alienImage);
AliensArray[i].setPosition(alienx, alieny);
alienx += 60;
column++;
// go onto a new line every 5 aliens
if (column >= 6) {
column = 0;
alienx = 200;
alieny += 60;
}
}
// creating a player icon & setting it's position
player = new Player(playerImage);
player.setPosition(270, 550);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
// create a new thread & start it
Thread t = new Thread(this);
t.start();
}
// thread's entry point
public void run() {
while (true) {
// repainting
this.repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void keyPressed(KeyEvent e) {
// getting the keycode of the event
int key = e.getKeyCode();
// if right key pressed, making the distance to be moved 10px to the right
if (key == KeyEvent.VK_RIGHT) {
dx = 5;
}
// if left key pressed, making the distance to be moved 10px to the left
if (key == KeyEvent.VK_LEFT) {
dx = -5;
}
}
@Override
public void keyReleased(KeyEvent e) {
// getting the keycode of the event
int key = e.getKeyCode();
// if the key released was the left or right arrow, setting dx back to 0
if (key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_LEFT) {
dx = 0;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
// application's paint method
public void paint(Graphics g) {
g = strategy.getDrawGraphics();
// draw a black rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 600);
// iterating through each sprite, moving it, and calling it's paint method
for (Alien a : AliensArray) {
a.move(right);
a.paint(g);
}
// checking if any of the aliens hit the edge when they were moved
for (Alien a : AliensArray) {
// changing direction & moving down if edge is hit
if (a.getx() > 750) {
right = false;
// looping through all the aliens and moving them down
for (Alien alien : AliensArray) {
alien.moveDown();
}
break;
}
else if (a.getx() < 0) {
right = true;
// looping through all the aliens and moving them down
for (Alien alien : AliensArray) {
alien.moveDown();
}
break;
}
}
// moving the player dx pixels - should be 0 if no key is being pressed
player.move(dx);
// calling the Player's paint method
player.paint(g);
strategy.show();
}
// application entry point
public static void main(String[] args) {
InvadersApplication ia = new InvadersApplication();
}
}

View File

@ -0,0 +1,13 @@
import java.awt.*;
import javax.swing.*;
public class Player extends Sprite2D {
public Player(Image image) {
super(image);
}
// method to move the player by the supplied distance
public void move(int distance) {
x += distance; // x is inherited from the Sprite2D superclass
}
}

View File

@ -0,0 +1,23 @@
import java.awt.*;
import javax.swing.*;
public class Sprite2D {
// member data
protected int x,y;
private Image image;
public Sprite2D(Image image) {
this.image = image;
}
// paint method
public void paint(Graphics g) {
// draw the image
g.drawImage(image, x, y, null);
}
// set the position of the object
public void setPosition(int x, int y) {
this.x = x;
this.y = y; }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,55 @@
import java.awt.*;
import javax.swing.*;
public class Alien extends Sprite2D {
public static long framesDrawn = 0; // variable to hold the number of frames drawn
public static int aliensKilled = 0; // static variable to hold the count of the aliens killed - in alien class as it's intended to be modified by aliens
public static int stepSize = 0; // how far the aliens move each frame - 0 by default but will get increased to 5 immediately
private Image altImage;
public Alien(Image image, Image altImage) {
super(image);
this.altImage = altImage;
}
// method to randomly move the alien
public void move(boolean right) {
// changing the x & y co-ordinates (inherited from superclass) by either plus or minus the stepSize, depending on the direction
if (right) {
x += stepSize;
}
else {
x -= stepSize;
}
}
// method to move aliend down
public void moveDown() {
y += 25;
}
// overridden paint method to allow animation
@Override
public void paint(Graphics g) {
framesDrawn++;
if (framesDrawn % 100 < 50) {
g.drawImage(image, x, y, null);
}
else {
g.drawImage(altImage, x, y, null);
}
}
@Override
// overridden kill method to set isAlive to false and increment the aliensKilled counter
public void kill() {
isAlive = false;
aliensKilled++;
}
// method to increase the stepsize of the aliens
public static void speedUp() {
stepSize = stepSize + 3;
}
}

View File

@ -0,0 +1,315 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.util.*;
public class InvadersApplication extends JFrame implements Runnable, KeyListener {
// member data
private static String workingDirectory = System.getProperty("user.dir");
private static boolean isGraphicsInitialised = false;
private Image alienImage;
private Image altAlienImage;
private Image playerImage;
private Image bulletImage;
private static final Dimension WindowSize = new Dimension(800, 600);
private static final int NUMALIENS = 30;
private Alien[] aliensArray = new Alien[NUMALIENS]; // arraylist of all the currently extant bullets
private ArrayList<PlayerBullet> bullets = new ArrayList<PlayerBullet>();
boolean right = true; // boolean to tell which direction the aliens are moving
private Player player;
private BufferStrategy strategy;
// variable to hold how far the player should be moving in the x axis per frame - default 0.
private int dx = 0;
public boolean gameOver = false; // boolean to tell what state the game is in
private long score = 0; // player's score
private long bestScore = 0; // the best score the player has achieved
// constructor
public InvadersApplication() {
// set up window
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// adding a key listener
addKeyListener(this);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
// load image from disk
ImageIcon alienIcon = new ImageIcon(workingDirectory + "/alien_ship_1.png");
ImageIcon altAlienIcon = new ImageIcon(workingDirectory + "/alien_ship_2.png");
ImageIcon playerIcon = new ImageIcon(workingDirectory + "/player_ship.png");
ImageIcon bulletIcon = new ImageIcon(workingDirectory + "/bullet.png");
alienImage = alienIcon.getImage();
altAlienImage = altAlienIcon.getImage();
playerImage = playerIcon.getImage();
bulletImage = bulletIcon.getImage();
// creating a player icon & setting it's position
player = new Player(playerImage);
player.setPosition(270, 550);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
// create a new thread & start it
Thread t = new Thread(this);
t.start();
isGraphicsInitialised = true;
}
// thread's entry point
public void run() {
while (true) {
// repainting
try {
this.repaint();
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void keyPressed(KeyEvent e) {
// what to do on keypress if the player is alive (game is being played)
if (player.isAlive) {
// getting the keycode of the event
int key = e.getKeyCode();
// if right key pressed, making the distance to be moved 10px to the right
if (key == KeyEvent.VK_RIGHT) {
dx = 5;
}
// if left key pressed, making the distance to be moved 10px to the left
if (key == KeyEvent.VK_LEFT) {
dx = -5;
}
}
// what to do on keypress if the player is not alive (game is over)
else {
// resetting everything so that the game can be restarted
resetAll();
}
}
@Override
public void keyReleased(KeyEvent e) {
// getting the keycode of the event
int key = e.getKeyCode();
// if the key released was the left or right arrow, setting dx back to 0
if (key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_LEFT) {
dx = 0;
}
// if space key released "firing" a bullet (creating one)
if (key == KeyEvent.VK_SPACE) { // firing bullets on release so that the player can't just hold down space to fire
bullets.add(new PlayerBullet(player, bulletImage));
}
}
@Override
public void keyTyped(KeyEvent e) {
}
// method to reset everything so that a new game may be started
public void resetAll() {
Alien.framesDrawn = 0;
Alien.aliensKilled = 0;
Alien.stepSize = 0;
newWave();
//aliensArray = null;
player.setPosition(270, 550);
player.isAlive = true;
}
// gameplay method
public void gameplay(Graphics g) {
// checking if any of the aliens hit the edge when they were moved
for (Alien a : aliensArray) {
// changing direction & moving down if edge is hit
if (a.getX() > 750) {
right = false;
// looping through all the aliens and moving them down
for (Alien alien : aliensArray) {
alien.moveDown();
}
break;
}
else if (a.getX() < 0) {
right = true;
// looping through all the aliens and moving them down
for (Alien alien : aliensArray) {
alien.moveDown();
}
break;
}
}
// looping through each bullet, moving it, and calling its paint method if it has not collided, removing it and the alien it collided with if it has
// using an iterator so that bullets can be removed from the list as we loop through
Iterator bulletsIterator = bullets.iterator();
while (bulletsIterator.hasNext()) {
PlayerBullet b = (PlayerBullet) bulletsIterator.next();
b.move();
// bullets will be removed to save memory, but aliens will not be removed until a wave is over to preserve correct movement
for (Alien a : aliensArray) {
// only checking for collisions if the alien is alive
if (a.isAlive) {
// if the bullet collides with an alien, removing the bullet & hiding the alien
// the aliens dimensions are 50x32
// the bullets dimensions are 6x16
if (
( (a.getX() < b.getX() && a.getX()+50 > b.getX()) || (b.getX() < a.getX() && b.getX()+6 > a.getX()) ) &&
( (a.getY() < b.getY() && a.getY()+32 > b.getY()) || (b.getY() < a.getY() && b.getY()+16 > a.getY()))
) {
bulletsIterator.remove();
a.kill();
score = score + 10; // increasing the score once the alien is killed
b.kill(); // "killing" the bullet so it's not painted before it's been removed
}
}
}
// painting the bullet if it is "alive"
if (b.isAlive) {
b.paint(g);
}
}
// looping through each alien to see if it has collided with the player
for (Alien a : aliensArray) {
// checking to see if any of the (alive) aliens have collided with the player
if (a.isAlive) {
if (
// the player's dimensions are 54 x 32
( (a.getX() < player.getX() && a.getX()+50 > player.getX()) || (player.getX() < a.getX() && player.getX()+54 > a.getX()) )
&&
( (a.getY() < player.getY() && a.getY()+32 > player.getY()) || (player.getY() < a.getY() && player.getY()+32 > a.getY()))
) {
player.kill(); // "killing" the player
return;
}
}
}
// moving the player dx pixels - should be 0 if no key is being pressed
player.move(dx);
// iterating through each sprite, moving it, and calling its paint method
for (Alien a : aliensArray) {
a.move(right);
// only painting the alien if it is alive
if (a.isAlive) {
a.paint(g);
}
}
// calling the Player's paint method
player.paint(g);
}
// application's paint method
public void paint(Graphics g) {
// making sure that the graphics are initialised before painting
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
// draw a black rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 600);
Font f = new Font("Times", Font.PLAIN, 50);
g.setColor(Color.WHITE);
// calculating score
score = Alien.aliensKilled * 10;
// displaying score and best score
String scorebar = "Score: " + score + " Best: " + bestScore;
g.drawString(scorebar, 50, 50);
// if the game is not over, playing the game. else, displaying a gameover screen.
if (player.isAlive) {
// checking if all the aliens are dead, and if so, spawning a new wave
boolean noAliens = true;
for (Alien a : aliensArray) {
if (a != null && a.isAlive) {
noAliens = false;
break;
}
}
if (noAliens) {
newWave();
}
gameplay(g);
}
else {
if (score > bestScore) {
bestScore = score;
}
String scores = "Score: " + score + " Best Score: " + bestScore;
g.drawString("GAME OVER", 400, 300);
g.drawString(scores, 400, 350);
g.drawString("Press any key to continue", 400, 400);
}
strategy.show();
}
}
// method to spawn a new wave of aliens
public void newWave() {
// deleting any existing bullets so the aliens don't spawn on top of them
bullets.clear();
// speeding up the aliens
Alien.speedUp();
// initial x and y coordinates for the aliens
int alienx = 200;
int alieny = 25;
int column = 0; // keeps track of which column the alien is in
for (int i = 0; i < NUMALIENS; i++) {
aliensArray[i] = new Alien(alienImage, altAlienImage);
aliensArray[i].setPosition(alienx, alieny);
alienx += 60;
column++;
// go onto a new line every 5 aliens
if (column >= 6) {
column = 0;
alienx = 200;
alieny += 60;
}
}
}
// application entry point
public static void main(String[] args) {
InvadersApplication ia = new InvadersApplication();
}
}

View File

@ -0,0 +1,13 @@
import java.awt.*;
import javax.swing.*;
public class Player extends Sprite2D {
public Player(Image image) {
super(image);
}
// method to move the player by the supplied distance
public void move(int distance) {
x += distance; // x is inherited from the Sprite2D superclass
}
}

View File

@ -0,0 +1,15 @@
import java.awt.*;
import javax.swing.*;
public class PlayerBullet extends Sprite2D {
public PlayerBullet(Player player, Image image) {
super(image);
x = player.getX() + 54/2;
y = player.getY();
}
// method to move the bullet up each frame
public void move() {
y = y - 10;
}
}

View File

@ -0,0 +1,41 @@
import java.awt.*;
import javax.swing.*;
public class Sprite2D {
// member data
protected int x,y;
protected Image image;
public boolean isAlive; // boolean to tell if the sprite is alive or not
public Sprite2D(Image image) {
this.image = image;
this.isAlive = true;
}
// paint method
public void paint(Graphics g) {
// draw the image
g.drawImage(image, x, y, null);
}
// set the position of the object
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
// getter method for the sprite's x position
public int getX() {
return x;
}
// getter method for the sprite's y position
public int getY() {
return y;
}
// method to set isAlive to false
public void kill() {
isAlive = false;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1 @@
- Multiple games

View File

@ -0,0 +1,88 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.util.*;
public class GameOfLife extends JFrame implements Runnable, MouseListener {
private static final Dimension WindowSize = new Dimension(800, 800);
private BufferStrategy strategy;
private static boolean isGraphicsInitialised = false;
private boolean gameState[][] = new boolean[40][40];
public GameOfLife() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
// create a new thread & start it
Thread t = new Thread(this);
t.start();
// adding mouse listener
addMouseListener(this);
isGraphicsInitialised = true;
}
// entry point of the application
public static void main(String[] args) {
GameOfLife game = new GameOfLife();
}
public void run() {
while (true) {
// repainting
try {
this.repaint();
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// application's paint method
public void paint(Graphics g) {
// making sure that the graphics are initialised before painting
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
// draw a white rectangle on the whole canvas
g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 800);
// looping through the gameState array
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// drawing a black square if true
if (gameState[i][j]) {
g.setColor(Color.BLACK);
g.fillRect(i * 20, j * 20, 20, 20);
}
}
}
strategy.show();
}
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
// mouse click event
public void mouseClicked(MouseEvent e) {
// setting boolean corresponding to the square that was clicked to true
gameState[(int) Math.floor(e.getX() / 20)][(int) Math.floor(e.getY() / 20)] = true;
}
}

View File

@ -0,0 +1,171 @@
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;
public class GameOfLife extends JFrame implements Runnable, MouseListener {
private static final Dimension WindowSize = new Dimension(800, 800);
private BufferStrategy strategy;
private static boolean isGraphicsInitialised = false;
private boolean gameState[][][] = new boolean[40][40][2];
private static boolean isPlaying = false;
public GameOfLife() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
// create a new thread & start it
Thread t = new Thread(this);
t.start();
// adding mouse listener
addMouseListener(this);
isGraphicsInitialised = true;
}
// entry point of the application
public static void main(String[] args) {
GameOfLife game = new GameOfLife();
}
public void run() {
while (true) {
// repainting
try {
this.repaint();
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// application's paint method
public void paint(Graphics g) {
// making sure that the graphics are initialised before painting
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
// draw a white rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0, 0, WindowSize.width, WindowSize.height);
// looping through the gameState array
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// drawing a white square if true
if (gameState[i][j][0]) {
g.setColor(Color.WHITE);
g.fillRect(i * 20, j * 20, 20, 20);
}
}
}
if (isPlaying) {
for (int x = 0; x < 40; x++) {
for (int y = 0; y < 40; y++) {
// count the live neighbours of cell [x][y][0]
int numLiveNeighbours = 0;
for (int xx = -1 ; xx <= 1; xx++) {
for (int yy = -1; yy <= 1; yy++) {
if (xx != 0 || yy != 0) {
// check cell [x+xx][y+yy][0]
// if x+xx or y+yy is out of bounds, getting the inverse of it modulo 40
int newX = (x+xx >= 0) ? (x+xx) % 40 : 40 + x+xx;
int newY = (y+yy >= 0) ? (y+yy) % 40 : 40 + y+yy;
if (gameState[newX][newY][0]) {
numLiveNeighbours++;
}
}
}
}
// killing the cell if it is alive and has fewer than two live neighbours or greater than 3 live neighbours
if (gameState[x][y][0] && (numLiveNeighbours < 2 || numLiveNeighbours > 3)) {
gameState[x][y][1] = false;
}
// bringing the cell back to life it is dead and has exactly 3 live neighbours
else if (!gameState[x][y][0] && numLiveNeighbours == 3) {
gameState[x][y][1] = true;
}
}
}
// making the "front buffer" equal to the "back buffer"
for (int x = 0; x < 40; x++) {
for (int y = 0; y < 40; y++) {
gameState[x][y][0] = gameState[x][y][1];
}
}
}
// if the game is not being played, drawing the buttons
else {
Font f = new Font("Times", Font.PLAIN, 12);
g.setFont(f);
FontMetrics fm = getFontMetrics(f);
// drawing the two buttons
g.setColor(Color.GREEN);
g.fillRect(20, 20, 60, 20);
g.fillRect(100, 20, 60, 20);
g.setColor(Color.BLACK);
g.drawString("Start", 35, 35);
g.drawString("Random", 105, 35);
}
strategy.show();
}
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
// mouse click event
public void mouseClicked(MouseEvent e) {
// if (!isPlaying) {
// if start button was pressed, switching to the playing game state
if ((e.getX() >= 20 && e.getX() <= 80) && (e.getY() >= 20 && e.getY() <= 40)) {
isPlaying = true;
}
// else if the random button was pressed, calling the random method
else if ((e.getX() >= 100 && e.getX() <= 160) && (e.getY() >= 20 && e.getY() <= 40)) {
random();
}
// else, setting the clicked square to true (white)
else {
// setting boolean corresponding to the square that was clicked to true
gameState[(int) Math.floor(e.getX() / 20)][(int) Math.floor(e.getY() / 20)][0] = true;
}
// }
}
// method to generate a random starting state
public void random() {
// looping through the gameState array
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// setting the square to alive with a probability of 1 in 10
if (((int) (Math.random() * 10)) == 1) {
gameState[i][j][0] = true;
}
}
}
}
}

View File

@ -0,0 +1,256 @@
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
public class GameOfLife extends JFrame implements Runnable, MouseListener, MouseMotionListener {
private static String workingDirectory = System.getProperty("user.dir");
private static final Dimension WindowSize = new Dimension(800, 800);
private BufferStrategy strategy;
private static boolean isGraphicsInitialised = false;
private boolean gameState[][][] = new boolean[40][40][2];
private static boolean isPlaying = false;
public GameOfLife() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
// create a new thread & start it
Thread t = new Thread(this);
t.start();
// adding mouse listener
addMouseListener(this);
addMouseMotionListener(this);
isGraphicsInitialised = true;
}
// entry point of the application
public static void main(String[] args) {
GameOfLife game = new GameOfLife();
}
public void run() {
while (true) {
// repainting
try {
this.repaint();
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// application's paint method
public void paint(Graphics g) {
// making sure that the graphics are initialised before painting
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
// draw a white rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0, 0, WindowSize.width, WindowSize.height);
// looping through the gameState array
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// drawing a white square if true
if (gameState[i][j][0]) {
g.setColor(Color.WHITE);
g.fillRect(i * 20, j * 20, 20, 20);
}
}
}
if (isPlaying) {
for (int x = 0; x < 40; x++) {
for (int y = 0; y < 40; y++) {
// count the live neighbours of cell [x][y][0]
int numLiveNeighbours = 0;
for (int xx = -1 ; xx <= 1; xx++) {
for (int yy = -1; yy <= 1; yy++) {
if (xx != 0 || yy != 0) {
// check cell [x+xx][y+yy][0]
// if x+xx or y+yy is out of bounds, getting the inverse of it modulo 40
int newX = (x+xx >= 0) ? (x+xx) % 40 : 40 + x+xx;
int newY = (y+yy >= 0) ? (y+yy) % 40 : 40 + y+yy;
if (gameState[newX][newY][0]) {
numLiveNeighbours++;
}
}
}
}
// killing the cell if it is alive and has fewer than two live neighbours or greater than 3 live neighbours
if (gameState[x][y][0] && (numLiveNeighbours < 2 || numLiveNeighbours > 3)) {
gameState[x][y][1] = false;
}
// bringing the cell back to life it is dead and has exactly 3 live neighbours
else if (!gameState[x][y][0] && numLiveNeighbours == 3) {
gameState[x][y][1] = true;
}
}
}
// making the "front buffer" equal to the "back buffer"
for (int x = 0; x < 40; x++) {
for (int y = 0; y < 40; y++) {
gameState[x][y][0] = gameState[x][y][1];
}
}
}
// if the game is not being played, drawing the buttons
else {
Font f = new Font("Times", Font.PLAIN, 12);
g.setFont(f);
FontMetrics fm = getFontMetrics(f);
// drawing the two buttons
g.setColor(Color.GREEN);
g.fillRect( 20, 20, 60, 20);
g.fillRect(100, 20, 60, 20);
g.fillRect(180, 20, 60, 20);
g.fillRect(260, 20, 60, 20);
g.setColor(Color.BLACK);
g.drawString("Start", 35, 35);
g.drawString("Random", 105, 35);
g.drawString("Save", 185, 35);
g.drawString("Load", 265, 35);
}
strategy.show();
}
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseMoved(MouseEvent e) { }
public void mouseDragged(MouseEvent e) {
// checking that index is in bounds before drawing
if (e.getX() < 800 && e.getX() >= 0 && e.getY() < 800 && e.getY() >= 0) {
gameState[(int) Math.floor(e.getX() / 20)][(int) Math.floor(e.getY() / 20)][0] = true;
}
}
// mouse click event
public void mouseClicked(MouseEvent e) {
// if (!isPlaying) {
// if start button was pressed, switching to the playing game state
if ((e.getX() >= 20 && e.getX() <= 80) && (e.getY() >= 20 && e.getY() <= 40)) {
isPlaying = true;
}
// else if the random button was pressed, calling the random method
else if ((e.getX() >= 100 && e.getX() <= 160) && (e.getY() >= 20 && e.getY() <= 40)) {
random();
}
// else if the save button was clicked
else if ((e.getX() >= 180 && e.getX() <= 240) && (e.getY() >= 20 && e.getY() <= 40)) {
save();
}
// else if the load button was clicked
else if ((e.getX() >= 260 && e.getX() <= 320) && (e.getY() >= 20 && e.getY() <= 40)) {
load();
}
// else, setting the clicked square to true (white)
else {
// setting boolean corresponding to the square that was clicked to true
gameState[(int) Math.floor(e.getX() / 20)][(int) Math.floor(e.getY() / 20)][0] = true;
}
// }
}
// method to generate a random starting state
public void random() {
// looping through the gameState array
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// setting the square to alive with a probability of 1 in 10
if (((int) (Math.random() * 10)) == 1) {
gameState[i][j][0] = true;
}
}
}
}
// method to save the gamestate to a txt file
public void save() {
// string that will be written to the file
StringBuilder output = new StringBuilder();
// looping through each index in the array
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// appending a 1 if true, 0 if false
if (gameState[i][j][0]) {
output.append("1");
}
else {
output.append("0");
}
}
}
// writing the string to the file
String filename = workingDirectory + "/gamestate.txt";
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
writer.write(output.toString());
writer.close();
}
catch (IOException e) {}
}
// method to load the gamestate from a txt file
public void load() {
String filename = workingDirectory + "/gamestate.txt";
String loadedtext = "";
String line = null;
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
do {
try {
line = reader.readLine();
// appending to loadedtext if not null
if (line != null) {
loadedtext += line;
}
} catch (IOException e) {}
} while (line != null);
} catch (IOException e) {}
// looping through each element of the front buffer and assigning true or false if the next char is 1 or 0
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
// getting the character that corresponds to the index of the array
if (loadedtext.charAt(40*i + j) == '1') {
gameState[i][j][0] = true;
}
else {
gameState[i][j][0] = false;
}
}
}
}
}

View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000001100000000000000000000000000000000000011100000000000000000000000000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111000000000000000000000000000000000001000100000000000000000000000000000000001100010000000000000000000000000000011111110001000000000000000000000000000011000000101100000000000000000000000000011000000011000000000000000000000000000001000000001110000000000000000000000000000100000001101000000000000000000000000000001110001100100000000000000000000000000000001111100110000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

View File

@ -0,0 +1,273 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
public class AStarMaze extends JFrame implements Runnable, MouseListener, MouseMotionListener, KeyListener {
// member data
private static final Dimension WindowSize = new Dimension(800, 800);
private boolean isInitialised = false;
private BufferStrategy strategy;
private Graphics offscreenBuffer;
private static boolean map[][] = new boolean[40][40];
private boolean isGameRunning = false;
private BadGuy badguy;
private Player player;
private String FilePath;
// constructor
public AStarMaze() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window, centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
this.setTitle("A* Pathfinding Demo");
FilePath = System.getProperty("user.dir") + "/";
// load raster graphics and instantiate game objects
ImageIcon icon = new ImageIcon(FilePath+"badguy.png");
Image img = icon.getImage();
badguy = new BadGuy(img);
icon = new ImageIcon(FilePath+"player.png");
img = icon.getImage();
player = new Player(img);
// initialise double-buffering
createBufferStrategy(2);
strategy = getBufferStrategy();
// create and start our animation thread
Thread t = new Thread(this);
t.start();
// register the Jframe itself to receive mouse and keyboard events
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
// initialise the map state
for (x=0;x<40;x++) {
for (y=0;y<40;y++) {
map[x][y]=false;
}
}
isInitialised = true;
}
// thread's entry point
public void run() {
long loops = 0;
while (true) {
// 1: sleep for 1/5 sec
try {
Thread.sleep(200);
} catch (InterruptedException e) { }
// 2: animate game objects
if (isGameRunning) {
loops++;
player.move(map); // player moves every frame
// recalculating the badguys path every move, highly inefficient but easier to program lol
badguy.reCalcPath(map, player.x, player.y);
if (loops%10==0) // badguy moves once every 3 frames
badguy.move(map,player.x,player.y);
}
// 3: force an application repaint
this.repaint();
}
}
private void loadMaze() {
String filename = FilePath+"maze.txt";
String textinput = null;
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
textinput = reader.readLine();
reader.close();
}
catch (IOException e) { }
if (textinput!=null) {
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
map[x][y] = (textinput.charAt(x*40+y)=='1');
}
}
}
}
private void saveMaze() {
// pack maze into a string
String outputtext="";
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
if (map[x][y])
outputtext+="1";
else
outputtext+="0";
}
}
try {
String filename = FilePath+"maze.txt";
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
writer.write(outputtext);
writer.close();
}
catch (IOException e) { }
}
// mouse events which must be implemented for MouseListener
public void mousePressed(MouseEvent e) {
if (!isGameRunning) {
// was the click on the 'start button'?
int x = e.getX();
int y = e.getY();
if (x>=15 && x<=85 && y>=40 && y<=70) {
isGameRunning=true;
return;
}
// or the 'load' button?
if (x>=315 && x<=385 && y>=40 && y<=70) {
loadMaze();
return;
}
// or the 'save' button?
if (x>=415 && x<=485 && y>=40 && y<=70) {
saveMaze();
return;
}
}
// determine which cell of the gameState array was clicked on
int x = e.getX()/20;
int y = e.getY()/20;
// toggle the state of the cell
map[x][y] = !map[x][y];
// throw an extra repaint, to get immediate visual feedback
this.repaint();
// store mouse position so that each tiny drag doesn't toggle the cell
// (see mouseDragged method below)
prevx=x;
prevy=y;
}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
//
// mouse events which must be implemented for MouseMotionListener
public void mouseMoved(MouseEvent e) {}
// mouse position on previous mouseDragged event
// must be member variables for lifetime reasons
int prevx=-1, prevy=-1;
public void mouseDragged(MouseEvent e) {
// determine which cell of the gameState array was clicked on
// and make sure it has changed since the last mouseDragged event
if (e.getX() < 800 && e.getX() >= 0 && e.getY() < 800 && e.getY() >= 0) {
int x = e.getX()/20;
int y = e.getY()/20;
if (x!=prevx || y!=prevy) {
// toggle the state of the cell
map[x][y] = !map[x][y];
// throw an extra repaint, to get immediate visual feedback
this.repaint();
// store mouse position so that each tiny drag doesn't toggle the cell
prevx=x;
prevy=y;
}
}
badguy.reCalcPath(map, player.x, player.y);
}
// Keyboard events
public void keyPressed(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_LEFT)
player.setXSpeed(-1);
else if (e.getKeyCode()==KeyEvent.VK_RIGHT)
player.setXSpeed(1);
else if (e.getKeyCode()==KeyEvent.VK_UP)
player.setYSpeed(-1);
else if (e.getKeyCode()==KeyEvent.VK_DOWN)
player.setYSpeed(1);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_LEFT || e.getKeyCode()==KeyEvent.VK_RIGHT)
player.setXSpeed(0);
else if (e.getKeyCode()==KeyEvent.VK_UP || e.getKeyCode()==KeyEvent.VK_DOWN)
player.setYSpeed(0);
}
public void keyTyped(KeyEvent e) { }
// application's paint method
public void paint(Graphics g) {
if (!isInitialised)
return;
// g = offscreenBuffer; // draw to offscreen buffer
g = strategy.getDrawGraphics();
// clear the canvas with a big black rectangle
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
// redraw the map
g.setColor(Color.WHITE);
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
if (map[x][y]) {
g.fillRect(x*20, y*20, 20, 20);
}
}
}
// redraw the player and badguy
// paint the game objects
player.paint(g);
badguy.paint(g);
if (!isGameRunning) {
// game is not running..
// draw a 'start button' as a rectangle with text on top
// also draw 'load' and 'save' buttons
g.setColor(Color.GREEN);
g.fillRect(15, 40, 70, 30);
g.fillRect(315, 40, 70, 30);
g.fillRect(415, 40, 70, 30);
g.setFont(new Font("Times", Font.PLAIN, 24));
g.setColor(Color.BLACK);
g.drawString("Start", 22, 62);
g.drawString("Load", 322, 62);
g.drawString("Save", 422, 62);
}
// flip the buffers
strategy.show();
}
// application entry point
public static void main(String[] args) {
AStarMaze w = new AStarMaze();
}
}

View File

@ -0,0 +1,298 @@
import java.awt.*;
import java.util.*;
public class BadGuy {
/* list of nodes to which the algorithm has already found a route (i.e., one of its conencted neighbours has been expanded)
* but have not themselves been expanded */
LinkedList<Node> openlist = new LinkedList<Node>();
// list of nodes that have been expanded and which therefore should not be revisited
LinkedList<Node> closedlist = new LinkedList<Node>();
Node[][] allnodes = new Node[40][40] ; // array of all the nodes
Stack<Node> finalpath = new Stack<Node>();
Image myImage;
int x=0,y=0;
boolean hasPath=false;
public BadGuy( Image i ) {
myImage=i;
x = 30;
y = 10;
}
public void reCalcPath(boolean map[][],int targx, int targy) {
System.out.println();
System.out.println("recalculating path");
hasPath = false;
openlist.clear();
closedlist.clear();
finalpath.clear();
// looping through map[][], generating each node, and marking each wall node as closed
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
allnodes[i][j] = new Node(i, j); // generating node
if (map[i][j]) {
allnodes[i][j].closed = true;
allnodes[i][j].open = false;
closedlist.add(allnodes[i][j]);
}
}
}
// calculate f,g,h for the starting node and set to open
Node starting = allnodes[x][y];
starting.g = 0;
starting.h = targx - x + targy - y; // manhattan distance
starting.f = starting.g + starting.h;
starting.open = true;
starting.closed = false;
openlist.add(starting);
// looping while a path has not been found
// end condition: if a neighbour is the target, or if there are no open nodes
while (!hasPath) {
// breaking if there are no open nodes
if (openlist.size() == 0) {
break;
}
/* progress is made by identifying the most promising node in the open list (i.e., the one with lowest f value) and
* expanding it by adding each of its connected neighbours to the open list, unless they are already closed. */
// looping through open list to find most promising node
Node mostpromising = openlist.get(0);
for (int i = 1; i < openlist.size(); i++) {
if (openlist.get(i).f < mostpromising.f) {
mostpromising = openlist.get(i);
}
}
int mx = mostpromising.x;
int my = mostpromising.y;
// expanding the most promising node by adding each of its connected neighbours to the open list, unless they are already closed
// as nodes are added to the open list, their f, g, h, & parent values are recorded
// the g value of a node is equal to the g value of its parent + the cost of moving from the parent to the node itself. t
// as nodes are expanded, they are moved to the closed list
mostpromising.open = false;
mostpromising.closed = true;
closedlist.add(mostpromising);
// openlist.remove(mostpromising);
// northwest neighbour
if (mx-1 >= 0 && my-1 >= 0 && !allnodes[mx-1][my-1].closed) {
// checking if this node is the target node, and breaking if so
if (mx-1 == targx && my-1 == targy) {
allnodes[mx-1][my-1].open = true;
allnodes[mx-1][my-1].closed = false;
closedlist.remove(allnodes[mx-1][my-1]);
openlist.add(allnodes[mx-1][my-1]);
break;
}
if (!allnodes[mx-1][my-1].open) {
allnodes[mx-1][my-1].g = mostpromising.g + 1;
allnodes[mx-1][my-1].h = targx - mx + targy - my;
allnodes[mx-1][my-1].f = allnodes[mx-1][my-1].g + allnodes[mx-1][my-1].h;
allnodes[mx-1][my-1].open = true;
allnodes[mx-1][my-1].closed = false;
openlist.add(allnodes[mx-1][my-1]);
}
}
// north neighbour
if (my-1 >= 0 && !allnodes[mx][my-1].closed) {
// checking if this node is the target node, and breaking if so
if (mx == targx && my-1 == targy) {
allnodes[mx][my-1].open = true;
allnodes[mx][my-1].closed = false;
closedlist.remove(allnodes[mx][my-1]);
openlist.add(allnodes[mx][my-1]);
break;
}
if (!allnodes[mx][my-1].open) {
allnodes[mx][my-1].g = mostpromising.g + 1;
allnodes[mx][my-1].h = targx - mx + targy - my;
allnodes[mx][my-1].f = allnodes[mx][my-1].g + allnodes[mx][my-1].h;
allnodes[mx][my-1].open = true;
allnodes[mx][my-1].closed = false;
openlist.add(allnodes[mx][my-1]);
}
}
// northeast neighbour
if (mx+1 < 40 && my-1 >= 0 && !allnodes[mx+1][my-1].closed) {
// checking if this node is the target node, and breaking if so
if (mx+1 == targx && my-1 == targy) {
allnodes[mx+1][my-1].open = true;
allnodes[mx+1][my-1].closed = false;
closedlist.remove(allnodes[mx+1][my-1]);
openlist.add(allnodes[mx+1][my-1]);
break;
}
if (!allnodes[mx+1][my-1].open && !allnodes[mx+1][my-1].closed) {
allnodes[mx+1][my-1].g = mostpromising.g + 1;
allnodes[mx+1][my-1].h = targx - mx+1 + targy - my;
allnodes[mx+1][my-1].f = allnodes[mx+1][my-1].g + allnodes[mx+1][my-1].h;
allnodes[mx+1][my-1].open = true;
allnodes[mx+1][my-1].closed = false;
openlist.add(allnodes[mx+1][my-1]);
}
}
// west neighbour
if (mx-1 >= 0 && !allnodes[mx-1][my].closed) {
// checking if this node is the target node, and breaking if so
if (mx-1 == targx && my == targy) {
allnodes[mx-1][my].open = true;
allnodes[mx-1][my].closed = false;
closedlist.remove(allnodes[mx-1][my]);
openlist.add(allnodes[mx-1][my]);
break;
}
if (!allnodes[mx-1][my].open && !allnodes[mx-1][my].closed) {
allnodes[mx-1][my].g = mostpromising.g + 1;
allnodes[mx-1][my].h = targx - mx + targy - my;
allnodes[mx-1][my].f = allnodes[mx-1][my].g + allnodes[mx-1][my].h;
allnodes[mx-1][my].open = true;
allnodes[mx-1][my].closed = false;
openlist.add(allnodes[mx-1][my]);
}
}
// east neighbour
if (mx+1 < 40 && !allnodes[mx+1][my].closed) {
// checking if this node is the target node, and breaking if so
if (mx+1 == targx && my == targy) {
allnodes[mx+1][my].open = true;
allnodes[mx+1][my].closed = false;
closedlist.remove(allnodes[mx+1][my]);
openlist.add(allnodes[mx+1][my]);
break;
}
if (!allnodes[mx+1][my].open) {
allnodes[mx+1][my].g = mostpromising.g + 1;
allnodes[mx+1][my].h = targx - mx+1 + targy - my;
allnodes[mx+1][my].f = allnodes[mx+1][my].g + allnodes[mx+1][my].h;
allnodes[mx+1][my].open = true;
allnodes[mx+1][my].closed = false;
openlist.add(allnodes[mx+1][my]);
}
}
// southwest neighbour
if (mx-1 >= 0 && my+1 < 40 && !allnodes[mx-1][my+1].closed) {
// checking if this node is the target node, and breaking if so
if (mx-1 == targx && my+1 == targy) {
allnodes[mx-1][my+1].open = true;
allnodes[mx-1][my+1].closed = false;
closedlist.remove(allnodes[mx-1][my+1]);
openlist.add(allnodes[mx-1][my+1]);
break;
}
if (!allnodes[mx-1][my+1].open) {
allnodes[mx-1][my+1].g = mostpromising.g + 1;
allnodes[mx-1][my+1].h = targx - mx + targy - my;
allnodes[mx-1][my+1].f = allnodes[mx-1][my+1].g + allnodes[mx-1][my+1].h;
allnodes[mx-1][my+1].open = true;
allnodes[mx-1][my+1].closed = false;
openlist.add(allnodes[mx-1][my+1]);
}
}
// south neighbour
if (my+1 < 40 && !allnodes[mx][my+1].closed) {
// checking if this node is the target node, and breaking if so
if (mx == targx && my+1 == targy) {
allnodes[mx][my+1].open = true;
allnodes[mx][my+1].closed = false;
closedlist.remove(allnodes[mx][my+1]);
openlist.add(allnodes[mx][my+1]);
break;
}
if (!allnodes[mx][my+1].open) {
allnodes[mx][my+1].g = mostpromising.g + 1;
allnodes[mx][my+1].h = targx - mx + targy - my;
allnodes[mx][my+1].f = allnodes[mx][my+1].g + allnodes[mx][my+1].h;
allnodes[mx][my+1].open = true;
allnodes[mx][my+1].closed = false;
openlist.add(allnodes[mx][my+1]);
}
}
// southeast neighbour
if (mx+1 < 40 && my+1 < 40 && !allnodes[mx+1][my+1].closed) {
// checking if this node is the target node, and breaking if so
if (mx+1 == targx && my+1 == targy) {
allnodes[mx+1][my+1].open = true;
allnodes[mx+1][my+1].closed = false;
closedlist.remove(allnodes[mx+1][my+1]);
openlist.add(allnodes[mx+1][my+1]);
break;
}
if (!allnodes[mx+1][my+1].open) {
allnodes[mx+1][my+1].g = mostpromising.g + 1;
allnodes[mx+1][my+1].h = targx - mx+1 + targy - my;
allnodes[mx+1][my+1].f = allnodes[mx+1][my+1].g + allnodes[mx+1][my+1].h;
allnodes[mx+1][my+1].open = true;
allnodes[mx+1][my+1].closed = false;
openlist.add(allnodes[mx+1][my+1]);
}
}
}
// generate final path by pushing target onto stack, followed by its parent in closedlist, ..., followed by start node
for (int i = openlist.size()-1; i >= 0; i--) {
System.out.println("pushing x=" + openlist.get(i).x + " y =" + openlist.get(i).y);
finalpath.push(openlist.get(i));
}
hasPath = true;
return;
}
public void move(boolean map[][],int targx, int targy) {
if (hasPath) {
Node nextnode = finalpath.pop();
System.out.println("next node x=" + nextnode.x + " y=" + nextnode.y);
x = nextnode.x;
y = nextnode.y;
}
else {
// no path known, so just do a dumb 'run towards' behaviour
int newx=x, newy=y;
if (targx<x)
newx--;
else if (targx>x)
newx++;
if (targy<y)
newy--;
else if (targy>y)
newy++;
if ((newx < 40 && newx >= 0 && newy < 40 && newy >=0) && !map[newx][newy]) {
x=newx;
y=newy;
}
}
}
public void paint(Graphics g) {
g.drawImage(myImage, x*20, y*20, null);
}
}

View File

@ -0,0 +1,15 @@
public class Node {
public int x;
public int y;
public int g; // cost of getting from the starting node to this node
public int h; // estimated heuristic cost of getting from this node to the target node
public int f; // sum of g & h, the algorithm's best current estimate as to the total cost of travelling from the starting location to the target location via this node
public boolean closed = false;
public boolean open = false;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
}

View File

@ -0,0 +1,42 @@
import java.awt.Graphics;
import java.awt.Image;
public class Player {
Image myImage;
int x=0,y=0;
int xSpeed=0, ySpeed=0;
public Player( Image i ) {
myImage=i;
x=10;
y=35;
}
public void setXSpeed( int x ) {
xSpeed=x;
}
public void setYSpeed( int y ) {
ySpeed=y;
}
public void move(boolean map[][]) {
int newx=x+xSpeed;
int newy=y+ySpeed;
// making sure that the newx & newy are not off the map or blocked
// if (e.getX() < 800 && e.getX() >= 0 && e.getY() < 800 && e.getY() >= 0) {
if ((newx < 40 && newx >= 0 && newy < 40 && newy >=0) && !map[newx][newy]) {
x=newx;
y=newy;
}
}
public void paint(Graphics g) {
g.drawImage(myImage, x*20, y*20, null);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000001100000000000000000000000000000000000000110000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000010000000000000000000000000000000000000011000000000000000000000011111111111111111100000000000000000000000000000000000000110000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000010000000000000000000000000000000000000011000000000000000000000000000000000000001100000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,110 @@
import java.awt.*;
import javax.swing.*;
public class Cave extends JFrame implements Runnable {
private static final Dimension WindowSize = new Dimension(800, 800);
private static boolean isGraphicsInitialised = false;
private boolean map[][][] = new boolean[200][200][2];
public Cave() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// randomly deciding whether each position in the map is a wall (true) or floor (false)
for (int i = 0; i < 200; i++) {
for (int j = 0; j < 200; j++) {
// setting the square to wall with a probability of 60%
map[i][j][0] = Math.random() < 0.6;
}
}
// display the window. centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2; int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
// create a new thread & start it
Thread t = new Thread(this);
t.start();
isGraphicsInitialised = true;
}
public void run() {
if (isGraphicsInitialised) {
// looping 5 times to show the initial state also, but re-running the cave procedure 4 times
for (int i = 0; i <= 4; i++){
// repainting
try {
this.repaint();
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void paint (Graphics g) {
// draw a white rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0, 0, WindowSize.width, WindowSize.height);
// looping through map and drawing a white square if floor (true)
for (int i = 0; i < 200; i++) {
for (int j = 0; j < 200; j++) {
// drawing a white square if true
if (map[i][j][0]) {
g.setColor(Color.WHITE);
g.fillRect(i * 4, j * 4, 4, 4);
}
}
}
// looping through array to make clumping happen
for (int x = 0; x < 200; x++) {
for (int y = 0; y < 200; y++) {
// count the wall neighbours of cell [x][y]
int numWallNeighbours = 0;
// looping through neighbour cells
for (int xx = -1 ; xx <= 1; xx++) {
for (int yy = -1; yy <= 1; yy++) {
if (xx != 0 || yy != 0) {
// check cell [x+xx][y+yy]()
// if x+xx or y+yy is out of bounds, getting the inverse of it modulo 200
int newX = (x+xx >= 0) ? (x+xx) % 200 : 200 + x+xx;
int newY = (y+yy >= 0) ? (y+yy) % 200 : 200 + y+yy;
// if the neighbour is a wall, increasing the count
if (map[newX][newY][0]) {
numWallNeighbours++;
}
}
}
}
// defining each cell that has at least 5 neighbouring wall cells as a wall itself
if (numWallNeighbours >= 5) {
map[x][y][1] = true;
}
// otherwise defining it as a floor
else {
map[x][y][1] = false;
}
}
}
// moving back buffer to front
for (int x = 0; x < 200; x++) {
for (int y = 0; y < 200; y++) {
map[x][y][0] = map[x][y][1];
}
}
}
public static void main(String[] args) {
Cave cave = new Cave();
}
}

Binary file not shown.

View File

@ -0,0 +1,552 @@
\documentclass[11pt]{article}
\usepackage{report}
\usepackage[utf8]{inputenc} % allow utf-8 input
\usepackage[T1]{fontenc} % use 8-bit T1 fonts
\usepackage[colorlinks=true, linkcolor=black, citecolor=blue, urlcolor=blue]{hyperref} % hyperlinks
\usepackage{url} % simple URL typesetting
\usepackage{booktabs} % professional-quality tables
\usepackage{amsfonts} % blackboard math symbols
\usepackage{nicefrac} % compact symbols for 1/2, etc.
\usepackage{microtype} % microtypography
\usepackage{lipsum} % Can be removed after putting your text content
\usepackage{graphicx}
\graphicspath{ {./images/} }
\usepackage{natbib}
\usepackage{doi}
\setcitestyle{aysep={,}}
\usepackage{array}
\usepackage{listings}
\usepackage{xcolor}
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
\definecolor{codeorange}{rgb}{1,0.49,0}
\definecolor{backcolour}{rgb}{0.95,0.95,0.96}
\lstdefinestyle{mystyle}{
backgroundcolor=\color{backcolour},
commentstyle=\color{codegray},
keywordstyle=\color{codeorange},
numberstyle=\tiny\color{codegray},
stringstyle=\color{codegreen},
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2,
xleftmargin=10pt,
}
\lstset{style=mystyle}
\title{CT255 - Next Gen Technologies II}
\author{Andrew Hayes\\
\AND
Student ID: 21321503\\
\AND
\AND
\AND
\AND
2BCT\\
\AND
University of Galway\\
}
% Uncomment to remove the date
\date{February 2022}
% Uncomment to override the `A preprint' in the header
\renewcommand{\headeright}{2D Games Programming in Java}
\renewcommand{\undertitle}{2D Games Programming in Java}
\renewcommand{\shorttitle}{}
%%% Add PDF metadata to help others organize their library
%%% Once the PDF is generated, you can check the metadata with
%%% $ pdfinfo template.pdf
% \hypersetup{
% pdftitle={A template for the arxiv style},
% pdfsubject={q-bio.NC, q-bio.QM},
% pdfauthor={David S.~Hippocampus, Elias D.~Striatum},
% pdfkeywords={First keyword, Second keyword, More},
% }
\begin{document}
\maketitle
\newpage
\tableofcontents
\thispagestyle{empty}
\newpage
\setcounter{page}{1}
\section{Lecture 1}
\subsection{2D Co-Ordinate System}
The \textbf{JFrame} class will provide a Window with associated graphics canvas \& a pixel-based
co-ordinate system with the origin at (0,0) on the top \textbf(left).
A JFrame is a top-level window with a title \& a border.
To have access to JFrame and associated methods:
\\
\verb|import java.awt.*;| \\
\verb|import javax.swing.*;|
The top 50 pixels or so are hidden by the window's title bar (depending on the operating system).
\subsection{Basic Graphics in Java}
2D graphics can be drawn using the \verb|Graphics| class.
This provides methods for drawing ``primitives'' (lines, circles, boxes) and also images (.jpg, .png, etc.).
The \verb|paint()| method of the \verb|JFrame| class is automatically invoked whenever it needs to be
painted (system-invoked).
Otherwise, you can force painting to happen via \verb|repaint()| if you need to repaint when the OS
doesn't think that it's needed.
\begin{lstlisting}[language=Java]
public void paint (Graphics g) {
// use the "g" object to draw graphics
}
\end{lstlisting}
\subsection{Drawing Text using Methods of the Graphics Class}
\begin{lstlisting}[language=Java]
public void paint (Graphics g) {
Font f = new Font("Times", Font.PLAIN, 24);
g.setFont(f);
Color c = Color.BLACK;
g.setColor(c);
g.drawString("Pacman!", 20, 60);
}
\end{lstlisting}.
This should be added as a method of the application class.
\section{Lecture 2}
\subsection{Animation with Threads}
\textbf{Animation} is the changing of grahics over time, e.g., moving a spaceship across the screen, changing its position by
one pixel every 0.02 seconds.
One of the best ways to do periodic execution of code is to use \textbf{threads}.
Threads allow multiple taks to run independently/concurrently within a program.
Essentially, this means that we spawn a separate execution ``branch'' that operates independently of our program's main flow of control.
For example, the new thread could repeatedly sleep for 20ms, then carry out an animation, and call \verb|this.repaint()| on the application.
\subsubsection{Implementing Threads in Java}
Your application class should implement the \verb|Runnable| interface, i.e.:
\begin{lstlisting}[language=Java]
public class MyApplication extends JFrame implements Runnable {
}
\end{lstlisting}
Your application now \textbf{must} provide an implementation for the \verb|run()| method, which is executed when a thread is started, serving as its ``main'' function, i.e.:
\begin{lstlisting}[language=Java]
public void run(){
}
\end{lstlisting}
To create \& start a new thread running from your application class:
\begin{lstlisting}[language=Java]
Thread t = new Thread(this);
t.start();
\end{lstlisting}
The typical actions of an animation thread are as follows:
\begin{enumerate}
\item Sleep for (say) 20ms using \verb|Thread.sleep(20);|. Note that you will be \textbf{required} to handle \verb|InterruptedException|.
\item Carry out movement of game objects.
\item Call \verb|this.repaint();| which (indirectly) invokes our \verb|paint(Graphics g)| method.
\item Go back to Step 1.
\end{enumerate}
\subsubsection{Threads Test}
\begin{lstlisting}[language=Java]
import java.awt.*;
import javax.swing.*;
public class ThreadsTest implements Runnable {
public ThreadsTest() {
Thread t = new Thread(this);
t.start();
}
public void run() {
System.out.println("Thread started");
for (int i = 0; i < 15; i++) {
System.out.println("Loop " + i + "Start");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Loop " + i + " end");
}
System.out.println("Thread ended");
}
public static void main(String[] args) {
ThreadsTest tt = new ThreadsTest();
}
}
\end{lstlisting}
\subsection{Game Object Classes}
Games typically have \textbf{game object classes} (spaceships, alines, cars, bullets, etc.).
Numerous instances of each may exist at runtime.
This class encapsulates the data (position, colour, etc.) and code (move, draw, die, etc.) associated with the game object.
Typically, we store these instances in a data structure such as an array, so that during our animation \& painting phases we can iterated through them all and invoke the \verb|animate()| \& \verb|paint()| methods on each instance.
\section{Lecture 03}
\subsection{Handling Keyboard Input}
In GUI-based languages such as Java (with AWT), the mouse \& keyboard are handled as ``\textbf{events}''.
These events may happen at any time.
Events are queued as they happen and are dealt with at the next free, idle time.
AWT handles events coming from the OS by dispatching them to \textit{listeners} registered to those events.
To handle keyboard input:
\begin{enumerate}
\item Make a class that implements \verb|KeyListener|. Make sure that you have an instance of this class.
\item Add this instance as a key listener attached to the \verb|JFrame| that receives the messages from the OS.
The simplest way is to make your JFrame-derived class handle the events it receives itself.
\end{enumerate}
\begin{lstlisting}[language=Java]
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyApplication extends JFrame implements KeyListener {
public MyApplication() {
// send keyboard events arriving into this JFrame to its own event handlers.
addKeyListener(this);
}
// 3 keyboard event handler functions
public void keyPressed(KeyEvent e) {
}
public void keyReleased(Event e) {
}
public void keyTyped(KeyEvent e) {
}
}
\end{lstlisting}
Notes:
\begin{itemize}
\item The \verb|KeyEvent| parameter \verb|e| provides the ``virtual keycode'' of the key that has triggered the event, and constants are defined to match these values, e.g., \verb|KeyEvent.VK_Q| or \verb|KeyEvent.VK_ENTER|.
\item To get the keycode, use \verb|e.getKeyCode()|.
\item For our game applications, our application class will implement both \verb|KeyListener| \& \verb|Runnable|.
\item Note the extra import: \verb|import java.awt.event.*;|.
\end{itemize}
\subsection{Loading \& Displaying Raster Images}
The constructor of the \verb|ImageIcon| class (defined in \verb|javax.swing| loads an image from disk (\verb|.jpg|. \verb|.gif|, or \verb|.png|) and returns it as a new instance of the \verb|ImageIcon| class.
The \verb|getImage()| method of this \verb|ImageIcon| object gives you a useable \verb|Image| class object, which can be displayed in your \verb|paint()| method by the \verb|Graphics| class.
\begin{lstlisting}[language=Java]
import java.awt.*;
import javax.swing.*;
public class DisplayRasterImage extends JFrame {
// member data
private static String workingDirectory;
private Image alienImage;
// constructor
public DisplayRasterImage() {
// set ip JFrame
setBounds(100, 100, 300, 300);
setVisible(true);
// load image from disk. Make sure you have the path right!
ImageIcon icon = new ImageIcon(workingDirectory + "/alien_ship_1.png");
alienImage = icon.getImage();
repaint();
}
// application's paint method (may first happen *before* image is finished loading, hence repaint() above
public void paint(Graphics g) {
// draw a black rectangle on the whole canvas
g.setColor(Color.BLACK);
g.fillRect(0,0,300,300);
// display the image (final argument is an "ImageObserver" object)
g.drawImage(alienImage, 150, 150, null);
}
// application entry point
public static void main(String[] args) {
workingDirectory = System.getProperty("user.dir");
System.out.println("workingDirectory = " + workingDirectory);
DisplayRasterImage d = new DisplayRasterImage();
}
}
\end{lstlisting}
\section{Lecture 04 - Screen Flicker}
Screen flicker is caused by software redrawing a screen out of sync with the screen being refreshed by the graphics hardware,
resulting in a half-drawn image occasionally being displayed.
The solution to screen flicker is to use \textbf{double buffering}.
Double buffering involves first rendering all graphics to an offscreen \textit{memory buffer}.
Then, when finished drawing a frame of animation, flip the offscreen buffer onscreen furing the ``vertical sync'' period.
\verb|java.awt| provides a \verb|BufferStrategy| class that applies the best approach based off the capabilities of the
computer on which the software is running.
\subsection{Implementing Double Buffering}
\begin{enumerate}
\item \verb|import java.awt.image.*;|
\item Add a new member variable to the Application class: \verb|private BufferStrategy strategy;|
\item In the Application class's constructor method:
\begin{lstlisting}[language=Java]
createBufferStrategy(2);
strategy = getBufferStrategy(); \end{lstlisting}
Note that this code should be executed \textbf{after} the JFrame has been displayed, i.e. after \verb|setBounds()|
\& \verb|setVisible()|.
\item At the start of the \verb|paint(Graphics g)| method, include \verb|g = strategy.getDrawGraphics();| to redirect our
drawing calls to the offscreen buffer.
\item At the end of the \verb|paint(Graphics g)| method, include \verb|strategy.show();| to indicate that we want to flip
the buffers.
\end{enumerate}
\section{Lecture 05 - Finishing Space Invaders}
\subsection{Animated 2D Sprites}
To animate a 2D sprite, we can simply load two or more images and alternate or cycle between them.
For our game, switching image once per second (i.e., every 50$\textsuperscript{th}$ redraw is about right).
E.g., use this in a modified \verb|Sprite2D| class.
\begin{lstlisting}[language=Java]
public void paint(Graphics g) {
framesDrawn++;
if (framesDrawn % 100 < 50) {
g.drawImage(myImage, (int) x, (int) y, null);
}
else {
g.drawImage(myImage2, (int) x, (int) y, null);
}
}
\end{lstlisting}
\subsection{Collision Detection}
To detect collisions, we cna simply check for overlapping rectangles.
\begin{lstlisting}[language=Java]
if ( ((x1<x2 && x1+w1>x2) ||(x2<x1 && x2+w2>x1) ) && ( (y1<y2 && y1+h1>y2 ) || (y2<y1 && y2 + h2>y1) ) )
\end{lstlisting}
\subsection{Game States}
Games normally have at least two high-level ``states'', i.e., is the game in progress or are we currently displaying
a menu before the game starts (or after it finishes)?
To do this, we can simply add a boolean member to the application class: \verb|isGameInProgress|.
Depending on the value of this, we can handle various things differently:
\begin{itemize}
\item Keypresses.
\item The \verb|paint()| method.
\item The thread's game loop.
\end{itemize}
\section{Lecture 06 - Conway's Game of Life}
\subsection{Mouse Events}
Mouse events notify when the user uses the mouse (or similar input device) to interact with a component.
Mouse events occur when the pointer enters or exits a component's onscreen area and when the user presses or releases one of the mouse buttons.
Additional events such as mouse movement \& the mouse wheel can be handled by implementing the \verb|MouseMotionListener|
and \verb|MouseWheelListener| interfaces.
\begin{enumerate}
\item Have your class implement \verb|MouseListener|.
\item Add \verb|addMouseListener(this);| to the clas constructor.
\item Implement the methods below:
\begin{lstlisting}[language=Java]
// mouse events which must be implemented for MouseListener
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) { }
\end{lstlisting}
\end{enumerate}
\subsection{Conway's Game of Life: Rules}
\verb|private boolean gameState[][][] new boolean[40][40][2];|
\begin{enumerate}
\item Any live cell with fewer than two live neighbours dies, as if caused by under-population.
\item Any live cell with two or three live neighbours lives on to the next generation.
\item Any live cell with more than three live neighbours dies, as if by overcrowding.
\item Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
\end{enumerate}
Each generation (iteration) of the game is created by applying the above rules simultaneously to every cell in its
preceding generation: births \& deaths occur simultaneously.
To implement this properly, we will need to have two separate game states in memory:
\begin{itemize}
\item One is the ``front buffer'' that we are currently displaying, and which we are checking the above rules on.
\item The other is the ``back buffer'' that we're applying the results of the rules to.
\item The ``back buffer'' will be switched to the ``front'' after applying the rules to every cell.
\end{itemize}
We will check the eight neighbours of each cell as follows:
\begin{lstlisting}[language=java]
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
// count the live neighbours of cell [x][y][0]
for (int xx=-1;xx<=1;xx++) {
for (int yy=-1;yy<=1;yy++) {
if (xx!=0 || yy!=0) {
// check cell [x+xx][y+yy][0]
// but.. what if x+xx==-1, etc. ?
}
}
}
}
}
\end{lstlisting}
Note that we need to define the neighbours for cells at the edges of the map.
The usual procedure is to ``wrap around'' to the opposite side.
\subsection{Another Example of a Cellular Automata Algorithm in Use}
The image below is of an algorithmically-generated cave-like structure, for use in a 2D computer game.
Each of the cells, laid out in a 60x30 grid, either has a wall (denoted by \verb|#|) or a floor (denoted by \verb|.|).
The cellular automata algorithm which generated this output uses the following steps:
\begin{itemize}
\item For each cell, randomly define it as: wall (60\% chance) or floor (40\% chance).
\item Perform the following procedure four times: Calculate the number of wall neighbours for each cell, and
define each cell which has at least 5 neighbouring wall cells, as a wall cell itself.
Otherwise (i.e., if it has less than 5 wall neighbours), define it as a floor cell.
\end{itemize}
\begin{center}
\includegraphics[width=0.6\textwidth]{cave.png}
\end{center}
\section{Week 8}
\subsection{Reading from Text Files}
The \verb|java.io| provides file handling classes:
\begin{itemize}
\item \verb|FileReader| to read from a text file.
\item \verb|BufferedFileReader| to read from a text file more efficiently (reads larger blocks \& buffers/caches them).
\begin{itemize}
\item \textit{Exception handling is required.}
\item Uses the \verb|FileReader| class constructor to open a file.
\item Uses the \verb|readLine()| method to read a line of text (which returns a \verb|String|).
\item Uses the \verb|close()| method to close the file.
\end{itemize}
\end{itemize}
Sample code that reads just one line from the file (stopping at the end of the file or when a carriage return is encountered):
\begin{lstlisting}[language=java]
String filename = "C:\\Users\\Sam\\Desktop\\lifegame.txt";
String textinput = null;
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
textinput = reader.readLine();
reader.close();
}
catch (IOException e) { }
\end{lstlisting}
Sample code that reads all the carriage return-separated lines from a file:
\begin{lstlisting}[language=java]
String line=null;
String filename = "C:\\Users\\Sam\\Desktop\\lifegame.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
do {
try {
line = reader.readLine();
// do something with String here!
} catch (IOException e) { }
}
while (line != null);
reader.close();
} catch (IOException e) { }
\end{lstlisting}
\subsection{Writing to Text Files}
Use the \verb|FileWriter| \& \verb|BufferedWriter| classes:
\verb|BufferedWriter|:
\begin{enumerate}
\item Use the \verb|FileWriter| class constructor to open a file.
\item Use the \verb|write(String s)| method to write a line to the file (with a CR appended automatically).
\item Use the \verb|close()| method to close the file.
\end{enumerate}
E.g., to write a single String to a file:
\begin{lstlisting}[language=java]
String filename = "C:\\Users\\Sam\\Desktop\\lifegame.txt";
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
writer.write(outputtext);
writer.close();
}
catch (IOException e) { }
\end{lstlisting}
\subsection{Handling Mouse Motion Events}
In addition to mouse button events, we can also receive mouse \textit{movement} events.
Have the class implement the \verb|MouseMotionListener| interface as well as \verb|MouseListener|.
In the application class constructor have: \verb|addMouseMotionListener(this);|.
Add these methods (receives the same data as the mouse events we have already seeen):
\begin{lstlisting}[language=Java]
public void mouseMoved(MouseEvent e)
public void mouseDragged(MouseEvent e)
\end{lstlisting}
This is useful for making it less tedious to create a new initial game set-up.
\section{A* Pathfinding}
The fundamental operations of the \textbf{A*} algorithm is to traverse a map by exploring promising positions (nodes) beginning at a starting location, witht the goal of finding the best route to a target location.
Each node has four attributes, other than its position on the map:
\begin{itemize}
\item $g$ is the cost of getting from the starting node to this node.
\item $h$ is the heuristic (estimated) cost of getting from this node to the target node.
$h$ is a best guess, since the algorithm does not yet know the actual cost.
\item $f$ is the sum of $g$ \& $h$, and is the algorithm;s best current estimate as to the total cost of travelling from the starting location to the target location via this node.
\item \textit{parent} is the identity of the node which connected to this node along a potential solution path.
\end{itemize}
The algorithm maintains two lists of nodes: the \textbf{open} list \& the \textbf{closed} list.
\begin{itemize}
\item The open list consists of nodes to which the algorithm has already found a route, i.e. one of its connected neighbours has been evaluated (\textit{expanded}) but which have not yet themselves been expanded.
\item The closed list consists of nodes that have been expanded and which therefore should not be re-visited.
\end{itemize}
Progress is made by identifying the most promising node in the open list, i.e., the one with the lowest $f$ value, and expanging it by adding each of its connected neighbours to the open list, unless they are
already closed.
As nodes are expanded, they are moved to the closed list.
As nodes are added to the open list, their $f$, $g$, $h$, \& \textit{parent} values are recorded.
The $g$ value of a node is, of course, equal to the $g$ value of its parent plus the cost of moving from the parent to the node itself.
\begin{center}
\includegraphics[width=0.7\textwidth]{astar.png}
\end{center}
\subsection{Implementing A* Pathfinding}
\bibliographystyle{unsrtnat}
\bibliography{references}
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,264 @@
\NeedsTeXFormat{LaTeX2e}
\ProcessOptions\relax
% fonts
\renewcommand{\rmdefault}{ptm}
\renewcommand{\sfdefault}{phv}
% set page geometry
\usepackage[verbose=true,letterpaper]{geometry}
\AtBeginDocument{
\newgeometry{
textheight=9in,
textwidth=6.5in,
top=1in,
headheight=14pt,
headsep=25pt,
footskip=30pt
}
}
\widowpenalty=10000
\clubpenalty=10000
\flushbottom
\sloppy
\newcommand{\headeright}{Ph.D. Confirmation Report}
\newcommand{\undertitle}{Ph.D. Confirmation Report}
\newcommand{\shorttitle}{\@title}
\usepackage{fancyhdr}
\fancyhf{}
\pagestyle{fancy}
\renewcommand{\headrulewidth}{0.4pt}
\fancyheadoffset{0pt}
\rhead{\scshape \footnotesize \headeright}
\chead{\shorttitle}
\cfoot{\thepage}
%Handling Keywords
\def\keywordname{{\bfseries \emph{Keywords}}}%
\def\keywords#1{\par\addvspace\medskipamount{\rightskip=0pt plus1cm
\def\and{\ifhmode\unskip\nobreak\fi\ $\cdot$
}\noindent\keywordname\enspace\ignorespaces#1\par}}
% font sizes with reduced leading
\renewcommand{\normalsize}{%
\@setfontsize\normalsize\@xipt\@xiipt
\abovedisplayskip 7\p@ \@plus 2\p@ \@minus 5\p@
\abovedisplayshortskip \z@ \@plus 3\p@
\belowdisplayskip \abovedisplayskip
\belowdisplayshortskip 4\p@ \@plus 3\p@ \@minus 3\p@
}
\normalsize
\renewcommand{\small}{%
\@setfontsize\small\@xpt\@xipt
\abovedisplayskip 6\p@ \@plus 1.5\p@ \@minus 4\p@
\abovedisplayshortskip \z@ \@plus 2\p@
\belowdisplayskip \abovedisplayskip
\belowdisplayshortskip 3\p@ \@plus 2\p@ \@minus 2\p@
}
\renewcommand{\footnotesize}{\@setfontsize\footnotesize\@ixpt\@xpt}
\renewcommand{\scriptsize}{\@setfontsize\scriptsize\@viipt\@viiipt}
\renewcommand{\tiny}{\@setfontsize\tiny\@vipt\@viipt}
\renewcommand{\large}{\@setfontsize\large\@xiipt{14}}
\renewcommand{\Large}{\@setfontsize\Large\@xivpt{16}}
\renewcommand{\LARGE}{\@setfontsize\LARGE\@xviipt{20}}
\renewcommand{\huge}{\@setfontsize\huge\@xxpt{23}}
\renewcommand{\Huge}{\@setfontsize\Huge\@xxvpt{28}}
% sections with less space
\providecommand{\section}{}
\renewcommand{\section}{%
\@startsection{section}{1}{\z@}%
{-2.0ex \@plus -0.5ex \@minus -0.2ex}%
{ 1.5ex \@plus 0.3ex \@minus 0.2ex}%
{\large\bf\raggedright}%
}
\providecommand{\subsection}{}
\renewcommand{\subsection}{%
\@startsection{subsection}{2}{\z@}%
{-1.8ex \@plus -0.5ex \@minus -0.2ex}%
{ 0.8ex \@plus 0.2ex}%
{\normalsize\bf\raggedright}%
}
\providecommand{\subsubsection}{}
\renewcommand{\subsubsection}{%
\@startsection{subsubsection}{3}{\z@}%
{-1.5ex \@plus -0.5ex \@minus -0.2ex}%
{ 0.5ex \@plus 0.2ex}%
{\normalsize\bf\raggedright}%
}
\providecommand{\paragraph}{}
\renewcommand{\paragraph}{%
\@startsection{paragraph}{4}{\z@}%
{1.5ex \@plus 0.5ex \@minus 0.2ex}%
{-1em}%
{\normalsize\bf}%
}
\providecommand{\subparagraph}{}
\renewcommand{\subparagraph}{%
\@startsection{subparagraph}{5}{\z@}%
{1.5ex \@plus 0.5ex \@minus 0.2ex}%
{-1em}%
{\normalsize\bf}%
}
\providecommand{\subsubsubsection}{}
\renewcommand{\subsubsubsection}{%
\vskip5pt{\noindent\normalsize\rm\raggedright}%
}
% float placement
\renewcommand{\topfraction }{0.85}
\renewcommand{\bottomfraction }{0.4}
\renewcommand{\textfraction }{0.1}
\renewcommand{\floatpagefraction}{0.7}
\newlength{\@abovecaptionskip}\setlength{\@abovecaptionskip}{7\p@}
\newlength{\@belowcaptionskip}\setlength{\@belowcaptionskip}{\z@}
\setlength{\abovecaptionskip}{\@abovecaptionskip}
\setlength{\belowcaptionskip}{\@belowcaptionskip}
% swap above/below caption skip lengths for tables
\renewenvironment{table}
{\setlength{\abovecaptionskip}{\@belowcaptionskip}%
\setlength{\belowcaptionskip}{\@abovecaptionskip}%
\@float{table}}
{\end@float}
% footnote formatting
\setlength{\footnotesep }{6.65\p@}
\setlength{\skip\footins}{9\p@ \@plus 4\p@ \@minus 2\p@}
\renewcommand{\footnoterule}{\kern-3\p@ \hrule width 12pc \kern 2.6\p@}
\setcounter{footnote}{0}
% paragraph formatting
\setlength{\parindent}{\z@}
\setlength{\parskip }{5.5\p@}
% list formatting
\setlength{\topsep }{4\p@ \@plus 1\p@ \@minus 2\p@}
\setlength{\partopsep }{1\p@ \@plus 0.5\p@ \@minus 0.5\p@}
\setlength{\itemsep }{2\p@ \@plus 1\p@ \@minus 0.5\p@}
\setlength{\parsep }{2\p@ \@plus 1\p@ \@minus 0.5\p@}
\setlength{\leftmargin }{3pc}
\setlength{\leftmargini }{\leftmargin}
\setlength{\leftmarginii }{2em}
\setlength{\leftmarginiii}{1.5em}
\setlength{\leftmarginiv }{1.0em}
\setlength{\leftmarginv }{0.5em}
\def\@listi {\leftmargin\leftmargini}
\def\@listii {\leftmargin\leftmarginii
\labelwidth\leftmarginii
\advance\labelwidth-\labelsep
\topsep 2\p@ \@plus 1\p@ \@minus 0.5\p@
\parsep 1\p@ \@plus 0.5\p@ \@minus 0.5\p@
\itemsep \parsep}
\def\@listiii{\leftmargin\leftmarginiii
\labelwidth\leftmarginiii
\advance\labelwidth-\labelsep
\topsep 1\p@ \@plus 0.5\p@ \@minus 0.5\p@
\parsep \z@
\partopsep 0.5\p@ \@plus 0\p@ \@minus 0.5\p@
\itemsep \topsep}
\def\@listiv {\leftmargin\leftmarginiv
\labelwidth\leftmarginiv
\advance\labelwidth-\labelsep}
\def\@listv {\leftmargin\leftmarginv
\labelwidth\leftmarginv
\advance\labelwidth-\labelsep}
\def\@listvi {\leftmargin\leftmarginvi
\labelwidth\leftmarginvi
\advance\labelwidth-\labelsep}
% create title
\providecommand{\maketitle}{}
\renewcommand{\maketitle}{%
\par
\begingroup
\renewcommand{\thefootnote}{\fnsymbol{footnote}}
% for perfect author name centering
\renewcommand{\@makefnmark}{\hbox to \z@{$^{\@thefnmark}$\hss}}
% The footnote-mark was overlapping the footnote-text,
% added the following to fix this problem (MK)
\long\def\@makefntext##1{%
\parindent 1em\noindent
\hbox to 1.8em{\hss $\m@th ^{\@thefnmark}$}##1
}
\thispagestyle{empty}
\@maketitle
\@thanks
%\@notice
\endgroup
\let\maketitle\relax
\let\thanks\relax
}
% rules for title box at top of first page
\newcommand{\@toptitlebar}{
\hrule height 2\p@
\vskip 0.25in
\vskip -\parskip%
}
\newcommand{\@bottomtitlebar}{
\vskip 0.29in
\vskip -\parskip
\hrule height 2\p@
\vskip 0.09in%
}
% create title (includes both anonymized and non-anonymized versions)
\providecommand{\@maketitle}{}
\renewcommand{\@maketitle}{%
\vbox{%
\hsize\textwidth
\linewidth\hsize
\vskip 0.8in
\@toptitlebar
\centering
{\LARGE\sc \@title\par}
\@bottomtitlebar
\vskip 0.5in
\textsc{\Large\undertitle}\\
\vskip 2.0in
\def\And{%
\end{tabular}\hfil\linebreak[0]\hfil%
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}\ignorespaces%
}
\def\AND{%
\end{tabular}\hfil\linebreak[4]\hfil%
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}\large\ignorespaces%
}
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}\Large\@author\end{tabular}%
\vskip 1.0in \@minus 0.1in \center{\large\@date} \vskip 0.2in
}
}
% add conference notice to bottom of first page
\newcommand{\ftype@noticebox}{8}
\newcommand{\@notice}{%
% give a bit of extra room back to authors on first page
\enlargethispage{2\baselineskip}%
\@float{noticebox}[b]%
\footnotesize\@noticestring%
\end@float%
}
% abstract styling
\renewenvironment{abstract}
{
\centerline
{\large \bfseries \scshape Abstract}
\begin{quote}
}
{
\end{quote}
}
\endinput

Binary file not shown.