Initial upload

master
Lenz Wiechers 2020-02-17 16:29:50 +01:00
commit 455322ac79
33 changed files with 645 additions and 0 deletions

3
README.txt Normal file
View File

@ -0,0 +1,3 @@
A simple Pac-Man clone.
So far.
About to add Path finding for the Ghosts and an A.I. that controls Pac-Man.

BIN
assets/Blinky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

BIN
assets/Clyde.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

BIN
assets/Inky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

35
assets/Map.txt Normal file
View File

@ -0,0 +1,35 @@
##################################
# # 0 #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # ############################ #
# # P 123 #
##################################
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
##

BIN
assets/Pacman_Down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

BIN
assets/Pacman_Left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

BIN
assets/Pacman_Original.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
assets/Pacman_Right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

BIN
assets/Pacman_Up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

BIN
assets/Pinky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

BIN
assets/brick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

BIN
bin/Brick.class Normal file

Binary file not shown.

BIN
bin/Game.class Normal file

Binary file not shown.

BIN
bin/Ghost.class Normal file

Binary file not shown.

BIN
bin/Main.class Normal file

Binary file not shown.

BIN
bin/Map.class Normal file

Binary file not shown.

BIN
bin/Picture.class Normal file

Binary file not shown.

BIN
bin/Player.class Normal file

Binary file not shown.

BIN
src/Brick.class Normal file

Binary file not shown.

21
src/Brick.java Normal file
View File

@ -0,0 +1,21 @@
// Diese Klasse stellt die einzelnen Bicks (Wände) auf der Map dar.
public class Brick extends Picture { // Die übergeordnete Klasse ist Picture
private static final long serialVersionUID = 5556462651856418189L;
public int xPos; // Position auf dem Frame in x-Richtung
public int yPos; // Position auf dem Frame in y-Richtung
public Brick(int newXPos, int newYPos) { // Erstellen des Konstruktors mit den Koordinaten, an denen sich der Brick
// beefinden soll.
super("brick"); // Aufrufen der übergeordneten Klasse
// Setzen der Positionen:
xPos = newXPos;
yPos = newYPos;
}
}

BIN
src/Game.class Normal file

Binary file not shown.

154
src/Game.java Normal file
View File

