Compare commits

..

79 Commits

Author SHA1 Message Date
Max
865b5e0c52 animationspeed of rick edited 2021-07-01 11:39:33 +02:00
Max
d28a29df45 Spider anzahl fixed 2021-07-01 11:02:17 +02:00
Max
b85a36bf14 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-07-01 11:00:34 +02:00
Max
66d36c4ea2 Rick added 2021-07-01 11:00:27 +02:00
Tim
d46d25115e Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-07-01 10:58:44 +02:00
Tim
5f0b827fab better coin alignment 2021-07-01 10:58:42 +02:00
Tim
ca40e4c01a Coin collect animation 2021-07-01 10:47:37 +02:00
Max
21790ecd7a Create rick_sprite_sheet.png 2021-07-01 10:40:17 +02:00
Max
da5c5571b2 Rickroll added 2021-07-01 10:37:24 +02:00
Tim
af51d3776e door colors on maps 2021-07-01 10:23:46 +02:00
e818037d75 Coin Counter added 2021-07-01 08:41:45 +02:00
Malin.sieckmann
3e99a2ebc2 door textures finally added! WOOP WOOP 2021-06-30 19:05:06 +02:00
Malin.sieckmann
dc9a08c9ee Added DoorTiles Textures 2021-06-30 19:05:05 +02:00
Asecave
58a41725eb Snakes drop coins now 2021-06-30 19:01:57 +02:00
Asecave
d440ad8f67 Coins can be collected 2021-06-30 18:03:47 +02:00
Asecave
f386ef49f6 added coin entity 2021-06-30 17:14:43 +02:00
Asecave
3a65c74546 Show boundingbox info/debug with 'o' 2021-06-30 17:08:57 +02:00
Asecave
e643ec092d added class AnimatedEntity between LivingEntity and Entity 2021-06-30 17:06:29 +02:00
Asecave
c035253790 Entity vs Entity collision 2021-06-30 15:47:17 +02:00
a5eed792e7 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-30 13:33:45 +02:00
cbc30b0ac5 class Sounds and sounds with ids added 2021-06-30 13:33:22 +02:00
Max
d150a613c4 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-30 13:33:20 +02:00
Max
ec74176426 Disco sprite sheet added 2021-06-30 13:32:26 +02:00
Tim
28b9404fe9 added default texture 2021-06-30 13:32:05 +02:00
Asecave
b7da4535d7 new map structure 2021-06-29 15:37:26 +02:00
Asecave
f36c861726 player can take damage 2021-06-28 23:04:39 +02:00
0b521ca667 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-28 22:56:58 +02:00
1f1f5bbc68 Added special classes for Inventory and Herzen 2021-06-28 22:56:52 +02:00
Asecave
12c57e1c3c Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-28 22:28:04 +02:00
Asecave
52a59d2808 doors always lead to other rooms 2021-06-28 22:27:58 +02:00
Malin.sieckmann
657c7bab9e left door added/ improved, 3D wall added, shadow added 2021-06-28 21:45:51 +02:00
Asecave
23eba51e5c performance fix 2021-06-28 15:45:48 +02:00
Tim
1555acd781 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-28 09:49:41 +02:00
Tim
4f76c1eaa8 performace 2021-06-28 09:49:21 +02:00
08a67a8a24 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-28 09:38:20 +02:00
595b9b26d9 Shaking Hearts added 2021-06-28 09:37:25 +02:00
a0f632608a Merge remote-tracking branch 'origin/master' 2021-06-28 09:37:18 +02:00
fc17421e0b Inventory HUD Implementation 2021-06-28 09:37:08 +02:00
Tim
a6726b5e25 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-28 09:08:55 +02:00
Tim
88580aec12 Doors working 2021-06-28 09:08:51 +02:00
Malin.Sieckmann
9e6dca2a43 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-28 08:59:37 +02:00
Malin.Sieckmann
a0abdd8aa8 Adding inventar picture 1st test 2021-06-28 08:59:32 +02:00
0d2d9c8dbf Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda
# Conflicts:
#	Zoelda/src/main/items/Item.java
2021-06-28 08:30:54 +02:00
d6acbbec29 Items lil bit 2021-06-28 08:23:55 +02:00
74e82abbb0 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-27 23:04:04 +02:00
805ae2a960 New engine for displaying Hearts (Big Brain) 2021-06-27 23:03:55 +02:00
Asecave
e19165c6c8 WIP: doors 2021-06-27 22:26:51 +02:00
83120aef20 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-27 20:32:37 +02:00
8cdf1c22d4 Added new Prototype for Heart HUD 2021-06-27 20:29:00 +02:00
Asecave
71621b0110 fixed loader 2021-06-27 20:27:38 +02:00
Asecave
b63f505030 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-27 18:27:14 +02:00
Asecave
54641a4c29 WIP: doors 2021-06-27 18:26:58 +02:00
04Mlg04
06432bd55b Spider mirrored
true mit false vertauscht
2021-06-27 15:31:23 +02:00
04Mlg04
fa21364a3f Spider death animation+ tracking added 2021-06-27 15:29:43 +02:00
Asecave
2f0aea175c Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-27 14:50:43 +02:00
Asecave
9fda8275f8 Combat done 2021-06-27 14:50:36 +02:00
Malin.sieckmann
bdff9e5ffb Edit Corridor
modified stone floor (lighting), centered corridor
2021-06-27 14:35:31 +02:00
Asecave
4b630769d5 MEHR FPSSSS yay 2021-06-27 13:46:04 +02:00
Asecave
eefbd17b26 snake fix 2021-06-26 23:15:45 +02:00
Asecave
4e6e4198f4 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-25 22:58:20 +02:00
Asecave
39e7e91dd4 death fix 2021-06-25 22:57:31 +02:00
Malin.sieckmann
4cd9c2559a Added Map01, Map02
New Area (big hall)
2021-06-25 22:52:28 +02:00
88369aed53 Inventory weiter vervollständigt
hinzufügen von weiteren gettern und settern sowie switch methoden um Inventarplätze zu wechseln
2021-06-25 22:16:27 +02:00
04Mlg04
6a100c8b88 Spider added 2021-06-25 20:27:03 +02:00
04Mlg04
1bb7c7ca7a Doublicate Variable Bug fixed
Spider und Snake wurden zwei mal neu geadded
2021-06-25 19:45:45 +02:00
Malin.sieckmann
d747e1f94c added tutorial map, comments ger -> eng 2021-06-25 19:37:55 +02:00
Malin.sieckmann
e415e7cbbb Lil fix
accidently deleted smth before. added it again.
2021-06-25 19:37:26 +02:00
Asecave
0a6d76da3a fixing snake 2021-06-25 18:39:42 +02:00
371a4b8be4 Grundgerüst für Inventory hinzugefügt
Unfertig aber ich mach das schon ;))
Container größtenteils schon fertig, werde wahrscheinlich noch ein paar hinzufügen müssen. Muss außerdem noch zum HUD verbunden werden, das würde ich auch machen, wenn das niemand vor mir macht. Ich hätte an eine box gedacht, in der das ausgewählte Item angezeigt wird und das Item wird mit einer taste gewechselt.
2021-06-25 00:10:35 +02:00
91aadb61e6 Minor fixes and Style improvements
Getter und Setter für Entity.velX und velY hinzugefügt, weil diese Protected sind und sonst Errors auslösen, Außerdem diese in Player.java implementiert
Gitignore um intellij stuff erweitert
2021-06-24 23:58:53 +02:00
dec597e550 Prototype HP HUD added 2021-06-24 22:36:47 +02:00
351240b464 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-24 15:03:43 +02:00
953aa20d83 Added class HUD + startet hp HUD 2021-06-24 15:03:27 +02:00
Malin.sieckmann
7aa013cc7f Stone Texture floor added
+ added into corridor
2021-06-24 14:44:53 +02:00
Tim
3b424d4c98 sanke damage animation attempt 2021-06-24 11:17:24 +02:00
Tim
14e85df71c new Entity help methods
line of sight and vector to entity
2021-06-24 10:57:03 +02:00
Tim
8bab8d02ed corrent dist method 2021-06-24 10:30:54 +02:00
Asecave
758c944ec6 Merge branch 'master' of https://git.ngb.schule/Tim/Zoelda 2021-06-23 23:11:29 +02:00
Asecave
38e9266696 code format 2021-06-23 23:11:17 +02:00
67 changed files with 1602 additions and 356 deletions

4
.gitignore vendored
View File

@@ -5,3 +5,7 @@
.classpath
.project
*.log
/.idea/
/out/
/Zoelda.iml
/bin/

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,77 @@
package main;
import ea.Ticker;
import main.entities.player.Player;
import main.maps.Map;
public class DoorTile extends Tile implements Ticker {
public static final int TOP = 0;
public static final int BOTTOM = 1;
public static final int LEFT = 2;
public static final int RIGHT = 3;
private int side;
private DoorTile connected;
private Map map;
private boolean waitForLeave;
public DoorTile(int id, float x, float y, Map map) {
super(id, x, y);
this.map = map;
}
@Override
public void tick() {
if (Main.instance.getWorld() != null) {
Player player = Main.instance.getWorld().getPlayer();
float dist = player.dist(posX + 0.5f, posY + 0.5f);
if (dist < 0.5f) {
if (!waitForLeave) {
if (connected != null) {
Main.instance.getWorld().changeMap(this);
}
}
} else {
waitForLeave = false;
}
}
}
public int getSide() {
return side;
}
public void setSide(int side) {
this.side = side;
}
public void setConnectedDoor(DoorTile door) {
connected = door;
}
public DoorTile getConnectedDoor() {
return connected;
}
public Map getMap() {
return map;
}
public void waitForLeave() {
waitForLeave = true;
}
@Override
public DoorTile clone() {
DoorTile t = new DoorTile(getID(), posX, posY, map);
t.setConnectedDoor(connected);
t.side = side;
t.map = map;
return t;
}
public void setMap(Map map) {
this.map = map;
}
}

View File

@@ -0,0 +1,28 @@
package main.HUD;
import java.awt.Graphics2D;
import ea.BoundingRechteck;
import ea.Knoten;
import main.Main;
public class HUD extends Knoten{
public final Herzen herzen;
public final Inventory inventory;
public HUD() {
herzen = new Herzen();
inventory = new Inventory();
add(herzen);
add(inventory);
Main.instance.manager.anmelden(herzen, 60);
Main.instance.manager.anmelden(inventory, 50);
}
@Override
public void zeichnen(Graphics2D g, BoundingRechteck r) {
herzen.zeichnen(g);
inventory.zeichnen(g);
}
}

View File

@@ -0,0 +1,114 @@
package main.HUD;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import ea.Knoten;
import ea.Ticker;
import main.Main;
public class Herzen extends Knoten implements Ticker{
private final static int SCALE = 50;
private BufferedImage volles_Herz;
private BufferedImage halbes_Herz;
private BufferedImage leeres_Herz;
private BufferedImage hauptBild;
private BufferedImage[] HPLeiste;
private boolean shakingSwitch;
private float HPVel = 0.3f;
private int counter = 0;
private float lastHP;
private int y;
private int HPLeisteY[];
public Herzen() {
// inizialisieren der Variablen, laden der Bilder und für den ticker anmelden
HPLeiste = new BufferedImage[5];
HPLeisteY = new int [HPLeiste.length];
try {
hauptBild = ImageIO.read(HUD.class.getResourceAsStream("/res/images/icons.png"));
} catch (IOException e) {
e.printStackTrace();
}
BufferedImage buff;
// volles_Herz:
buff = hauptBild.getSubimage(16, 0, 16, 16);
volles_Herz = buff;
// halbes_Herz:
buff = hauptBild.getSubimage(32, 0, 16, 16);
halbes_Herz = buff;
// leeres_Herz
buff = hauptBild.getSubimage(48, 0, 16, 16);
leeres_Herz = buff;
HPLeiste[0] = volles_Herz;
HPLeiste[1] = volles_Herz;
HPLeiste[2] = volles_Herz;
}
private int shakeY() {
shakingSwitch = !shakingSwitch;
if (shakingSwitch == true) {
return 3;
}
return 0;
}
private int regenY() {
if (HPVel > 0) {
if (counter < HPLeiste.length + 1) {
counter++;
if (counter * 4 < HPLeiste.length + 1) {
return 3;
} else {
return 0;
}
} else {
counter = 0;
}
}
return 0;
}
// wird alle 200ms ausgeführt:
public void tick() {
// teilt den Wert der HP in Teile auf, welche der Anzahl der Herzen entspricht
// und prüft dann für den eigenen Teil des Herzens, ob das jeweilige Herz voll,
// halb oder leer ist (BIG BRAIN):
HPVel = Main.instance.getWorld().getPlayer().getHP() - lastHP;
lastHP = Main.instance.getWorld().getPlayer().getHP();
float localeHP;
for (int i = 0; i < HPLeiste.length; i++) {
localeHP = Main.instance.getWorld().getPlayer().getHP();
localeHP -= ((float) i) * (1f / HPLeiste.length);
if (localeHP <= 0f) {
HPLeiste[i] = leeres_Herz;
} else if (localeHP < (1 / (float) (2 * HPLeiste.length))) {
HPLeiste[i] = halbes_Herz;
} else if (localeHP > 1 / (float) (2 * HPLeiste.length)) {
HPLeiste[i] = volles_Herz;
}
}
if(Main.instance.getWorld().getPlayer().getHP() < 0.33f) {
y = shakeY();
} else {
for (int i = 0; i < HPLeiste.length; i++) {
HPLeisteY[i] = regenY();
}
}
}
// Zeichnet alle Herzen im Array HPLeiste[] auf den Bildschirm
public void zeichnen(Graphics2D g) {
for (int i = 0; i < HPLeiste.length; i++) {
if(Main.instance.getWorld().getPlayer().getHP() < 0.33f) {
g.drawImage(HPLeiste[i], (i + 2) * SCALE, y , SCALE, SCALE, null);
} else {
g.drawImage(HPLeiste[i], (i + 2) * SCALE, HPLeisteY[i] , SCALE, SCALE, null);
}
}
}
}

View File

@@ -0,0 +1,51 @@
package main.HUD;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import ea.Knoten;
import ea.Ticker;
import main.Main;
import main.entities.player.PlayerInventory;
import main.worlds.World;
public class Inventory extends Knoten implements Ticker {
private static final int SCALE = 50;
private BufferedImage inventoryFrame;
private BufferedImage coinCounterIcon;
private PlayerInventory inventory;
public Inventory() {
inventory = Main.instance.getWorld().getPlayer().getInventory();
try {
inventoryFrame = ImageIO.read(HUD.class.getResourceAsStream("/res/images/inventory.png"));
coinCounterIcon = ImageIO.read(HUD.class.getResourceAsStream("/res/images/coins.png"));
} catch (IOException e) {
e.printStackTrace();
}
coinCounterIcon = coinCounterIcon.getSubimage(0, 20, 7, 4);
}
public void style(Graphics2D g) {
Font currentFont = g.getFont();
Font newFont = currentFont.deriveFont(Font.BOLD, 20);
g.setFont(newFont);
}
public void zeichnen(Graphics2D g) {
style(g);
g.drawImage(inventoryFrame, 0, 0, SCALE * 2, SCALE * 2, null);
g.drawString(String.valueOf(inventory.getCoins()), SCALE + 10, 145);
g.drawImage(coinCounterIcon, 0, 125, coinCounterIcon.getWidth() * World.SCALE_FACTOR,
coinCounterIcon.getHeight() * World.SCALE_FACTOR, null);
}
// wird alle 50ms ausgef<65>hrt:
public void tick() {
}
}

View File