@ -0,0 +1,154 @@
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
// In dieser Klasse findet der größte Teil des Spiels statt:
// Rendern von Map, Geistern, Pac-Man etc.
// Überprüfung von Kollisionen verschiedener Elemente (der komplizierteste Teil des Programms)
public class Game {
// Deklaration der sichtbaren Elemente
JFrame frame;
JPanel panel;
Player player;
Ghost ghosts[];
Map map;
// Delta time: siehe https://en.wikipedia.org/wiki/Delta_timing
private long dt;
private long lastT;
private int windowSizeX = 800; // Größe des Frame in x-Richtung
private int windowSizeY = 800; // Größe des Frame in y-Richtung
private int frameLocationX = 100; // Position des Frame auf dem Bildschirm in x-Richtung
private int frameLocationY = 100; // Position des Frame auf dem Bildschirm in x-Richtung
// oben links (0|0)
// nach rechts --> x wird größer
// nach unten --> y wird größer
public Game() { // Erstellen des Konstruktors (Was soll passieren, sobald dieses Klasse
// aufgerufen wird?)
frame = new JFrame(); // Fenster
panel = new JPanel(); // darauf werden alle sichtbaren Elemente gespeichert
ghosts = new Ghost[4]; // 4 Geister
player = new Player(); // Pac-Man
panel.add(player); // Pac-Man wird dem Panel hinzugefügt
frame.addKeyListener(player); // KeyListener wird hinzugefügt, man kann nun Pac-Maan mit der tastatur steuern
// Einstellen des Frame bezüglich Größe und Position
frame.setSize(windowSizeX, windowSizeY);
frame.setLocation(frameLocationX, frameLocationY);
frame.setVisible(false);
frame.setTitle("Pac-Man"); // Der Titel des Frame wird auf "Pac-Man" gesetzt
frame.setResizable(false); // Man kann die Größe des Frame nicht verändern
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Wenn der Frame geschlossen wird, wird auch das Programm
// beendet
// Der Inhalt des Panels wird auf dem Frame angezeigt:
frame.setContentPane(panel);
frame.getContentPane().setLayout(null);
panel.setBackground(Color.BLACK); // Der Hintergrund ist schwarz
for (int i = 0; i < ghosts.length; i++) { // für jeden Geist:
ghosts[i] = new Ghost(i); // Erstellen des jeweiligen Geistes
panel.add(ghosts[i]); // Hinzufügen zum Panel des jeiligen Geistes
ghosts[i].setBounds(ghosts[i].getPos('x', 0), ghosts[i].getPos('y', 0), 20, 20);
}
map = new Map(player, ghosts); // Map auf der gespielt wird
map.mapping();
player.setBounds(player.getPos('x', 0), player.getPos('y', 0), 20, 20); // Pac-Man wird das erste Mal gerendert
for (int i = 0; i < 35; i++) { // für jeden Brick
for (int j = 0; j < 35; j++) { // für jeden Brick
if (Map.bricks[j][i] != null) { // Damit kein Fehler auftritt wegen nicht vorhandenen Bricks
panel.add(Map.bricks[j][i]); // Der jeweilige Brick wird zum panel hinzugefügt
Map.bricks[j][i].setBounds(Map.bricks[j][i].xPos, Map.bricks[j][i].yPos, 20, 20); // Rendern des
}
}
}
frame.setVisible(true);
lastT = System.nanoTime(); // delta time
while (true) { // Hauptschleife
dt = System.nanoTime() - lastT; // delta time
lastT = System.nanoTime(); // delta time
// Zu Beginn jeden Schleifendurchlaufs wird die Position von Pac-Man neu
// gesetzt:
player.setLocation(player.getPos('x', dt), player.getPos('y', dt));
// Aktualiesieren der Positionen der Geister:
for (int i = 0; i < ghosts.length; i++) {
ghosts[i].setLocation(ghosts[i].getPos('x', dt), ghosts[i].getPos('y', dt));
}
player.calcDir(0); // Berechnen wo Pac-Man als nächstes hin soll
// Kollision von Pac-Man mit Bricks:
for (int i = 0; i < 35; i++) { // für jeden Brick
for (int j = 0; j < 35; j++) { // für jeden Brick
if (Map.bricks[j][i] != null) { // Damit kein Fehler auftritt wegen nicht vorhandenen Bricks
if (player.getPos('x', 0) < Map.bricks[j][i].xPos + 20
&& player.getPos('x', 0) > Map.bricks[j][i].xPos - 20
&& player.getPos('y', 0) < Map.bricks[j][i].yPos + 20
&& player.getPos('y', 0) > Map.bricks[j][i].yPos - 20) {
if (player.left) {
player.setPos('x', Map.bricks[j][i].xPos + 20);
player.left = false;
} else if (player.right) {
player.setPos('x', Map.bricks[j][i].xPos - 20);
player.right = false;
} else if (player.up) {
player.setPos('y', Map.bricks[j][i].yPos + 20);
player.up = false;
} else if (player.down) {
player.setPos('y', Map.bricks[j][i].yPos - 20);
player.down = false;
}
}
}
}
}
for (int i = 0; i < ghosts.length; i++) {
if (player.getPos('x', 0) < ghosts[i].getPos('x', 0) + 20
&& player.getPos('x', 0) > ghosts[i].getPos('x', 0) - 20
&& player.getPos('y', 0) < ghosts[i].getPos('y', 0) + 20
&& player.getPos('y', 0) > ghosts[i].getPos('y', 0) - 20) {
player.lives--;
System.out.println(player.lives);
map.mapping();
}
}
delay(10); // Ein delay von 10s zum Ende der Hauptschleife
}
}
// Methode zum verzögern (warten) in ms
public void delay(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

BIN
src/Ghost.class Normal file

Binary file not shown.

43
src/Ghost.java Normal file
View File

@ -0,0 +1,43 @@
// Diese Klasse stellt die einzelnen Geister dar.
public class Ghost extends Picture { // Die übergeordnete Klasse ist Picture
private static final long serialVersionUID = -5352006665147359473L;
private int xPos;
private int yPos;
public Ghost(int index) {
super("Pinky"); // Aufrufen der übergeordneten Klasse
//xPos = 150 + 40 * index;
if (index == 0) {
this.changeSauce("Blinky");
} else if (index == 2) {
this.changeSauce("Inky");
} else if (index == 3) {
this.changeSauce("Clyde");
}
}
public int getPos(char coordinate, long dt) {
if (coordinate == 'x') {
return xPos;
} else if (coordinate == 'y') {
return yPos;
} else
return -1;
}
public void setPos(char coordinate, int newPos) {
if (coordinate == 'x') {
xPos = newPos;
} else if(coordinate == 'y') {
yPos = newPos;
}
}
}

BIN
src/Main.class Normal file

Binary file not shown.

19
src/Main.java Normal file
View File

@ -0,0 +1,19 @@
// Programmiert von Lenz Wiechers im Jahre 2020
/// Hauptdatei
// In dieser Datei wird das Spiel erstellt
// Muss ausgeführt werden zum Starten
public class Main {
@SuppressWarnings("unused") // Die "unused" - Warnungen werden in dieser Datei nicht mehr angezeigt
public static void main(String[] args) {
System.setProperty("sun.java2d.opengl", "true");
Game game = new Game(); // Das Spiel wird gestartet
}
}

BIN
src/Map.class Normal file

Binary file not shown.

67
src/Map.java Normal file
View File

@ -0,0 +1,67 @@
import java.io.BufferedReader;
import java.io.FileReader;
// Diese Klasse ist zuständig für das Laden der Karte
// In der Textdatei map.txt enthalten im "assets" - Ordner kann man anhand von '#' Positionen von Bricks festlegen. Dort wo sich kein '#' befindet, ist also eine Lücke.
public class Map {
public static Brick bricks[][] = new Brick[35][35]; // Zweidimensionales Array für alle Bricks
// Zweidimensionale Arrays siehe
// https://de.wikipedia.org/wiki/Feld_(Datentyp)#Mehrdimensional_/_in-sich-mehrdimensional
BufferedReader reader; // reader zum Einlesen der Text Datei
Player player;
Ghost ghosts[];
String line; // String in dem eingelsene Zeilen der Datei gespeichert werden
public Map(Player player, Ghost ghosts[]) { // Erstellen des Konstruktors
this.ghosts = ghosts;
this.player = player;
}
public void mapping(){
try {
reader = new BufferedReader(new FileReader("assets/map.txt")); // Einlesen der .txt Datei
for (int i = 0; i < 35; i++) { // für die ersten 35 Zeilen der Datei:
String line = reader.readLine(); // Einlesen der jeweiligen Zeile
for (int j = 0; j < 35; j++) { // für die ersten 35 Zeichen der jeweiligen Zeile
try {
if (line.charAt(j) == '#') { // Erkennen ob sich dort ein '#' befindet
bricks[i][j] = new Brick(10 + 20 * j, 10 + 20 * i); // wenn ja, soll an der Stelle ein neuer
// Brick erstellt werden
} else if (line.charAt(j) == 'P') {
player.setPos('x', 10 + 20 * j);
player.setPos('y', 10 + 20 * i);
} else if (line.charAt(j) == '0') {
ghosts[0].setPos('x', 10 + 20 * j);
ghosts[0].setPos('y', 10 + 20 * i);
} else if (line.charAt(j) == '1') {
ghosts[1].setPos('x', 10 + 20 * j);
ghosts[1].setPos('y', 10 + 20 * i);
} else if (line.charAt(j) == '2') {
ghosts[2].setPos('x', 10 + 20 * j);
ghosts[2].setPos('y', 10 + 20 * i);
} else if (line.charAt(j) == '3') {
ghosts[3].setPos('x', 10 + 20 * j);
ghosts[3].setPos('y', 10 + 20 * i);
}
} catch (Exception e) {
}
}
}
} catch (Exception e) { // Falls etwas mit dem Einlesen der Datei schiefläuft:
System.out.println(
"There seems to be an error with the file of the map. Pls use hashes to indicate positions of Walls. ERROR: "
+ e);
}
}
}

BIN
src/Picture.class Normal file

Binary file not shown.

57
src/Picture.java Normal file
View File

@ -0,0 +1,57 @@
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
// Diese Klasse ist die Grundlagee zum Render von Elementen auf dem Frame, anhand der Javax Swing Bibliothek
public class Picture extends JLabel { // Die übergeordnete Klasse ist JLabel
private static final long serialVersionUID = 3916370092871263037L;
BufferedImage pic; // pic ist das eingelesene Bild
public Picture(String sauce) { // Erstellen des Konstruktors mit der Eingabe sauce --> Name der jeweiligen
// Datei ohne Endung
super(); // Aufrufen der übergeordneten Klasse
try {
pic = ImageIO.read(new File("assets/" + sauce + ".png")); // Einlesen der Datei aus dem "assets" - Ordner
this.setIcon(new ImageIcon(pic)); // Das eingelesene BufferedImage pic wird auf das JLabel (diese Klasse)
// geladen
} catch (IOException ex) {
// Falls es ein Problem mit dem Einlesen der Datei gibt:
JOptionPane.showMessageDialog(null, "Please check your file paths", "Error", JOptionPane.ERROR_MESSAGE);
}
}
// Methode zum auswählen eines anderen Bildes ohne ein neues Objekt erstellen zu
// müssen
public void changeSauce(String newSauce) {
try {
pic = ImageIO.read(new File("assets/" + newSauce + ".png"));
this.setIcon(new ImageIcon(pic));
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Please check your file paths", "Error", JOptionPane.ERROR_MESSAGE);
}
}
}

BIN
src/Player.class Normal file

Binary file not shown.

246
src/Player.java Normal file
View File

@ -0,0 +1,246 @@
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
// Diese Klasse stellt die vom Spieler mit den Pfeiltasten gestuerte Figur --> Pac-Man dar
public class Player extends Picture implements KeyListener { // extends Picture --> Jeder 'Player' ist auch ein
// 'Picture'
// implements KeyListener --> Benötigt zum Erkennen von
// gedrückten Tasten.
private static final long serialVersionUID = -4225811153447791553L;
private float xPos; // Position auf dem Frame in x-Richtung
private float yPos; // Position auf dem Frame in y-Richtung
public int lives = 3;
private float speed = 0.00000014f; // Diee Geschwindigkeit von Pac-man. In alle Richtungen gleich. Muss so klein
// sein wegen delta time
public long timer; // Variable die speichert zu welchem Zeitpunkt eine Änderung der Richtung
// vorgenommen wurde, welche nicht sofort durchgeführt wegen kann, wegen einem
// Brick, welcher im Weg ist. --> siehe boolean hui
public int blob = 1000; // Zeit in ms, nachdem die Richtungsangabe auf einer Geraden zurückgesetzt wird
public boolean right; // Boolean der speichert, ob sich Pac-Man gerade nach rechts bewegt (Analog für
// links, oben, unten)
public boolean pressed_right; // Boolean der speichert, ob Pac-Man als nächstes nach rechts gehen soll (Analog
// für links, oben, unten)
public boolean left;
public boolean pressed_left;
public boolean up;
public boolean pressed_up;
public boolean down;
public boolean pressed_down;
private boolean hui; // Boolean zur Abfrage, ob gerade ein Brick im Weg ist, um den aktuellen
// Richtungsbefehl durchzuführen.
public Player() { // Erstellen des Konstruktors
super("Pacman_Right"); // Aufrufen der übergeordneten Klasse (Picture)
}
public void calcDir(int keyCode) { // Methode zum Errechnen der Richtung in die Pacman gerade geht und als nächstes
// gehen soll mit der Eingabe, welche Taste angeschlagen wurde
// keyCode = 37 --> Pfeiltaste nach links
// keyCode = 39 --> Pfeiltaste nach rechts
// keyCode = 38 --> Pfeiltaste nach oben
// keyCode = 40 --> Pfeiltaste nach unten
if (keyCode == 37 || pressed_left && System.currentTimeMillis() - timer <= blob) {
for (int i = 0; i < 35; i++) { // für jeden Brick
for (int j = 0; j < 35; j++) { // für jeden Bick
if (Map.bricks[j][i] != null) { // Damit kein Fehler auftritt wegen nicht vorhandenen Bricks
if (Map.bricks[j][i].xPos + 20 == (int) xPos && (int) yPos < Map.bricks[j][i].yPos + 20
&& (int) yPos > Map.bricks[j][i].yPos - 20) { // wenn Pac-Man gerade rechts an einem
// Brick vorbeistreift:
hui = true; // Pac-Man kann gerade nicht nach links gehen
}
}
}
}
if (!hui) { // wenn links von Pac-Man gerade kein Block ist:
// bewegt sich Pac-Man nun nach links:
left = true;
right = false;
up = false;
down = false;
// und Pac-Man hat keine Richtung in die er als nächstes soll:
pressed_left = false;
pressed_right = false;
pressed_up = false;
pressed_down = false;
// und Pac-Man schaut jetzt nach links
this.changeSauce("Pacman_Left");
} else { // ansonsten:
// soll Pac-Man sich sobald er kann nach links bewegen
pressed_left = true;
pressed_right = false;
pressed_up = false;
pressed_down = false;
if (keyCode == 37) // wenn die Pfeiltaste nach links gedrückt wurde:
timer = System.currentTimeMillis(); // wird der Timer, der angibt, wann der Befehl zum nach links
// Abbiegen eingegeben wurde
}
}
// Analog für rechts, oben, unten:
if (keyCode == 39 || pressed_right && System.currentTimeMillis() - timer <= blob) {
for (int i = 0; i < 35; i++) {
for (int j = 0; j < 35; j++) {
if (Map.bricks[j][i] != null) {
if (Map.bricks[j][i].xPos - 20 == (int) xPos && (int) yPos < Map.bricks[j][i].yPos + 20
&& (int) yPos > Map.bricks[j][i].yPos - 20) {
hui = true;
}
}
}
}
if (!hui) {
left = false;
right = true;
up = false;
down = false;
pressed_left = false;
pressed_right = false;
pressed_up = false;
pressed_down = false;
this.changeSauce("Pacman_Right");
} else {
pressed_left = false;
pressed_right = true;
pressed_up = false;
pressed_down = false;
if (keyCode == 39)
timer = System.currentTimeMillis();
}
}
if (keyCode == 38 || pressed_up && System.currentTimeMillis() - timer <= blob) {
for (int i = 0; i < 35; i++) {
for (int j = 0; j < 35; j++) {
if (Map.bricks[j][i] != null) {
if (Map.bricks[j][i].yPos + 20 == (int) yPos && (int) xPos < Map.bricks[j][i].xPos + 20
&& (int) xPos > Map.bricks[j][i].xPos - 20) {
hui = true;
}
}
}
}
if (!hui) {
left = false;
right = false;
up = true;
down = false;
pressed_left = false;
pressed_right = false;
pressed_up = false;
pressed_down = false;
this.changeSauce("Pacman_Up");
} else {
pressed_left = false;
pressed_right = false;
pressed_up = true;
pressed_down = false;
if (keyCode == 38)
timer = System.currentTimeMillis();
}
}
if (keyCode == 40 || pressed_down && System.currentTimeMillis() - timer <= blob) {
for (int i = 0; i < 35; i++) {
for (int j = 0; j < 35; j++) {
if (Map.bricks[j][i] != null) {
if (Map.bricks[j][i].yPos - 20 == (int) yPos && (int) xPos < Map.bricks[j][i].xPos + 20
&& (int) xPos > Map.bricks[j][i].xPos - 20) {
hui = true;
}
}
}
}
if (!hui) {
left = false;
right = false;
up = false;
down = true;
pressed_left = false;
pressed_right = false;
pressed_up = false;
pressed_down = false;
this.changeSauce("Pacman_Down");
} else {
pressed_left = false;
pressed_right = false;
pressed_up = false;
pressed_down = true;
if (keyCode == 40)
timer = System.currentTimeMillis();
}
}
hui = false; // Muss zurückgesetzt werden
}
// Methoden zur Erkennung von Tastenanschlägen:
public void keyPressed(KeyEvent e) {
calcDir(e.getKeyCode()); // aufrufen von der Methode calcDir mit der Eingabe e.getKeyCode() --> zuletzt
// angeschlagene Taste
}
// Die folgenden 2 Methoden sind zwar leer, müssen jedoch trotzdem existieren,
// damit nicht dauerhaft Fehlermeldungen ausgegeben werden:
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
// Methode zum Errechnen der aktuellen Position
public int getPos(char coordinate, long dt) { // Hier kommt die zuvor erwähnte delta time ins Spiel
if (coordinate == 'x') { // Auslesen der 'x' - Koordinate:
if (left && dt != 0) {
xPos -= speed * dt;
} else if (right && dt != 0) {
xPos += speed * dt;
}
return (int) xPos;
} else if (coordinate == 'y') { // Auslesen der 'y' - Koordinate:
if (down && dt != 0) {
yPos += speed * dt;
} else if (up && dt != 0) {
yPos -= speed * dt;
}
return (int) yPos;
} else {
return -1;
}
}
// Methode zum Setzen einer neuen Position:
public void setPos(char coordinate, int newPos) {
if (coordinate == 'x') {
this.xPos = newPos;
} else if (coordinate == 'y') {
this.yPos = newPos;
}
}
}