@@ -1,31 +1,43 @@
package main;
import ea.Game;
import ea.Taste;
import main.HUD.HUD;
import main.worlds.TestWorld;
import main.worlds.World;
/**
* Von hier wird alles initialisiert. Das ist die höchste Klasse.
*/
public class Main extends Game {
public static Main instance;
public static boolean SHOW_DEBUG = false;
private World world;
public static final int WIDTH = 1440; // Fensterbreite
public static final int HEIGHT = 1056; // Fensterhöhe
private HUD hud;
private Sounds sounds;
public Main() {
super(WIDTH, HEIGHT);
super(World.SCALE * 15, World.SCALE * 11, 16);
instance = this;
// Welt initialisieren und Spieler hinzufügen
world = new World();
// die Welt zu EA hinzufügen
// Welt initialisieren und Spieler hinzufügen und die Welt zu EA hinzufügen
world = new TestWorld();
manager.anmelden(world.getPlayer(), 20);
world.start();
wurzel.add(world);
hud = new HUD();
wurzel.add(hud);
// sounds = new Sounds();
// sounds.playSound(2);
}
@Override
public void tasteReagieren(int code) {
if (code == Taste.O) {
SHOW_DEBUG = !SHOW_DEBUG;
}
}
public World getWorld() {

View File

@@ -11,45 +11,47 @@ import ea.internal.gra.PixelFeld;
public class SheetLoader {
private static Figur[] figures;
private Figur[] figures;
private BufferedImage sheet;
/**
* Macht aus einem Spritesheet Figuren.
* @param path - Der pfad zum sheet
* @param width - die Breite von einem Bild
* @param height - die Höhe von einem Bild (nicht das ganze sheet)
*
* @param path - Der pfad zum sheet
* @param width - die Breite von einem Bild
* @param height - die Höhe von einem Bild (nicht das ganze sheet)
* @param lengths - die Anzahl der Frames der verschiedenen Animationen
*/
public SheetLoader(String path, int width, int height, int[] frames) {
public SheetLoader(String path) {
try {
// Bild laden
BufferedImage sheet = ImageIO.read(Tile.class.getResourceAsStream(path));
// Anzahl der Animationen
int rows = frames.length;
// Sprites anordnen *magie*
PixelFeld[][] sprites = new PixelFeld[rows][];
for (int i = 0; i < frames.length; i++) {
sprites[i] = new PixelFeld[frames[i]];
}
for (int i = 0; i < sprites.length; i++) {
loadSprites(sprites[i], i, width, height, sheet);
}
Figur fig;
figures = new Figur[rows];
for (int i = 0; i < figures.length; i++) {
fig = new Figur();
fig.animationSetzen(sprites[i]);
figures[i] = fig;
}
sheet = ImageIO.read(Tile.class.getResourceAsStream(path));
} catch (IOException e) {
e.printStackTrace();
}
}
public void generateFigures(int width, int height, int[] frames) {
// Anzahl der Animationen
int rows = frames.length;
// Sprites anordnen *magie*
PixelFeld[][] sprites = new PixelFeld[rows][];
for (int i = 0; i < frames.length; i++) {
sprites[i] = new PixelFeld[frames[i]];
}
for (int i = 0; i < sprites.length; i++) {
loadSprites(sprites[i], i, width, height, sheet);
}
Figur fig;
figures = new Figur[rows];
for (int i = 0; i < figures.length; i++) {
fig = new Figur();
fig.animationSetzen(sprites[i]);
figures[i] = fig;
}
}
public Figur getFigur(int y) {
return figures[y];
}

View File

@@ -0,0 +1,45 @@
package main;
import ea.Sound;
public class Sounds {
private Sound[] sounds;
public Sounds() {
sounds = new Sound[6];
for(int i = 0; i < sounds.length; i++) {
sounds[i] = new Sound(getPathFromId(i));
}
}
public void playSound(int id) {
sounds[id].play();
}
public void loopSound(int id) {
sounds[id].loop();
}
public void stopSound(int id) {
sounds[id].stop();
}
private String getPathFromId(int id) {
switch(id) {
case 0:
return "/res/sounds/Water-Balloon-Maniacs.mp3";
case 1:
return "/res/sounds/Runaway-Food-Truck.mp3";
case 2:
return "/res/sounds/Hypnotic-Puzzle2.mp3" ;
case 3:
return "/res/sounds/Game-Menu_v001.mp3" ;
case 4:
return "/res/sounds/Blob-Monsters-on-the-Loose.mp3";
case 5:
return "/res/sounds/And-the-Machines-Came-at-Midnight.mp3";
default:
return null;
}
}
}

View File

@@ -7,6 +7,7 @@ import javax.imageio.ImageIO;
import ea.Bild;
import ea.Knoten;
import main.worlds.World;
/**
* Ein feld auf der Map
@@ -14,47 +15,74 @@ import ea.Knoten;
public class Tile extends Knoten {
// IDs der Tiles
public static final int VOID = -1;
public static final int GRASS = 0;
public static final int WALL_TOP = 1;
public static final int WALL_BOTTOM = 2;
public static final int STONE_WALL = 3;
public static final int STONE_WALL_BOTTOM = 4;
public static final int STONE_FLOOR = 5;
public static final int STONE_FLOOR_SHADOW_LEFT = 6;
public static final int DOOR_LEFT = 7;
public static final int DOOR_RIGHT_LEFT_TOP = 8;
public static final int DISCO = 9;
public static final int DOOR_RIGHT = 10;
public static final int DOOR_TOP = 11;
public static final int DOOR_BOTTOM = 12;
private Bild img; // Bild, das gerendert wird
private int id; // Die id dises Tiles
private int id; // Die id dises Tiles//
protected float posX, posY; // Position dieses Tiles
private static Bild[] images;
/**
* @param id
* @param x - X-Koordinate in units
* @param y - Y-Koordinate in units
* @param x - X-Koordinate in units
* @param y - Y-Koordinate in units
*/
public Tile(int id, float x, float y) {
this.id = id;
// Das Bild laden
try {
BufferedImage buff = ImageIO.read(Tile.class.getResourceAsStream(getPathFromId(id)));
// Gras hat 8 verschiedene Texturen von denen eine zufällig ausgewählt werden
// muss.
if (id == GRASS) {
buff = buff.getSubimage(16 * (int) (Math.random() * 8), 0, 16, 16);
}
// Skalieren
BufferedImage scaled = new BufferedImage(World.SCALE, World.SCALE, BufferedImage.TYPE_INT_RGB);
scaled.getGraphics().drawImage(buff, 0, 0, World.SCALE, World.SCALE, null);
img = new Bild(x * World.SCALE, y * World.SCALE, scaled);
} catch (IOException e) {
e.printStackTrace();
if (images == null) {
loadImages();
}
this.id = id;
posX = x;
posY = y;
if (id != VOID) {
img = images[id].clone();
img.positionSetzen(posX * World.SCALE, posY * World.SCALE);
// Bild zu EA hinzuf<75>gen.
add(img);
}
}
private static void loadImages() {
images = new Bild[13];
for (int i = 0; i < images.length; i++) {
try {
BufferedImage buff = ImageIO.read(Tile.class.getResourceAsStream(getPathFromId(i)));
// Gras hat 8 verschiedene Texturen von denen eine zufaellig ausgewaehlt werden
// muss.
if (i == GRASS) {
buff = buff.getSubimage(16 * (int) (Math.random() * 8), 0, 16, 16);
}
// Skalieren
BufferedImage scaled = new BufferedImage(World.SCALE, World.SCALE, BufferedImage.TYPE_INT_RGB);
scaled.getGraphics().drawImage(buff, 0, 0, World.SCALE, World.SCALE, null);
images[i] = new Bild(0, 0, scaled);
} catch (IOException e) {
e.printStackTrace();
}
}
// Bild zu EA hinzufügen.
add(img);
}
/**
* @return den Pfad der zu der Id gehört.
* @return den Pfad der zu der Id gehoert.
*/
private String getPathFromId(int id) {
private static String getPathFromId(int id) {
switch (id) {
case GRASS:
return "/res/images/tiles/grass.png";
@@ -66,14 +94,30 @@ public class Tile extends Knoten {
return "/res/images/tiles/stone_wall.png";
case STONE_WALL_BOTTOM:
return "/res/images/tiles/stone_wall_bottom.png";
case STONE_FLOOR:
return "/res/images/tiles/stone_floor.png";
case STONE_FLOOR_SHADOW_LEFT:
return "/res/images/tiles/stone_floor_shadow_left.png";
case DOOR_LEFT:
return "/res/images/tiles/door_left.png";
case DOOR_RIGHT_LEFT_TOP:
return "/res/images/tiles/door_right_left_top.png";
case DISCO:
return "/res/images/tiles/disco_sprite_sheet.png";
case DOOR_RIGHT:
return "/res/images/tiles/door_right.png";
case DOOR_TOP:
return "/res/images/tiles/door_top.png";
case DOOR_BOTTOM:
return "/res/images/tiles/door_bottom.png";
}
return null;
}
/**
* @return die Größe der Textur
* @return die Groesse der Textur
*/
public static int getSize() {
private static int getSize() {
return 16;
}
@@ -81,36 +125,53 @@ public class Tile extends Knoten {
* @return ob man durch das Tile durchgehen kann
*/
public boolean isCollidable() {
// Alle Tiles durch die man nicht laufen soll müssen hier true zurückgeben,
// sonst werden sie bei der Collisiondetection nicht berücksichtigt.
return id == WALL_TOP || id == STONE_WALL ;
// Alle Tiles durch die man nicht laufen soll muessen hier true zurueckgeben,
// sonst werden sie bei der Collisiondetection nicht ber<EFBFBD>cksichtigt.
return id == WALL_TOP || id == STONE_WALL;
}
/**
* Kleine Hifsmethode un die koordinate der Top-Kante rurückzugenben.
* Kleine Hifsmethode um die Koordinate der Top-Kante zurueckzugenben.
*/
public int getTop() {
return positionY();
}
/**
* Kleine Hifsmethode un die koordinate der Bottom-Kante rurückzugenben.
* Kleine Hifsmethode um die Koordinate der Bottom-Kante zurueckzugenben.
*/
public int getBottom() {
return positionY() + getSize();
}
/**
* Kleine Hifsmethode un die koordinate der Left-Kante rurückzugenben.
* Kleine Hifsmethode um die Koordinate der Left-Kante zurueckzugenben.
*/
public int getLeft() {
return positionX();
}
/**
* Kleine Hifsmethode un die koordinate der Right-Kante rurückzugenben.
* Kleine Hifsmethode um die Koordinate der Right-Kante zurueckzugenben.
*/
public int getRight() {
return positionX() + getSize();
}
public int getID() {
return id;
}
public float getPosX() {
return posX;
}
public float getPosY() {
return posY;
}
@Override
public Tile clone() {
return new Tile(id, posX, posY);
}
}

View File

@@ -1,52 +0,0 @@
package main;
import ea.Knoten;
import main.entities.Entity;
import main.entities.Player;
import main.entities.Snake;
import main.entities.Spider;
import main.maps.Corridor;
import main.maps.Map;
import main.maps.TestMap;
/**
* Hier werden alle Maps gespeichert.
*/
public class World extends Knoten {
public static final int SCALE_FACTOR = 6; // Der Basis Zoomfaktor
public static final int SCALE = SCALE_FACTOR * Tile.getSize(); // Eine Gameunit ist so viele pixel lang
private Map currentMap; // Die Map die aktuell angezeigt werden soll.
public World() {
// Map initialisieren
currentMap = new TestMap();
// Map zu EA hinzufügen
add(currentMap);
// und Entities auch
Player player = new Player();
add(player.actionFigur);
currentMap.getEntities().add(player);
Spider spider = new Spider();
// und Spinnen auch
add(spider.actionFigur);
currentMap.getEntities().add(spider);
Snake snake = new Snake();
add(snake.actionFigur);
currentMap.getEntities().add(snake);
// Alle Entities als ticker registrieren (triggert dann die update methoden)
for (Entity e : currentMap.getEntities()) {
Main.instance.manager.anmelden(e, 20);
}
}
public Map getCurrentMap() {
return currentMap;
}
}

View File

@@ -0,0 +1,77 @@
package main.entities;
import java.awt.Color;
import java.awt.Graphics2D;
import ea.ActionFigur;
import ea.BoundingRechteck;
import ea.Figur;
import ea.internal.gra.PixelFeld;
import main.Main;
import main.worlds.World;
public abstract class AnimatedEntity extends Entity {
public ActionFigur actionFigur; // Sprite des Entities
protected float spriteScale = 1f; // Skalierung des Sprites
protected float spriteOffsetX, spriteOffsetY; // Offset des Sprites. Hier kann man die relative render-Position
// nachjustieren.
protected boolean side;
private static Figur noTexture = new Figur();
static {
PixelFeld[] img = new PixelFeld[1];
img[0] = new PixelFeld(16, 16, 1);
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
img[0].farbeSetzen(x, y, Color.MAGENTA);
}
}
noTexture.animationSetzen(img);
}
public AnimatedEntity() {
actionFigur = new ActionFigur(noTexture, "undefined") {
// DEBUG: render boxes
@Override
public void zeichnen(Graphics2D g, BoundingRechteck r) {
super.zeichnen(g, r);
if (Main.SHOW_DEBUG) {
g.setColor(Color.CYAN);
g.drawRect((int) actionFigur.positionX(), (int) actionFigur.positionY(),
(int) actionFigur.getBreite(), (int) actionFigur.getHoehe());
g.setColor(Color.GREEN);
g.drawRect((int) ((posX - width / 2) * World.SCALE), (int) ((posY - height / 2) * World.SCALE),
(int) (width * World.SCALE), (int) (height * World.SCALE));
}
}
};
}
@Override
protected void update() {
checkTileCollision(Main.instance.getWorld().getCurrentMap());
checkEntityCollision(Main.instance.getWorld().getCurrentMap());
// Packt das Sprite an die richtige Stelle
actionFigur.faktorSetzen((int) (spriteScale * World.SCALE_FACTOR));
float offsetX = width / 2 + spriteOffsetX - width / 2;
float offsetY = height / 2 + spriteOffsetY - height / 2;
actionFigur.positionSetzen((posX + offsetX) * World.SCALE - actionFigur.getBreite() / 2,
(posY + offsetY) * World.SCALE - actionFigur.getHoehe() / 2);
}
/**
* Spiegelt die figur autmatisch, wenn nötig.
*/
protected void zustandSetzen(String name) {
actionFigur.spiegelXSetzen(side);
if (!actionFigur.aktuellesVerhalten().equals(name)) {
actionFigur.zustandSetzen(name);
actionFigur.aktuelleFigur().animationsBildSetzen(0);
}
}
}

View File

@@ -0,0 +1,57 @@
package main.entities;
import main.Main;
import main.SheetLoader;
import main.entities.player.Player;
public class Coin extends AnimatedEntity {
private static SheetLoader loader = new SheetLoader("/res/images/coins.png");
private boolean moveToCounterAnimation;
private float animationDestX = 0.2f;
private float animationDestY = 2.0f;
public Coin() {
loader.generateFigures(8, 8, new int[] { 8, 8, 1 });
loader.getFigur(0).animationsGeschwindigkeitSetzen(100);
loader.getFigur(1).animationsGeschwindigkeitSetzen(100);
loader.getFigur(2).animationsGeschwindigkeitSetzen(100);
actionFigur.neuerZustand(loader.getFigur(0), "gold");
actionFigur.neuerZustand(loader.getFigur(1), "silver");
actionFigur.neuerZustand(loader.getFigur(2), "bronze");
zustandSetzen("bronze");
posX = 4f;
posY = 4f;
width = 0.375f;
height = 0.25f;
spriteOffsetY = -0.1f;
enablePushBack = false;
}
@Override
protected void update() {
super.update();
if (moveToCounterAnimation) {
float distX = animationDestX - posX;
float distY = animationDestY - posY;
posX += distX / 10f;
posY += distY / 10f;
if (distX < 0.05f && distX > -0.05f && distY < 0.05f && distY > -0.05f) {
deleteEntity();
Main.instance.getWorld().getPlayer().getInventory().addCoins(1);
}
}
}
@Override
public void onEntityCollision(Entity e) {
if (e instanceof Player && !moveToCounterAnimation) {
moveToCounterAnimation = true;
enableTileCollisions = false;
}
}
}

View File

@@ -1,6 +1,9 @@
package main.entities;
import ea.Ticker;
import ea.Vektor;
import main.Main;
import main.Tile;
import main.maps.Map;
/*
@@ -14,6 +17,9 @@ public abstract class Entity implements Ticker {
protected float accelleration = 0.012f; // Beschleunigung des entities in gameunits pro frame.
protected float friction = 0.2f; // Entschleunigung des entities in gameunits pro frame.
protected float width = 1f, height = 1f; // Breite und Höhe der Hitbox.
private boolean deleteEntity; // Wenn true wird dieses Entity von der map gelöscht
protected boolean enablePushBack = true; // Ob das Entity von anderen Entities weggedrückt werden kann.
protected boolean enableTileCollisions = true; // Ob das Entity von Wänden abprallen soll
// Das ist die Ticker-Methode von ea; wird jeden frame ausgeführt (frameloop)
@Override
@@ -45,12 +51,16 @@ public abstract class Entity implements Ticker {
/**
* Checkt collision mit tiles von der map. Fertig, clean, nie wieder ändern.
*/
public void checkTileCollisions(Map map) {
public void checkTileCollision(Map map) {
if (!enableTileCollisions) {
return;
}
for (int x = (int) (posX - 2); x < posX + 2; x++) {
for (int y = (int) (posY - 2); y < posY + 2; y++) {
if (x >= 0 && x < map.getWidth() && y >= 0 && y < map.getHeight()) {
if (map.getTile(x, y).isCollidable()) {
if (posY + height / 2 > y && posY - height / 2 < y + 1 && posX + width / 2 > x && posX - width / 2 < x + 1) {
if (posY + height / 2 > y && posY - height / 2 < y + 1 && posX + width / 2 > x
&& posX - width / 2 < x + 1) {
float distN = Math.abs((y + 1 + height / 2) - posY);
float distE = Math.abs((x + 1 + width / 2) - posX);
float distS = Math.abs((y - height / 2) - posY);
@@ -71,6 +81,37 @@ public abstract class Entity implements Ticker {
}
}
public void checkEntityCollision(Map map) {
for (int i = 0; i < map.getEntities().size(); i++) {
Entity e = map.getEntities().get(i);
if (e != this) {
float esize = (e.getWidth() + e.getHeight()) / 2;
float size = (width + height) / 2;
float dist = dist(e);
float sizes = esize / 2 + size / 2;
if (dist < sizes) {
if (enablePushBack && e.enablePushBack) {
float overlap = dist - sizes;
float xDist = e.posX - posX;
float yDist = e.posY - posY;
if (xDist == 0f) {
xDist = (float) (Math.random() - 0.5f) * 0.01f;
}
if (yDist == 0f) {
yDist = (float) (Math.random() - 0.5f) * 0.01f;
}
posX += (overlap * xDist);
posY += (overlap * yDist);
}
onEntityCollision(e);
}
}
}
}
public void onEntityCollision(Entity e) {
}
/**
* Gehört mit zur collision detection. Hier werden kollisionen aufgelöst.
*/
@@ -100,12 +141,123 @@ public abstract class Entity implements Ticker {
posX = blockX - width / 2;
}
}
/**
* @return die entifernung zu diesem Entity
*/
public float dist(Entity e) {
return (float) Math.sqrt(e.posX * e.posX + posY * posY);
return (float) Math.sqrt((e.posX - posX) * (e.posX - posX) + (e.posY - posY) * (e.posY - posY));
}
/**
* @return die entifernung zu dieser Koordinate
*/
public float dist(float x, float y) {
return (float) Math.sqrt((x - posX) * (x - posX) + (y - posY) * (y - posY));
}
/**
* Generiert einen vektor von diesm Entity zu einem anderen
*/
public Vektor vectorToEntity(Entity e) {
Vektor v = new Vektor(e.posX - posX, e.posY - posY);
;
if (v.x == 0 && v.y == 0) {
return new Vektor(0.001f, 0.001f);
}
return v;
}
protected boolean lineOfSightClear(Entity e) {
Vektor direct = vectorToEntity(e).normiert();
direct = direct.teilen(4f);
Vektor loc = new Vektor(posX, posY);
float lastDist;
float dist = Float.MAX_VALUE;
boolean clear = true;
do {
loc = loc.summe(direct);
lastDist = dist;
dist = Math.abs(e.posX - loc.x) + Math.abs(e.posY - loc.y);
Tile t = Main.instance.getWorld().getCurrentMap().getTile((int) loc.x, (int) loc.y);
if (t != null && t.isCollidable()) {
clear = false;
break;
}
} while (dist < lastDist);
return clear;
}
/**
* Gibt den velX Wert zurück.
*
* @return gibt den velX Wert als float zurück.
*/
public float getVelX() {
return velX;
}
/**
* Gibt den velY Wert zurück.
*
* @return gibt den velY Wert als float zurück.
*/
public float getVelY() {
return velY;
}
/**
* Setzt eine neue velX velocity.
*
* @param velX neuer float velX Wert.
*/
public void setVelX(float velX) {
this.velX = velX;
}
/**
* Setzt eine neue Y velocity.
*
* @param velY neuer float velY Wert.
*/
public void setVelY(float velY) {
this.velY = velY;
}
public void setPosX(float x) {
posX = x;
}
public void setPosY(float y) {
posY = y;
}
public void setPos(float x, float y) {
posX = x;
posY = y;
}
public float getPosX() {
return posX;
}
public float getPosY() {
return posY;
}
public void deleteEntity() {
deleteEntity = true;
}
public boolean isReadyToDelete() {
return deleteEntity;
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
}

View File

@@ -1,63 +1,47 @@
package main.entities;
import ea.ActionFigur;
import ea.Figur;
import main.World;
/*
* Alles was zustände hat und sich Bewegen kann, ist ein LivingEntity.
*/
public class LivingEntity extends Entity {
public abstract class LivingEntity extends AnimatedEntity {
protected boolean side; // true = gespiegelt, false = nicht
public ActionFigur actionFigur; // Sprite des Entities
protected float spriteScale = 1f; // Skalierung des Sprites
protected float spriteOffsetX, spriteOffsetY; // Offset des Sprites. Hier kann man die relative render-Position nachjustieren.
protected boolean mirrored; // true = gespiegelt, false = nicht
protected float hp = 1f; //hp des Entitys
protected boolean mirrored;
/**
* @param figur - erstes (standart) Sprite
* @param name - name des Zustands
*/
public LivingEntity(Figur figur, String name) {
actionFigur = new ActionFigur(figur, name) {
// DEBUG: render boxes
// @Override
// public void zeichnen(Graphics2D g, BoundingRechteck r) {
// g.setColor(Color.GREEN);
// g.drawRect((int) actionFigur.positionX(), (int) actionFigur.positionY(), (int) actionFigur.getBreite(), (int) actionFigur.getHoehe());
// g.drawRect((int) ((posX - width / 2) * World.SCALE), (int) ((posY - height / 2) * World.SCALE), (int) (width * World.SCALE), (int) (height * World.SCALE));
// super.zeichnen(g, r);
// }
};
}
@Override
protected void update() {
// Prüft zu welcher seite man guckt
if (velX < 0) {
side = true;
side = !mirrored;
} else if (velX > 0) {
side = false;
side = mirrored;
}
// Packt das Sprite an die richtige Stelle
actionFigur.faktorSetzen((int) (spriteScale * World.SCALE_FACTOR));
float offsetX = width / 2 + spriteOffsetX - width / 2;
float offsetY = height / 2 + spriteOffsetY - height / 2;
actionFigur.positionSetzen((posX + offsetX) * World.SCALE - actionFigur.getBreite() / 2, (posY + offsetY) * World.SCALE - actionFigur.getHoehe() / 2);
if (hp <= 0) {
actionFigur.zustandSetzen(getDeathAnimationName());
velX = 0;
velY = 0;
if (actionFigur.aktuelleFigur().aktuellesBild() == actionFigur.aktuelleFigur().animation().length - 1 && !isReadyToDelete()) {
deleteEntity();
onDeath();
}
}
super.update();
}
/**
* Spiegelt die figur autmatisch, wenn nötig.
*/
protected void zustandSetzen(String name) {
actionFigur.spiegelXSetzen(mirrored ? !side : side);
actionFigur.zustandSetzen(name);
}
protected float getHealthPoints() {
public float getHP() {
return hp;
}
public void takeDamage(float damage, Entity e) {
zustandSetzen(getDamageAnimationName());
actionFigur.aktuelleFigur().animationsBildSetzen(0);
hp -= damage;
}
public abstract String getDeathAnimationName();
public abstract String getDamageAnimationName();
protected void onDeath() {
}
}

View File

@@ -1,87 +0,0 @@
package main.entities;
import ea.Taste;
import main.Main;
import main.SheetLoader;
public class Player extends LivingEntity {
private static SheetLoader loader = new SheetLoader("/res/images/player_sprite_sheet.png", 64, 32, new int[] {5, 8, 7, 6, 2, 5, 4, 7});
public Player() {
super(loader.getFigur(0), "idle");
// Entity-Eigenschaften werden festgelegt
width = 0.7f;
height = 0.8f;
spriteOffsetY = -0.14f;
spriteScale = 0.8f;
posX = 4f;
posY = 4f;
// unterschiedliche Animationsgeschwindigkeiten
// für idle
loader.getFigur(0).animationsGeschwindigkeitSetzen(200);
// fürs laufen
loader.getFigur(1).animationsGeschwindigkeitSetzen(50);
// Zustände werden hinzugefügt
actionFigur.neuerZustand(loader.getFigur(0), "idle");
actionFigur.neuerZustand(loader.getFigur(1), "walk");
actionFigur.neuerZustand(loader.getFigur(2), "strike");
actionFigur.neuerZustand(loader.getFigur(3), "swipe");
actionFigur.neuerZustand(loader.getFigur(7), "die");
}
@Override
protected void update() {
// Bei dieser animation bleibt man sofort stehen.
if (!((actionFigur.aktuellesVerhalten().equals("strike"))
&& actionFigur.aktuelleFigur().aktuellesBild() < actionFigur.aktuelleFigur().animation().length - 1)) {
// Bei diser soll man sich nicht bewegen können aber weiter rutschen
if (!((actionFigur.aktuellesVerhalten().equals("swipe"))
&& actionFigur.aktuelleFigur().aktuellesBild() < actionFigur.aktuelleFigur().animation().length - 1)) {
// wasd movement
if (Main.instance.tasteGedrueckt(Taste.A)) {
velX -= accelleration;
}
if (Main.instance.tasteGedrueckt(Taste.D)) {
velX += accelleration;
}
if (Main.instance.tasteGedrueckt(Taste.W)) {
velY -= accelleration;
}
if (Main.instance.tasteGedrueckt(Taste.S)) {
velY += accelleration;
}
// Auf idle stellen wenn man sich nicht bewegt
if (velX == 0 && velY == 0) {
zustandSetzen("idle");
} else {
zustandSetzen("walk");
}
// Attacken
if (Main.instance.tasteGedrueckt(Taste.LEERTASTE)) {
zustandSetzen("swipe");
}
if (Main.instance.tasteGedrueckt(Taste.Q)) {
zustandSetzen("strike");
}
if (Main.instance.tasteGedrueckt(Taste.F)) {
zustandSetzen("die");
}
}
// auf Kollisionen prüfen
checkTileCollisions(Main.instance.getWorld().getCurrentMap());
// LivingEntity auch updaten lassen
super.update();
} else {
velX = 0;
velY = 0;
}
}
}

View File

@@ -0,0 +1,36 @@
package main.entities;
import main.SheetLoader;
public class Rick extends LivingEntity{
private static SheetLoader loader = new SheetLoader("/res/images/rick_sprite_sheet.png");
public Rick() {
loader.generateFigures(24, 24, new int[] {4});
width = 0.7f;
height = 0.8f;
spriteOffsetY = -0.14f;
spriteScale = 0.8f;
posX = 4f;
posY = 4f;
mirrored = true;
loader.getFigur(0).animationsGeschwindigkeitSetzen(265);
actionFigur.neuerZustand(loader.getFigur(0), "dancin");
zustandSetzen("dancin");
}
@Override
public String getDeathAnimationName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getDamageAnimationName() {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -1,80 +1,95 @@
package main.entities;
import java.util.ArrayList;
import ea.Vektor;
import main.Main;
import main.SheetLoader;
import main.Tile;
import main.entities.player.Player;
public class Snake extends LivingEntity {
private static SheetLoader loader = new SheetLoader("/res/images/snake_spritesheet_calciumtrice.png", 32, 32, new int[] { 10, 10, 10, 10, 10 });
private static SheetLoader loader = new SheetLoader("/res/images/snake_spritesheet_calciumtrice.png");
private float damage = 0.1f;
private boolean attackOnce;
public Snake() {
super(loader.getFigur(0), "idle");
loader.generateFigures(32, 32, new int[] { 10, 10, 10, 10, 13, 8 });
posX = 9f;
posY = 9f;
accelleration = 0.008f;
accelleration = 0.006f;
spriteOffsetY = -0.6f;
width = 0.65f;
height = 0.8f;
mirrored = true;
actionFigur.neuerZustand(loader.getFigur(0), "idle");
actionFigur.neuerZustand(loader.getFigur(1), "lost_sight");
actionFigur.neuerZustand(loader.getFigur(2), "walk");
actionFigur.neuerZustand(loader.getFigur(3), "attack");
actionFigur.neuerZustand(loader.getFigur(4), "die");
actionFigur.neuerZustand(loader.getFigur(4), getDeathAnimationName());
actionFigur.neuerZustand(loader.getFigur(5), getDamageAnimationName());
loader.getFigur(3).animationsGeschwindigkeitSetzen(80);
loader.getFigur(5).animationsGeschwindigkeitSetzen(60);
}
@Override
protected void update() {
ArrayList<Entity> entities = Main.instance.getWorld().getCurrentMap().getEntities();
Entity nearestPlayer = null;
for (Entity e : entities) {
if (e instanceof Player) {
if (nearestPlayer == null || e.dist(this) < nearestPlayer.dist(this)) {
nearestPlayer = e;
Player player = Main.instance.getWorld().getPlayer();
if (!actionFigur.aktuellesVerhalten().equals(getDamageAnimationName())) {
if (lineOfSightClear(player)) {
if (dist(player) < 1f) {
zustandSetzen("attack");
if (actionFigur.aktuelleFigur().aktuellesBild() == 6) {
if (!attackOnce) {
attackOnce = true;
player.takeDamage(damage, this);
}
} else {
attackOnce = false;
}
} else {
Vektor toPlayer = vectorToEntity(player).normiert();
velX += toPlayer.x * accelleration;
velY += toPlayer.y * accelleration;
zustandSetzen("walk");
}
} else {
if (!actionFigur.aktuellesVerhalten().equals("idle")) {
zustandSetzen("lost_sight");
if (actionFigur.aktuelleFigur().aktuellesBild() == actionFigur.aktuelleFigur().animation().length
- 1) {
zustandSetzen("idle");
}
}
}
}
if (nearestPlayer != null && lineOfSightClear(nearestPlayer)) {
Vektor toPlayer = new Vektor(nearestPlayer.posX - posX, nearestPlayer.posY - posY);
toPlayer = toPlayer.normiert();
velX += toPlayer.x * accelleration;
velY += toPlayer.y * accelleration;
zustandSetzen("walk");
} else {
if (actionFigur.aktuellesVerhalten().equals("walk")) {
zustandSetzen("lost_sight");
}
if (actionFigur.aktuellesVerhalten().equals("lost_sight") && actionFigur.aktuelleFigur().aktuellesBild() == actionFigur.aktuelleFigur().animation().length - 1) {
actionFigur.aktuelleFigur().animationsBildSetzen(0);
zustandSetzen("idle");
if (actionFigur.aktuelleFigur().aktuellesBild() == actionFigur.aktuelleFigur().animation().length - 1) {
zustandSetzen("walk");
}
}
this.checkTileCollisions(Main.instance.getWorld().getCurrentMap());
super.update();
}
@Override
public String getDeathAnimationName() {
return "die";
}
@Override
public String getDamageAnimationName() {
return "damage";
}
private boolean lineOfSightClear(Entity e) {
Vektor direct = new Vektor(e.posX - posX, e.posY - posY).normiert();
direct = direct.teilen(4f);
Vektor loc = new Vektor(posX, posY);
float lastDist;
float dist = Float.MAX_VALUE;
boolean clear = true;
do {
loc = loc.summe(direct);
lastDist = dist;
dist = Math.abs(e.posX - loc.x) + Math.abs(e.posY - loc.y);
Tile t = Main.instance.getWorld().getCurrentMap().getTile((int) loc.x, (int) loc.y);
if (t != null && t.isCollidable()) {
clear = false;
break;
}
} while (dist < lastDist);
return clear;
@Override
protected void onDeath() {
int count = (int) (Math.random() * 3);
for (int i = 0; i < count; i++) {
Coin c = new Coin();
float x = posX + (float) Math.random() * width - width / 2;
float y = posY + (float) Math.random() * height - height / 2;
c.setPos(x, y);
Main.instance.getWorld().getCurrentMap().addAnimatedEntity(c);
}
}
}

View File

@@ -1,15 +1,16 @@
package main.entities;
import ea.Vektor;
import main.Main;
import main.SheetLoader;
import main.entities.player.Player;
public class Spider extends LivingEntity {
private static SheetLoader loader = new SheetLoader("/res/images/spider_sprite_sheet.png", 32, 32,
new int[] { 5, 6, 9, 1, 4, 3, 9, 6, 5, 6, 9, 1, 4, 3, 9, 6 });
private static SheetLoader loader = new SheetLoader("/res/images/spider_sprite_sheet.png");
public Spider() {
super(loader.getFigur(0), "walk");
loader.generateFigures(32, 32, new int[] { 5, 3, 6, 9, 9, 8 });
width = 0.7f;
height = 0.8f;
@@ -17,17 +18,55 @@ public class Spider extends LivingEntity {
spriteScale = 0.8f;
posX = 4f;
posY = 4f;
mirrored = true;
actionFigur.neuerZustand(loader.getFigur(0), "idle");
actionFigur.neuerZustand(loader.getFigur(1), "lost_sight");
actionFigur.neuerZustand(loader.getFigur(2), "walk");
actionFigur.neuerZustand(loader.getFigur(3), "attack");
actionFigur.neuerZustand(loader.getFigur(4), getDeathAnimationName());
actionFigur.neuerZustand(loader.getFigur(5), getDamageAnimationName());
loader.getFigur(3).animationsGeschwindigkeitSetzen(80);
loader.getFigur(5).animationsGeschwindigkeitSetzen(40);
}
protected void update() {
// auf Kollisionen prüfen
checkTileCollisions(Main.instance.getWorld().getCurrentMap());
// LivingEntity auch updaten lassen
Player player = Main.instance.getWorld().getPlayer();
if (!actionFigur.aktuellesVerhalten().equals(getDamageAnimationName())) {
if (lineOfSightClear(player)) {
if (dist(player) < 1f) {
zustandSetzen("attack");
} else {
Vektor toPlayer = vectorToEntity(player).normiert();
velX += toPlayer.x * accelleration;
velY += toPlayer.y * accelleration;
zustandSetzen("walk");
}
} else {
if (!actionFigur.aktuellesVerhalten().equals("idle")) {
zustandSetzen("lost_sight");
if (actionFigur.aktuelleFigur().aktuellesBild() == actionFigur.aktuelleFigur().animation().length - 1) {
zustandSetzen("idle");
}
}
}
} else {
if (actionFigur.aktuelleFigur().aktuellesBild() == actionFigur.aktuelleFigur().animation().length - 1) {
zustandSetzen("walk");
}
}
super.update();
velX = 0;
velY = 0;
}
@Override
public String getDeathAnimationName() {
return "die";
}
@Override
public String getDamageAnimationName() {
return "damage";
}
}

View File

@@ -0,0 +1,133 @@
package main.entities.player;
import java.util.ArrayList;
import ea.Taste;
import ea.Vektor;
import main.Main;
import main.SheetLoader;
import main.entities.Entity;
import main.entities.LivingEntity;
public class Player extends LivingEntity {
private static SheetLoader loader = new SheetLoader("/res/images/player_sprite_sheet.png");
private boolean onlyAttackOnceTrigger;
private float range = 1.2f; // die reichweite der Attacke
private PlayerInventory inventory;
public Player() {
loader.generateFigures(64, 32, new int[] { 5, 8, 7, 6, 2, 5, 4, 7 });
// Entity-Eigenschaften werden festgelegt
width = 0.7f;
height = 0.8f;
spriteOffsetY = -0.14f;
spriteScale = 0.8f;
posX = 7.5f;
posY = 5.5f;
// unterschiedliche Animationsgeschwindigkeiten
// f<>r idle
loader.getFigur(0).animationsGeschwindigkeitSetzen(200);
// f<>rs laufen
loader.getFigur(1).animationsGeschwindigkeitSetzen(50);
// Zust<73>nde werden hinzugef<65>gt
actionFigur.neuerZustand(loader.getFigur(0), "idle");
actionFigur.neuerZustand(loader.getFigur(1), "walk");
actionFigur.neuerZustand(loader.getFigur(2), "strike");
actionFigur.neuerZustand(loader.getFigur(3), "swipe");
actionFigur.neuerZustand(loader.getFigur(6), getDamageAnimationName());
actionFigur.neuerZustand(loader.getFigur(7), getDeathAnimationName());
//Spieler Inventar
inventory = new PlayerInventory(5);
}
@Override
protected void update() {
// Bei dieser animation bleibt man sofort stehen.
if (!((actionFigur.aktuellesVerhalten().equals("strike"))
&& actionFigur.aktuelleFigur().aktuellesBild() < actionFigur.aktuelleFigur().animation().length - 1)) {
// Bei diser soll man sich nicht bewegen k<>nnen aber weiter rutschen
if (!((actionFigur.aktuellesVerhalten().equals("swipe")) && actionFigur.aktuelleFigur()
.aktuellesBild() < actionFigur.aktuelleFigur().animation().length - 1)) {
// wasd movement
if (Main.instance.tasteGedrueckt(Taste.A)) {
velX -= accelleration;
}
if (Main.instance.tasteGedrueckt(Taste.D)) {
velX += accelleration;
}
if (Main.instance.tasteGedrueckt(Taste.W)) {
velY -= accelleration;
}
if (Main.instance.tasteGedrueckt(Taste.S)) {
velY += accelleration;
}
// Auf idle stellen wenn man sich nicht bewegt
if (velX == 0 && velY == 0) {
zustandSetzen("idle");
} else {
zustandSetzen("walk");
}
// Attacken
if (Main.instance.tasteGedrueckt(Taste.LEERTASTE)) {
zustandSetzen("swipe");
}
if (Main.instance.tasteGedrueckt(Taste.Q)) {
zustandSetzen("strike");
}
if (Main.instance.tasteGedrueckt(Taste.F)) {
zustandSetzen("die");
}
onlyAttackOnceTrigger = false;
}
// LivingEntity auch updaten lassen
super.update();
} else {
velX = 0;
velY = 0;
}
if (!actionFigur.aktuellesVerhalten().equals(getDamageAnimationName())) {
if (!onlyAttackOnceTrigger && actionFigur.aktuellesVerhalten().equals("swipe")
&& actionFigur.aktuelleFigur().aktuellesBild() == 1) {
onlyAttackOnceTrigger = true;
ArrayList<Entity> entities = Main.instance.getWorld().getCurrentMap().getEntities();
for (Entity e : entities) {
if (e instanceof LivingEntity && e != this && e.dist(this) <= range) {
LivingEntity le = (LivingEntity) e;
if (le.getHP() > 0) {
Vektor toE = vectorToEntity(le);
toE = toE.normiert();
if ((toE.x > 0 && !side) || (toE.x <= 0 && side)) {
le.setVelX(le.getVelX() + toE.x * 0.1f);
le.setVelY(le.getVelY() + toE.y * 0.1f);
le.takeDamage(0.1f, this);
}
}
}
}
}
}
}
public PlayerInventory getInventory() {
return inventory;
}
@Override
public String getDeathAnimationName() {
return "die";
}
@Override
public String getDamageAnimationName() {
return "damage";
}
}

View File

@@ -0,0 +1,114 @@
package main.entities.player;
import main.items.Item;
/**
* Container Klasse für das Inventar des Spielers,
* eventuell später verallgemeinerbar für Truhen o.ä. je nach design dieser.
*/
public class PlayerInventory {
private int coins;
private Item[] items;
private int currentItem;
/**
* Erstellt ein Player Inventar, welches einen Coin counter und ein Item Inventar enthält.
* @param inventorySize Gibt die größe des Item inventars als int an.
*/
public PlayerInventory(int inventorySize){
items = new Item [inventorySize];
currentItem = 0;
}
/**
* Getter für den Coin counter
* @return Gibt die Anzahl der Coins im Inventar als int zurück.
*/
public int getCoins(){
return coins;
}
/**
* Setzt die Anzahl von Coins im Inventar zu angegebener Anzahl.
* @param coins Anzahl an coins als int, die im Inventar sein sollen.
*/
public void setCoins(int coins) {
this.coins = coins;
}
/**
* Fügt die angegebene Anzahl an Coins in das Inventar hinzu.
* @param amount Die Anzahl an Coins als int, die hinzugefügt werden soll.
*/
public void addCoins(int amount){
this.coins+= amount;
}
/**
* Entfernt die angegebene Anzahl an Coins vom Inventar.
* @param amount Die Anzahl an Coins als int, die entfernt werden soll.
*/
public void subtractCoins(int amount){
this.coins-= amount;
}
/**
* Getter für das Items im Inventar.
* @return gibt ein Array mit allen Item Objekten zurück, die im Inventar enthalten sind.
*/
public Item[] getItems(){
return items;
}
/**
* Ersetzt das jetzige Inventar um ein neues mit im Item-Array items angegebenen Items.
* @param items Array mit Items die das Inventar ersetzen sollen.
*/
public void setItems(Item[] items) {
this.items = items;
}
/**
* Entfernt ein Item auf angegebner Position im Item-Array.
* @param itemPosition Position des Items das entfernt werden soll, angegeben als int.
*/
public void removeItem(int itemPosition) {
items[itemPosition]=null;
}
/**
* Setzt das gerade ausgewählte Item fest.
* @param currentItem int gibt an welcher Index des Item Arrays ausgewählt werden soll.
*/
public void setCurrentItem(int currentItem) {
this.currentItem = currentItem;
}
/**
* Wechselt auf den nächsten Slot im Inventar.
*/
public void changeCurrentItem(){
if(currentItem>=items.length) currentItem=0;
else currentItem++;
}
/**
* Methode zum Hinzufügen von Items.
* @param newItem Das Item, dass hinzugefügt werden soll.
* @return gibt zurück ob das Item hinzugefügt wurde, d.h. true wenn hinzugefügt und false wenn nicht hinzugefügt.
*/
public boolean addItem(Item newItem){
for(int i =0;i< items.length;i++) {
if (items[i] == null) {
items[i] = newItem;
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,16 @@
package main.items;
//TODO:Hier soll die Item Oberklasse entstehen
public class Item {
private String icon;
public Item(String iconPath){
icon=iconPath;
}
/**
* Gibt den Pfad zu dem Icon dieses Items an.
* @return String, der den Pfad des Icons dieses Items beschreibt
*/
public String getIconPath(){
return icon;
}
}

View File

@@ -5,22 +5,39 @@ import main.Tile;
public class Corridor extends Map {
public Corridor() {
super(5, 10);
for (int x = 0; x < map.length; x++) {
for (int y = 0; y < map[0].length; y++) {
if((y == 0 || x == 0 || y == 9 || x == 4) && x != 2 ) {
map[x][y] = new Tile(3, x, y);
add(map[x][y]);
} else if(y == 1 && (x != 0 || x != 4)&& x != 2 ) {
map[x][y] = new Tile(4, x, y);
add(map[x][y]);
super(15, 11);
for (int x = 0; x < tiles.length; x++) {
for (int y = 0; y < tiles[0].length; y++) {
// Wand
if ((y == 0 || x == 5 || y == 10 || x == 9) && x != 7 && x >= 5 && x <= 9) {
tiles[x][y] = new Tile(Tile.STONE_WALL, x, y);
add(tiles[x][y]);
}
else {
map[x][y] = new Tile(0, x, y);
add(map[x][y]);
// 3D-Wand
else if (y == 1 && (x != 0 || x != 4) && x != 7 && x >= 6 && x <= 8) {
tiles[x][y] = new Tile(Tile.STONE_WALL_BOTTOM, x, y);
add(tiles[x][y]);
}
// Steinboden
else if (x >= 6 && x <= 8) {
if (x == 7 && (y == 0 || y == tiles[0].length - 1)) {
} else {
tiles[x][y] = new Tile(Tile.STONE_FLOOR, x, y);
add(tiles[x][y]);
}
} else {
tiles[x][y] = new Tile(Tile.VOID, x, y);
add(tiles[x][y]);
}
}
}
}
@Override
public Map clone() {
Corridor c = new Corridor();
c.cloneTiles(this);
return c;
}
}

View File

@@ -0,0 +1,106 @@
package main.maps;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import main.DoorTile;
import main.Tile;
public class ImageMap extends Map {
// Erstellung der abzulesenden Tiles (einem Tile wird eine Farbe zugewiesen)
private static PixelTile[] pixels = {
new PixelTile(Tile.STONE_WALL, new Color(100, 100, 100)),
new PixelTile(Tile.STONE_FLOOR, new Color(127, 127, 127)),
new PixelTile(Tile.VOID, new Color(0, 0, 0)),
new PixelTile(Tile.DOOR_LEFT, new Color(255, 150, 0)),
new PixelTile(Tile.DOOR_RIGHT, new Color(69, 150, 0)),
new PixelTile(Tile.DOOR_BOTTOM, new Color(150, 150, 0)),
new PixelTile(Tile.DOOR_TOP, new Color(0, 147, 150)),
new PixelTile(Tile.STONE_WALL_BOTTOM, new Color(145, 145, 145)),
new PixelTile(Tile.STONE_FLOOR_SHADOW_LEFT, new Color(251, 251, 129)) };
public ImageMap(String path) {
super(15, 11);
try {
BufferedImage img = ImageIO.read(ImageMap.class.getResourceAsStream(path));
if (img.getWidth() != 15 || img.getHeight() != 11) {
System.err.println("Odd map size! Use 15x11");
}
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
int id = Tile.VOID;
int rgb = img.getRGB(x, y);
for (PixelTile t : pixels) {
if (t.c == rgb) {
id = t.id;
break;
}
}
if (id == Tile.DOOR_LEFT) {
DoorTile door = new DoorTile(id, x, y, this);
leftDoor = door;
door.setSide(DoorTile.LEFT);
tiles[x][y] = door;
add(tiles[x][y]);
continue;
}
if (id == Tile.DOOR_RIGHT ) {
DoorTile door = new DoorTile(id, x, y, this);
rightDoor = door;
door.setSide(DoorTile.RIGHT);
tiles[x][y] = door;
add(tiles[x][y]);
continue;
}
if (id == Tile.DOOR_TOP) {
DoorTile door = new DoorTile(id, x, y, this);
topDoor = door;
door.setSide(DoorTile.TOP);
tiles[x][y] = door;
add(tiles[x][y]);
continue;
}
if (id == Tile.DOOR_BOTTOM) {
DoorTile door = new DoorTile(id, x, y, this);
bottomDoor = door;
door.setSide(DoorTile.BOTTOM);
tiles[x][y] = door;
add(tiles[x][y]);
continue;
}
tiles[x][y] = new Tile(id, x, y);
add(tiles[x][y]);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public ImageMap(ImageMap map) {
super(map.getWidth(), map.getHeight());
cloneTiles(map);
}
private static class PixelTile {
public final int c;
public final int id;
public PixelTile(int id, Color c) {
this.c = c.getRGB();
this.id = id;
}
}
@Override
public ImageMap clone() {
return new ImageMap(this);
}
}

View File

@@ -3,42 +3,155 @@ package main.maps;
import java.util.ArrayList;
import ea.Knoten;
import ea.Ticker;
import main.DoorTile;
import main.Main;
import main.Tile;
import main.entities.AnimatedEntity;
import main.entities.Entity;
import main.entities.player.Player;
/**
* Auf der Map sind alle Entities, sowie die Tiles gespiechert.
*/
public abstract class Map extends Knoten {
public abstract class Map extends Knoten implements Ticker {
protected Tile[][] map; // Die Tiles der map in einem 2D Array.
protected Tile[][] tiles; // Die Tiles der map in einem 2D Array.
private ArrayList<Entity> entities;
private boolean started;
public DoorTile topDoor;
public DoorTile leftDoor;
public DoorTile rightDoor;
public DoorTile bottomDoor;
public Map(int width, int height) {
map = new Tile[width][height];
tiles = new Tile[width][height];
entities = new ArrayList<>(100);
Main.instance.manager.anmelden(this, 20);
}
/**
* Gibt das Tile-Objekt an der gegebenen Koordinate zurück. (nur wenn es existiert)
* Gibt das Tile-Objekt an der gegebenen Koordinate zurück. (nur wenn es
* existiert)
*/
public Tile getTile(int x, int y) {
if (x >= 0 && x < map.length && y >= 0 && y < map[0].length) {
return map[x][y];
if (x >= 0 && x < tiles.length && y >= 0 && y < tiles[0].length) {
return tiles[x][y];
}
return null;
}
public int getWidth() {
return map.length;
@Override
public void tick() {
for (int i = 0; i < entities.size(); i++) {
Entity e = entities.get(i);
if (e.isReadyToDelete()) {
if (e instanceof AnimatedEntity) {
entfernen(((AnimatedEntity) e).actionFigur);
}
Main.instance.manager.abmelden(e);
entities.remove(e);
}
}
}
public int getWidth() {
return tiles.length;
}
public int getHeight() {
return map[0].length;
return tiles[0].length;
}
public ArrayList<Entity> getEntities() {
return entities;
}
public void addAnimatedEntity(AnimatedEntity e) {
entities.add(e);
add(e.actionFigur);
if (started) {
Main.instance.manager.anmelden(e, 20);
}
}
public abstract Map clone();
public void cloneTiles(Map map) {
for (int x = 0; x < map.getWidth(); x++) {
for (int y = 0; y < map.getHeight(); y++) {
tiles[x][y] = map.getTile(x, y).clone();
if (tiles[x][y] instanceof DoorTile) {
DoorTile dt = (DoorTile) tiles[x][y];
if (dt.getSide() == DoorTile.TOP) {
topDoor = dt;
topDoor.setMap(this);
}
if (dt.getSide() == DoorTile.BOTTOM) {
bottomDoor = dt;
bottomDoor.setMap(this);
}
if (dt.getSide() == DoorTile.LEFT) {
leftDoor = dt;
leftDoor.setMap(this);
}
if (dt.getSide() == DoorTile.RIGHT) {
rightDoor = dt;
rightDoor.setMap(this);
}
}
add(tiles[x][y]);
}
}
}
public void start() {
if (topDoor != null) {
Main.instance.manager.anmelden(topDoor, 50);
}
if (bottomDoor != null) {
Main.instance.manager.anmelden(bottomDoor, 50);
}
if (leftDoor != null) {
Main.instance.manager.anmelden(leftDoor, 50);
}
if (rightDoor != null) {
Main.instance.manager.anmelden(rightDoor, 50);
}
for (Entity e : entities) {
if (!(e instanceof Player)) {
Main.instance.manager.anmelden(e, 20);
}
}
started = true;
}
public void stop() {
if (topDoor != null) {
Main.instance.manager.abmelden(topDoor);
}
if (bottomDoor != null) {
Main.instance.manager.abmelden(bottomDoor);
}
if (leftDoor != null) {
Main.instance.manager.abmelden(leftDoor);
}
if (rightDoor != null) {
Main.instance.manager.abmelden(rightDoor);
}
for (Entity e : entities) {
if (!(e instanceof Player)) {
Main.instance.manager.abmelden(e);
}
}
started = false;
}
public void connectDoors(DoorTile door, DoorTile door2) {
door.setConnectedDoor(door2);
door2.setConnectedDoor(door);
}
}

View File

@@ -1,17 +0,0 @@
package main.maps;
import main.Tile;
public class TestMap extends Map {
public TestMap() {
super(15, 11);
for (int x = 0; x < map.length; x++) {
for (int y = 0; y < map[0].length; y++) {
map[x][y] = new Tile(Math.random() * 5 < 1 ? 1 : 0, x, y);
add(map[x][y]);
}
}
}
}

View File

@@ -0,0 +1,41 @@
package main.maps;
import main.Tile;
import main.entities.Snake;
import main.entities.Spider;
public class TutorialMap extends Map {
public TutorialMap() {
super(15, 11);
for (int x = 0; x < tiles.length; x++) {
for (int y = 0; y < tiles[0].length; y++) {
//Wand, Sichtschutz
if (y == 0 ||y == tiles[0].length - 1 || x == 0 || x == tiles.length - 1 || ((y == 4|| y == 5) && x == 10 )) {
tiles[x][y] = new Tile (1, x, y);
add(tiles [x][y]);
}
//3D-Wand, 3F-Sichtschutz
else if(y == 1 || ( y == 6 && x == 10)) {
tiles[x][y] = new Tile (2, x, y);
add(tiles [x][y]);
}
//Grasboden
else{
tiles[x][y] = new Tile(0, x, y);
add(tiles[x][y]);
}
}
}
addAnimatedEntity(new Spider());
addAnimatedEntity(new Snake());
}
@Override
public Map clone() {
TutorialMap c = new TutorialMap();
c.cloneTiles(this);
return c;
}
}

View File

@@ -0,0 +1,41 @@
package main.worlds;
import main.entities.Coin;
import main.entities.Rick;
import main.entities.Snake;
import main.entities.Spider;
import main.maps.Map;
public class TestWorld extends World {
public TestWorld() {
super(4);
Map m2 = maps[3].clone();
getCurrentMap().connectDoors(getCurrentMap().bottomDoor, m2.topDoor);
for (int i = 0; i < 15; i++) {
Coin c = new Coin();
c.setPosX(i * 0.5f + 4);
getCurrentMap().addAnimatedEntity(c);
}
for (int i = 0; i < 2; i++) {
Snake s = new Snake();
s.setPosX((float) (Math.random() * 5 + 2));
getCurrentMap().addAnimatedEntity(s);
}
for (int i = 0; i < 3; i++) {
Spider spooda = new Spider();
spooda.setPosX((float) (Math.random() * 5 + 2));
getCurrentMap().addAnimatedEntity(spooda);
}
for (int i = 0; i < 1; i++) {
Rick astley = new Rick();
astley.setPosX((float) (Math.random() * 5 + 2));
getCurrentMap().addAnimatedEntity(astley);
}
}
}

View File

@@ -0,0 +1,67 @@
package main.worlds;
import ea.Knoten;
import main.DoorTile;
import main.entities.player.Player;
import main.maps.ImageMap;
import main.maps.Map;
/**
* Hier werden alle Maps gespeichert.
*/
public abstract class World extends Knoten {
public static final int SCALE_FACTOR = 4; // Der Basis Zoomfaktor
public static final int SCALE = SCALE_FACTOR * 16; // Eine Gameunit ist so viele pixel lang
private Map currentMap; // Die Map die aktuell angezeigt werden soll.
private Player player;
protected static Map[] maps;
public World(int startMap) {
if (maps == null) {
maps = new ImageMap[8];
for (int i = 0; i < maps.length; i++) {
maps[i] = new ImageMap("/res/images/maps/map" + i + "a.png");
}
}
init(maps[startMap]);
}
public World(Map startMap) {
init(startMap);
}
private void init(Map startMap) {
currentMap = startMap;
player = new Player();
add(currentMap);
}
public Map getCurrentMap() {
return currentMap;
}
public Player getPlayer() {
return player;
}
public void changeMap(DoorTile door) {
currentMap.stop();
currentMap.entfernen(player.actionFigur);
entfernen(currentMap);
currentMap = door.getConnectedDoor().getMap();
add(currentMap);
currentMap.add(player.actionFigur);
currentMap.start();
player.setPos(door.getConnectedDoor().getPosX() + 0.5f, door.getConnectedDoor().getPosY() + 0.5f);
door.getConnectedDoor().waitForLeave();
}
public void start() {
currentMap.addAnimatedEntity(player);
currentMap.start();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 450 B