|
@ -19,6 +19,9 @@ img.png
|
|||
image.png
|
||||
/maps/
|
||||
/assets/
|
||||
lib/
|
||||
out/
|
||||
project/
|
||||
target/
|
||||
|
||||
TheGame.jar
|
||||
|
|
126
README.md
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Projet programmation 2
|
||||
author: Yohann D'ANELLO
|
||||
author: Yohann D'ANELLO, Édouard Némery
|
||||
---
|
||||
|
||||
# The Game
|
||||
|
@ -30,7 +30,7 @@ Une tour contient également diverses propriétés :
|
|||
* Des dégâts par tir
|
||||
* Une vitesse de tir
|
||||
* Un prix
|
||||
* Une fonction permettant de récupérer les mobs sur lesquels tirer
|
||||
* Une fonction indiquant ce qu'il se passe lorsque la tour tire
|
||||
|
||||
Le jeu fonctionne par tick. Toutes les 50 millisecondes a lieu un tick. Toutes les tours sont mises à jour, puis les
|
||||
mobs se déplacent éventuellement. La vitesse des tours et des mobs influe sur le fait de faire quelque chose pendant le
|
||||
|
@ -43,6 +43,122 @@ Si un mob doit se déplacer, un chemin est calculé jusqu'au bord de la fenêtre
|
|||
de collisions est en effet géré, empêchant 2 mobs ou tours de se trouver au même endroit. Si un tel chemin existe, alors
|
||||
le mob avance d'une case selon ce chemin. Sinon, il reste sur place.
|
||||
|
||||
### Différents mobs
|
||||
|
||||
Il existe différents types de mobs. Ils contiennent 3 propriétés : points de vie (dégâts nécessaires pour être tués),
|
||||
lenteur (nombre de ticks de jeu nécessaires à déclencher un tick chez le mob), butin (nombre de pièces ramassé par
|
||||
le joueur lorsque le mob est tué).
|
||||
|
||||
À chaque tick de mob, une fonction de tick spécifique au mob est appelée, qui permet des actions supplémentaires.
|
||||
|
||||
Les mobs peuvent être gelés, si tel est le cas le nombre de ticks d'attente est multiplié par 2. Par ailleurs, un facteur
|
||||
aléatoire compris entre 0.95 et 1.05 est appliqué.
|
||||
|
||||
#### Mob1
|
||||
|
||||
Ne fait rien de spécial.
|
||||
|
||||
* Points de vie : 2
|
||||
* Lenteur : 50
|
||||
* Butin : 10
|
||||
|
||||
#### Mob2
|
||||
|
||||
Ne fait rien de spécial.
|
||||
|
||||
* Points de vie : 6
|
||||
* Lenteur : 20
|
||||
* Butin : 20
|
||||
|
||||
#### MobStrong
|
||||
|
||||
Ne fait rien de spécial.
|
||||
|
||||
* Points de vie : 50
|
||||
* Lenteur : 100
|
||||
* Butin : 100
|
||||
|
||||
#### MobHealer
|
||||
|
||||
Soigne de 2 points de vie à chacun de ses ticks tous les mobs à 3 blocs à la ronde, à l'exception de lui-même.
|
||||
|
||||
* Points de vie : 20
|
||||
* Lenteur : 60
|
||||
* Butin : 20
|
||||
|
||||
#### MobSpeeder
|
||||
|
||||
Accélère d'un facteur 3 les ticks des mobs à 3 blocs à la ronde, à l'exception de lui-même.
|
||||
|
||||
* Point de vie : 25
|
||||
* Lenteur : 60
|
||||
* Butin : 30
|
||||
|
||||
#### MobBreaker
|
||||
|
||||
Casse les tours sur son passage (à tuer à distance)
|
||||
|
||||
* Points de vie : 110
|
||||
* Lenteur : 120
|
||||
* Butin : 70
|
||||
|
||||
### Différentes tours
|
||||
|
||||
Différentes tours sont à la disposition du joueur, avec des prix différents (rendant toutes les tours non accessibles
|
||||
au début du jeu). Elles ont toutes un nombre de dégât indicatif, un nombre de ticks à attendre entre 2 tirs, et si
|
||||
elle est améliorée ou non (voir UpgradeTower). Elles disposent aussi d'une fonction `shot` précisant l'action de la tour
|
||||
à chaque tir.
|
||||
|
||||
#### BasicTower
|
||||
|
||||
Cette tour tire sur une unique cible aléatoire à 3 blocs à la ronde.
|
||||
|
||||
* Période : 5
|
||||
* Prix : 10
|
||||
* Dégâts : 1 (3 si améliorée)
|
||||
|
||||
#### WallTower
|
||||
|
||||
Cette tour ne fait rien, agit uniquement comme un mur empêchant les mobs de passer par là.
|
||||
|
||||
* Période : +infini
|
||||
* Prix : 5
|
||||
* Dégâts : 0
|
||||
|
||||
#### FreezeTower
|
||||
|
||||
Cette tour ne faît aucun dégât et gêle pendant 40 ticks (2 secondes), 100 ticks (5 secondes) si améliorée, tous les mobs
|
||||
à 3 blocs à la ronde.
|
||||
|
||||
* Période : 10
|
||||
* Prix : 40
|
||||
* Dégâts : 0 (1 si améliorée)
|
||||
|
||||
#### ExploderTower
|
||||
|
||||
Cette tour lance des projectiles explosifs, qui inflige le double des dégâts à la cible ainsi que des dégâts aux mobs
|
||||
présents à 3 blocs à la ronde de ce mob. La portée est de 5 blocs.
|
||||
|
||||
* Période : 20
|
||||
* Prix : 70
|
||||
* Dégâts : 3 (7 si améliorée)
|
||||
|
||||
#### UpgradeTower
|
||||
|
||||
Cette tour améliore de façon permanente toutes les tours à 5 blocs à la ronde (sauf elle-même).
|
||||
|
||||
* Période : 60
|
||||
* Prix : 65
|
||||
* Dégâts : 0 (1 si améliorée)
|
||||
|
||||
#### LaserTower
|
||||
|
||||
Cette tour tire des rayons laser dans les quatre directions et chaque mob reçoit des dégâts.
|
||||
|
||||
* Période : 40
|
||||
* Prix : 80
|
||||
* Dégâts : 3 (8 si améliorée)
|
||||
|
||||
## Implémentation
|
||||
|
||||
Le projet est intégralement fait en Java. On ne détaillera pas ici la partie éditeur de niveau, bien qu'elle soit
|
||||
|
@ -67,10 +183,10 @@ Une case est une position et 3 sprites (couche 1, couche 2, couche 3).
|
|||
Un sprite est une image de taille 16x16, qui contient des informations sur l'endroit où le chercher.
|
||||
|
||||
Un Mob est une classe abstraite contenant des informations abstraites (détaillées plus haut). Un type de mob sera donc
|
||||
une classe héritant de `Mob`, telles que `Mob1`, `Mob2` et `MobCancer`.
|
||||
une classe héritant de `Mob`.
|
||||
|
||||
Il en est de même pour les tours, avec `BasicTower`, `NullTower` et `AutoTower`.
|
||||
Il en est de même pour les tours, qui hérite de `Tower`.
|
||||
|
||||
L'intérêt de l'héritage par rapport à un type donné à une classe Mob (paramètres donnés dans une enumération `MobType`
|
||||
par exemple) est de pouvoir mieux personnaliser les fonctions, par exemple en imaginant des dégâts aléatoires.
|
||||
par exemple) est de pouvoir mieux personnaliser les fonctions, par exemple en intégrant les dégâts aléatoires.
|
||||
|
||||
|
|
BIN
README.pdf
|
@ -0,0 +1,8 @@
|
|||
scalaVersion := "2.13.1"
|
||||
|
||||
name := "TheGame"
|
||||
organization := "fr.ynerant"
|
||||
version := "1.0"
|
||||
|
||||
// https://mvnrepository.com/artifact/net.liftweb/lift-json
|
||||
libraryDependencies += "net.liftweb" %% "lift-json" % "3.4.1"
|
24
compile.sh
|
@ -1,24 +0,0 @@
|
|||
#!/bin/bash
|
||||
chmod +x lib/*.jar
|
||||
rm -rf tmp
|
||||
mkdir tmp
|
||||
javac -cp src/main/java:lib/gson-2.8.6.jar:lib/jopt-simple-6.0-alpha-3.jar \
|
||||
-target 1.9 -source 1.9 \
|
||||
-d tmp --module-path src/main/java \
|
||||
src/main/java/fr/ynerant/leveleditor/api/editor/*.java \
|
||||
src/main/java/fr/ynerant/leveleditor/client/main/*.java \
|
||||
src/main/java/fr/ynerant/leveleditor/editor/*.java \
|
||||
src/main/java/fr/ynerant/leveleditor/frame/*.java \
|
||||
src/main/java/fr/ynerant/leveleditor/game/*.java \
|
||||
src/main/java/fr/ynerant/leveleditor/game/mobs/*.java \
|
||||
src/main/java/fr/ynerant/leveleditor/game/towers/*.java
|
||||
cp -r src/main/resources/* tmp/
|
||||
unzip lib/gson-2.8.6.jar -x META-INF/MANIFEST.MF -d tmp
|
||||
unzip lib/jopt-simple-6.0-alpha-3.jar -x META-INF/MANIFEST.MF -d tmp
|
||||
cd tmp
|
||||
zip -r TheGame.jar *
|
||||
mv TheGame.jar ../
|
||||
cd ..
|
||||
rm -rf tmp
|
||||
chmod +x TheGame.jar
|
||||
echo "Successfully compiled to \"TheGame.jar\". To run: \"java -jar TheGame.jar\"".
|
|
@ -1,52 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
|
||||
public class Case {
|
||||
private int x;
|
||||
private int y;
|
||||
private Sprite couche1;
|
||||
private Sprite couche2;
|
||||
private Sprite couche3;
|
||||
private Collision collision;
|
||||
|
||||
public static Case create(int posX, int posY, Sprite couche1, Sprite couche2, Sprite couche3, Collision collision) {
|
||||
Case c = new Case();
|
||||
c.x = posX;
|
||||
c.y = posY;
|
||||
c.couche1 = couche1;
|
||||
c.couche2 = couche2;
|
||||
c.couche3 = couche3;
|
||||
c.collision = collision;
|
||||
return c;
|
||||
}
|
||||
|
||||
public int getPosX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getPosY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Sprite getCoucheOne() {
|
||||
return couche1;
|
||||
}
|
||||
|
||||
public Sprite getCoucheTwo() {
|
||||
return couche2;
|
||||
}
|
||||
|
||||
public Sprite getCoucheThree() {
|
||||
return couche3;
|
||||
}
|
||||
|
||||
public Collision getCollision() {
|
||||
return collision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{Case x=" + x + " y=" + y + " couche1=" + couche1 + " couche2=" + couche2 + " couche3=" + couche3 + " collision=" + collision.name().toUpperCase() + "}\n";
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor;
|
||||
|
||||
public enum Collision {
|
||||
FULL, PARTIAL, ANY
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import fr.ynerant.leveleditor.editor.Map;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class EditorAPI {
|
||||
private static File LAST_FILE;
|
||||
|
||||
public static RawMap toRawMap(int width, int height) {
|
||||
List<RawCase> cases = new ArrayList<>();
|
||||
|
||||
for (int y = 1; y < height; y += 16) {
|
||||
for (int x = 1; x < width; x += 16) {
|
||||
RawCase c = RawCase.create(x / 16, y / 16, RawSprite.BLANK, RawSprite.BLANK, RawSprite.BLANK, Collision.ANY);
|
||||
cases.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
return RawMap.create(cases, width, height);
|
||||
}
|
||||
|
||||
public static Gson createGson() {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
|
||||
builder.enableComplexMapKeySerialization();
|
||||
builder.serializeNulls();
|
||||
builder.setPrettyPrinting();
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public static JFileChooser createJFC() {
|
||||
JFileChooser jfc = new JFileChooser();
|
||||
|
||||
jfc.setFileFilter(new FileNameExtensionFilter("Fichiers monde (*.gmap, *.dat)", "gmap", "dat"));
|
||||
jfc.setFileHidingEnabled(true);
|
||||
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
File dir = new File("maps");
|
||||
assert dir.mkdirs();
|
||||
jfc.setCurrentDirectory(dir);
|
||||
|
||||
return jfc;
|
||||
}
|
||||
|
||||
public static void saveAs(RawMap map) {
|
||||
JFileChooser jfc = createJFC();
|
||||
File file;
|
||||
jfc.showSaveDialog(null);
|
||||
file = jfc.getSelectedFile();
|
||||
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
if (!file.getName().toLowerCase().endsWith(".gmap") && !file.getName().toLowerCase().endsWith(".dat")) {
|
||||
file = new File(file.getParentFile(), file.getName() + ".gmap");
|
||||
}
|
||||
|
||||
LAST_FILE = file;
|
||||
|
||||
save(file, map);
|
||||
}
|
||||
|
||||
public static void save(RawMap map) {
|
||||
if (LAST_FILE != null)
|
||||
save(LAST_FILE, map);
|
||||
else
|
||||
saveAs(map);
|
||||
}
|
||||
|
||||
public static void save(File file, RawMap map) {
|
||||
String json = createGson().toJson(map);
|
||||
|
||||
try {
|
||||
assert file.createNewFile();
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(file)));
|
||||
|
||||
bos.write(json.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Map open() {
|
||||
JFileChooser jfc = createJFC();
|
||||
File file;
|
||||
|
||||
jfc.showOpenDialog(null);
|
||||
file = jfc.getSelectedFile();
|
||||
|
||||
if (file == null)
|
||||
return null;
|
||||
|
||||
LAST_FILE = file;
|
||||
|
||||
return open(file);
|
||||
}
|
||||
|
||||
public static RawMap getRawMap(File f) {
|
||||
String json = null;
|
||||
try {
|
||||
GZIPInputStream gis = new GZIPInputStream(new BufferedInputStream(new FileInputStream(f)));
|
||||
byte[] bytes = new byte[512 * 1024];
|
||||
int count;
|
||||
StringBuilder text = new StringBuilder();
|
||||
while ((count = gis.read(bytes)) != -1) {
|
||||
text.append(new String(bytes, 0, count, StandardCharsets.UTF_8));
|
||||
}
|
||||
gis.close();
|
||||
|
||||
json = text.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return createGson().fromJson(json, RawMap.class);
|
||||
}
|
||||
|
||||
public static Map open(File f) {
|
||||
return open(getRawMap(f));
|
||||
}
|
||||
|
||||
public static Map open(RawMap map) {
|
||||
if (map.getFont() == null) {
|
||||
int baseWidth = map.getWidth();
|
||||
int baseHeight = map.getHeight();
|
||||
int width = baseWidth + (baseWidth / 16) + 1;
|
||||
int height = baseHeight + (baseHeight / 16) + 1;
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
g.setColor(Color.white);
|
||||
g.fillRect(0, 0, width, height);
|
||||
g.setColor(Color.black);
|
||||
g.drawLine(0, 0, width, 0);
|
||||
g.drawLine(0, 0, 0, height);
|
||||
for (int x = 17; x <= width; x += 17) {
|
||||
g.drawLine(x, 0, x, height);
|
||||
}
|
||||
|
||||
for (int y = 17; y <= height; y += 17) {
|
||||
g.drawLine(0, y, width, y);
|
||||
}
|
||||
|
||||
map.setFont(image);
|
||||
}
|
||||
|
||||
return new Map(map);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor;
|
||||
|
||||
public class RawCase {
|
||||
private int x;
|
||||
private int y;
|
||||
private RawSprite couche1;
|
||||
private RawSprite couche2;
|
||||
private RawSprite couche3;
|
||||
private Collision collision;
|
||||
|
||||
public static RawCase create(int posX, int posY, RawSprite couche1, RawSprite couche2, RawSprite couche3, Collision collision) {
|
||||
RawCase c = new RawCase();
|
||||
c.x = posX;
|
||||
c.y = posY;
|
||||
c.couche1 = couche1;
|
||||
c.couche2 = couche2;
|
||||
c.couche3 = couche3;
|
||||
c.collision = collision;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static RawCase create(Case c) {
|
||||
RawCase raw = new RawCase();
|
||||
raw.x = c.getPosX();
|
||||
raw.y = c.getPosY();
|
||||
raw.couche1 = RawSprite.create(c.getCoucheOne());
|
||||
raw.couche2 = RawSprite.create(c.getCoucheTwo());
|
||||
raw.couche3 = RawSprite.create(c.getCoucheThree());
|
||||
raw.collision = c.getCollision();
|
||||
return raw;
|
||||
}
|
||||
|
||||
public int getPosX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getPosY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public RawSprite getCoucheOne() {
|
||||
return couche1;
|
||||
}
|
||||
|
||||
public RawSprite getCoucheTwo() {
|
||||
return couche2;
|
||||
}
|
||||
|
||||
public RawSprite getCoucheThree() {
|
||||
return couche3;
|
||||
}
|
||||
|
||||
public Collision getCollision() {
|
||||
return collision;
|
||||
}
|
||||
|
||||
public void setCollision(Collision collision) {
|
||||
this.collision = collision;
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.editor.Map;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RawMap {
|
||||
private List<RawCase> cases;
|
||||
private java.util.Map<Integer, RawCase> cases_map;
|
||||
private int width;
|
||||
private int height;
|
||||
private transient BufferedImage font;
|
||||
|
||||
public static RawMap create(List<RawCase> cases, int width, int height) {
|
||||
RawMap rm = new RawMap();
|
||||
rm.cases = cases;
|
||||
rm.width = width;
|
||||
rm.height = height;
|
||||
return rm;
|
||||
}
|
||||
|
||||
public static RawMap create(Map map) {
|
||||
RawMap raw = new RawMap();
|
||||
raw.width = map.getWidth();
|
||||
raw.height = map.getHeight();
|
||||
raw.cases = new ArrayList<>();
|
||||
for (Case c : map.getAllCases()) {
|
||||
RawCase rc = RawCase.create(c);
|
||||
raw.cases.add(rc);
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
public List<RawCase> getCases() {
|
||||
return cases;
|
||||
}
|
||||
|
||||
public RawCase getCase(int x, int y) {
|
||||
if (cases_map == null) {
|
||||
cases_map = new HashMap<>();
|
||||
for (RawCase c : getCases())
|
||||
cases_map.put(c.getPosY() * width + c.getPosX(), c);
|
||||
}
|
||||
|
||||
return cases_map.get(y * getWidth() + x);
|
||||
}
|
||||
|
||||
public Collection<RawCase> getNeighbours(RawCase c) {
|
||||
List<RawCase> list = new ArrayList<>();
|
||||
list.add(getCase(c.getPosX() - 1, c.getPosY()));
|
||||
list.add(getCase(c.getPosX(), c.getPosY() - 1));
|
||||
list.add(getCase(c.getPosX() + 1, c.getPosY()));
|
||||
list.add(getCase(c.getPosX(), c.getPosY() + 1));
|
||||
return list.stream().filter(_c -> _c != null && _c.getCollision() == Collision.ANY).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public BufferedImage getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setFont(BufferedImage font) {
|
||||
this.font = font;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
|
||||
public class RawSprite {
|
||||
public static transient final RawSprite BLANK = new RawSprite();
|
||||
private String category = "blank";
|
||||
private int index = 0;
|
||||
|
||||
public static RawSprite create(Sprite spr) {
|
||||
RawSprite raw = new RawSprite();
|
||||
raw.category = spr.getCategory().getName();
|
||||
raw.index = spr.getIndex();
|
||||
return raw;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
/**
|
||||
* @author ÿnérant
|
||||
*/
|
||||
package fr.ynerant.leveleditor.api.editor;
|
|
@ -1,33 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor.sprites;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Category {
|
||||
private List<Sprite> sprites;
|
||||
private String name;
|
||||
|
||||
private Category() {
|
||||
}
|
||||
|
||||
public static Category create(String name, List<Sprite> sprites) {
|
||||
Category c = new Category();
|
||||
|
||||
c.name = name;
|
||||
c.sprites = sprites;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Sprite> getSprites() {
|
||||
return sprites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor.sprites;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Sprite {
|
||||
public static final Sprite BLANK = new Sprite(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), Category.create("blank", new ArrayList<>()), 0);
|
||||
|
||||
static {
|
||||
Graphics2D g = BLANK.getImage().createGraphics();
|
||||
g.setComposite(AlphaComposite.Clear);
|
||||
g.setColor(new Color(0, true));
|
||||
g.fillRect(0, 0, 16, 16);
|
||||
}
|
||||
|
||||
private final Category cat;
|
||||
private final BufferedImage img;
|
||||
private final int index;
|
||||
|
||||
public Sprite(BufferedImage img, Category cat, int index) {
|
||||
this.img = img;
|
||||
this.cat = cat;
|
||||
this.index = index;
|
||||
|
||||
if (!this.cat.getSprites().contains(this))
|
||||
this.cat.getSprites().add(this);
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
return this.img;
|
||||
}
|
||||
|
||||
public Category getCategory() {
|
||||
return cat;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return cat.hashCode() ^ getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Sprite))
|
||||
return false;
|
||||
|
||||
Sprite other = (Sprite) o;
|
||||
|
||||
return hashCode() == other.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{Sprite img=" + img + " cat=" + cat.getName() + "}";
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
package fr.ynerant.leveleditor.api.editor.sprites;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import fr.ynerant.leveleditor.client.main.Main;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class SpriteRegister {
|
||||
private static Map<String, List<List<Double>>> nameToCoords;
|
||||
private static final Map<String, Category> sprites = new HashMap<>();
|
||||
|
||||
public static void unpack() throws IOException {
|
||||
if (Main.isInDevelopmentMode()) {
|
||||
try {
|
||||
File dir = new File(SpriteRegister.class.getResource("/assets").toURI()).getParentFile();
|
||||
unpackDir(dir);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else {
|
||||
@SuppressWarnings("deprecation")
|
||||
String path = URLDecoder.decode(SpriteRegister.class.getProtectionDomain().getCodeSource().getLocation().getPath());
|
||||
File jarFile = new File(path);
|
||||
|
||||
if (jarFile.isFile()) {
|
||||
JarFile jar = new JarFile(jarFile);
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry je = entries.nextElement();
|
||||
String name = je.getName();
|
||||
if (name.startsWith("assets/")) {
|
||||
File f = new File(name);
|
||||
if (name.endsWith("/")) {
|
||||
if (!f.mkdirs() && !f.isDirectory())
|
||||
throw new IOException("Unable to make dir: " + f);
|
||||
}
|
||||
else if (!f.isFile())
|
||||
Files.copy(jar.getInputStream(je), Paths.get(f.toURI()));
|
||||
}
|
||||
}
|
||||
jar.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void unpackDir(File dir) throws IOException {
|
||||
for (File f : Objects.requireNonNull(dir.listFiles())) {
|
||||
if (f.isDirectory()) {
|
||||
unpackDir(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
String path = f.getAbsolutePath().substring(f.getAbsolutePath().indexOf(File.separatorChar + "assets") + 1);
|
||||
File local = new File(path);
|
||||
assert local.getParentFile().mkdirs();
|
||||
assert !local.exists() || local.delete();
|
||||
Files.copy(Paths.get(f.toURI()), Paths.get(local.toURI()));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void refreshAllSprites() {
|
||||
if (nameToCoords != null && !nameToCoords.isEmpty() && !sprites.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File assetsDir = new File("assets");
|
||||
List<String> assets = new ArrayList<>();
|
||||
|
||||
for (File dir : Objects.requireNonNull(assetsDir.listFiles())) {
|
||||
assets.add(dir.getName());
|
||||
}
|
||||
|
||||
for (String asset : assets) {
|
||||
try {
|
||||
File f = new File(assetsDir.getAbsolutePath() + "/" + asset + "/textures/sprites");
|
||||
assert f.mkdirs();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(f, "sprites.json"))));
|
||||
nameToCoords = new Gson().fromJson(br, Map.class);
|
||||
br.close();
|
||||
|
||||
for (String key : nameToCoords.keySet()) {
|
||||
try {
|
||||
BufferedInputStream is = new BufferedInputStream(new FileInputStream(new File(f, key + ".png")));
|
||||
BufferedImage img = ImageIO.read(is);
|
||||
Category cat = Category.create(key, new ArrayList<>());
|
||||
|
||||
for (List<Double> list : nameToCoords.get(key)) {
|
||||
int x = list.get(0).intValue();
|
||||
int y = list.get(1).intValue();
|
||||
BufferedImage child = img.getSubimage(x, y, 16, 16);
|
||||
new Sprite(child, cat, nameToCoords.get(key).indexOf(list));
|
||||
}
|
||||
|
||||
sprites.put(key, cat);
|
||||
} catch (Throwable t) {
|
||||
System.err.println("Erreur lors de la lecture du sprite '" + key + "'");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Category getCategory(String name) {
|
||||
return sprites.get(name);
|
||||
}
|
||||
|
||||
public static List<Category> getAllCategories() {
|
||||
return new ArrayList<>(sprites.values());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
package fr.ynerant.leveleditor.client.main;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.EditorAPI;
|
||||
import fr.ynerant.leveleditor.api.editor.RawMap;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
|
||||
import fr.ynerant.leveleditor.frame.MainFrame;
|
||||
import fr.ynerant.leveleditor.game.GameFrame;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class principale qui lance le jeu
|
||||
*
|
||||
* @author ÿnérant
|
||||
* @see #main(String...)
|
||||
*/
|
||||
public class Main {
|
||||
/**
|
||||
* Variable disant si le jeu est lancé en développement ou non.
|
||||
*
|
||||
* @see #isInDevelopmentMode()
|
||||
* @see #main(String...)
|
||||
* @since 0.1-aplha
|
||||
*/
|
||||
private static boolean DEV;
|
||||
|
||||
/**
|
||||
* @param args arguments du jeu. Possibilités :<br> <strong>--edit</strong> lancera un éditeur<br> <strong>--help</strong> lance l'aide affichant toutes les options possibles
|
||||
* @see #launchEditMode()
|
||||
* @since 0.1-alpha
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
System.setProperty("sun.java2d.noddraw", "true");
|
||||
|
||||
Locale.setDefault(Locale.FRANCE);
|
||||
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace();
|
||||
System.err.print("Caused by ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
new File(Main.class.getResource("/assets").toURI());
|
||||
DEV = true;
|
||||
} catch (Throwable t) {
|
||||
DEV = false;
|
||||
}
|
||||
|
||||
checkJava();
|
||||
|
||||
OptionParser parser = new OptionParser();
|
||||
|
||||
OptionSpec<String> edit = parser.accepts("edit", "Lancer l'\u00e9diteur de monde").withOptionalArg();
|
||||
OptionSpec<String> help = parser.accepts("help", "Affiche ce menu d'aide").withOptionalArg().forHelp();
|
||||
|
||||
OptionSet set = parser.parse(args);
|
||||
|
||||
if (set.has(help)) {
|
||||
try {
|
||||
parser.printHelpOn(System.out);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
SpriteRegister.unpack();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
SpriteRegister.refreshAllSprites();
|
||||
|
||||
if (set.has(edit)) {
|
||||
launchEditMode();
|
||||
return;
|
||||
}
|
||||
|
||||
launchFrame();
|
||||
}
|
||||
|
||||
private static void checkJava() {
|
||||
if (GraphicsEnvironment.isHeadless()) {
|
||||
HeadlessException ex = new HeadlessException("Impossible de lancer un jeu sans \u00e9cran !");
|
||||
System.err.println("Cette application est un jeu, sans écran, elle aura du mal \u00e0 tourner ...");
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
Map.class.getDeclaredMethod("getOrDefault", Object.class, Object.class);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "<html>Cette application requiert <strong>Java 8</strong>.<br />La page de t\u00e9l\u00e9chargement va maintenant s'ouvrir.</html>");
|
||||
JOptionPane.showMessageDialog(null, "<html>Si vous êtes certain que Java 8 est installé sur votre machine, assurez-vous qu'il n'y a pas de versions obsolètes de Java,<br />ou si vous êtes plus expérimentés si le path vers Java est bien défini vers la bonne version.</html>");
|
||||
try {
|
||||
if (Desktop.isDesktopSupported())
|
||||
Desktop.getDesktop().browse(new URL("http://java.com/download").toURI());
|
||||
else
|
||||
JOptionPane.showMessageDialog(null, "<html>Votre machine ne supporte pas la classe Desktop, impossible d'ouvrir la page.<br />Rendez-vous y manuellement sur <a href=\"http://java.com/download\">http://java.com/download</a> pour installer Java.</html>");
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lance la fenêtre principale
|
||||
*
|
||||
* @see #main(String...)
|
||||
* @see #launchEditMode()
|
||||
*/
|
||||
private static void launchFrame() {
|
||||
MainFrame.getInstance().setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de lancer l'éditeur de carte
|
||||
*
|
||||
* @see #main(String...)
|
||||
* @see #launchFrame()
|
||||
* @since 0.1-aplha
|
||||
*/
|
||||
public static boolean launchEditMode() {
|
||||
System.out.println("Lancement de l'\u00e9diteur de monde ...");
|
||||
int baseWidth;
|
||||
int baseHeight;
|
||||
int width;
|
||||
int height;
|
||||
while (true) {
|
||||
try {
|
||||
String baseWidthStr = JOptionPane.showInputDialog(null, "Veuillez entrez le nombre de cases longueur de votre carte (0 pour annuler) :");
|
||||
if (baseWidthStr == null)
|
||||
return false;
|
||||
baseWidth = Integer.parseInt(baseWidthStr) * 16;
|
||||
if (baseWidth < 0)
|
||||
throw new NumberFormatException();
|
||||
if (baseWidth == 0)
|
||||
return false;
|
||||
break;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
String baseHeightStr = JOptionPane.showInputDialog("Veuillez entrez le nombre de cases hauteur de votre carte (0 pour annuler) :");
|
||||
if (baseHeightStr == null)
|
||||
return false;
|
||||
baseHeight = Integer.parseInt(baseHeightStr) * 16;
|
||||
if (baseHeight < 0)
|
||||
throw new NumberFormatException();
|
||||
if (baseHeight == 0)
|
||||
return false;
|
||||
break;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
width = baseWidth + (baseWidth / 16) + 1;
|
||||
height = baseHeight + (baseHeight / 16) + 1;
|
||||
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
g.setColor(Color.white);
|
||||
g.fillRect(0, 0, width, height);
|
||||
g.setColor(Color.black);
|
||||
g.drawLine(0, 0, width, 0);
|
||||
g.drawLine(0, 0, 0, height);
|
||||
for (int x = 17; x <= width; x += 17) {
|
||||
g.drawLine(x, 0, x, height);
|
||||
}
|
||||
|
||||
for (int y = 17; y <= height; y += 17) {
|
||||
g.drawLine(0, y, width, y);
|
||||
}
|
||||
|
||||
RawMap rm = EditorAPI.toRawMap(baseWidth, baseHeight);
|
||||
rm.setFont(image);
|
||||
|
||||
EditorAPI.open(rm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean launchGameMode() {
|
||||
System.out.println("Lancement du jeu ...");
|
||||
JFileChooser jfc = EditorAPI.createJFC();
|
||||
jfc.showOpenDialog(MainFrame.getInstance());
|
||||
if (jfc.getSelectedFile() == null)
|
||||
return false;
|
||||
|
||||
RawMap map = EditorAPI.getRawMap(jfc.getSelectedFile());
|
||||
|
||||
new GameFrame(map);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesseur disant si le jeu est lancé en développement ou non.
|
||||
*
|
||||
* @see #DEV
|
||||
* @since 0.1-alpha
|
||||
*/
|
||||
public static boolean isInDevelopmentMode() {
|
||||
return DEV;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
/**
|
||||
* Ce package comprend uniquement la classe Main, qui lance l'application.
|
||||
*
|
||||
* @author ÿnérant
|
||||
*/
|
||||
package fr.ynerant.leveleditor.client.main;
|
|
@ -1,83 +0,0 @@
|
|||
package fr.ynerant.leveleditor.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Case;
|
||||
import fr.ynerant.leveleditor.api.editor.Collision;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class CollidPanel extends JPanel {
|
||||
private static final long serialVersionUID = -138754019431984881L;
|
||||
|
||||
private final EditorFrame frame;
|
||||
|
||||
public CollidPanel(EditorFrame frame) {
|
||||
super();
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
public Map getMap() {
|
||||
return frame.getMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
BufferedImage img = getMap().getFont();
|
||||
int x = getWidth() / 2 - img.getWidth();
|
||||
int y = getHeight() / 2 - img.getHeight();
|
||||
int width = img.getWidth() * 2;
|
||||
int height = img.getHeight() * 2;
|
||||
g.drawImage(getMap().getFont(), x, y, width, height, null);
|
||||
|
||||
for (Case c : getMap().getAllCases()) {
|
||||
if (isEmpty(c.getCoucheOne().getImage()))
|
||||
continue;
|
||||
|
||||
g.drawImage(c.getCoucheOne().getImage(), x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
|
||||
if (isEmpty(c.getCoucheTwo().getImage()))
|
||||
continue;
|
||||
|
||||
g.drawImage(c.getCoucheTwo().getImage(), x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
|
||||
if (isEmpty(c.getCoucheThree().getImage()))
|
||||
continue;
|
||||
|
||||
g.drawImage(c.getCoucheThree().getImage(), x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}
|
||||
|
||||
for (Case c : getMap().getAllCases()) {
|
||||
if (c.getCollision() != Collision.ANY) {
|
||||
BufferedImage alpha = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
if (c.getCollision() == Collision.FULL) {
|
||||
Graphics2D grap = alpha.createGraphics();
|
||||
grap.setColor(new Color(0, 0, 0, 100));
|
||||
grap.fillRect(0, 0, 16, 16);
|
||||
grap.dispose();
|
||||
} else if (c.getCollision() == Collision.PARTIAL) {
|
||||
Graphics2D grap = alpha.createGraphics();
|
||||
grap.setColor(new Color(255, 0, 255, 70));
|
||||
grap.fillRect(0, 0, 16, 16);
|
||||
grap.dispose();
|
||||
}
|
||||
|
||||
g.drawImage(alpha, x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEmpty(BufferedImage image) {
|
||||
int allrgba = 0;
|
||||
|
||||
for (int x = 0; x < image.getWidth(); ++x) {
|
||||
for (int y = 0; y < image.getHeight(); ++y) {
|
||||
allrgba += image.getRGB(x, y) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return allrgba == 0;
|
||||
}
|
||||
}
|
|
@ -1,322 +0,0 @@
|
|||
package fr.ynerant.leveleditor.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.EditorAPI;
|
||||
import fr.ynerant.leveleditor.api.editor.RawMap;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Category;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
|
||||
import fr.ynerant.leveleditor.frame.listeners.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
|
||||
public class EditorFrame extends JFrame implements ChangeListener, ActionListener, WindowListener {
|
||||
private static final long serialVersionUID = -2705122356101556462L;
|
||||
|
||||
private final Map map;
|
||||
|
||||
private final JMenuItem save = new JMenuItem("Sauvegarder");
|
||||
private final JMenuItem saveAs = new JMenuItem("Sauvegarder sous ...");
|
||||
private final JMenuItem exit = new JMenuItem("Quitter");
|
||||
private final JRadioButtonMenuItem pen = new JRadioButtonMenuItem("Pinceau");
|
||||
private final JRadioButtonMenuItem pot = new JRadioButtonMenuItem("Pot de peinture");
|
||||
private final JTabbedPane tabs = new JTabbedPane();
|
||||
private final CollidPanel tabColl;
|
||||
private final MapPanel mapPanel;
|
||||
private final JTabbedPane resources = new JTabbedPane();
|
||||
private final JPanel couche1 = new JPanel();
|
||||
private final JPanel couche2 = new JPanel();
|
||||
private final JPanel couche3 = new JPanel();
|
||||
final ButtonGroup group = new ButtonGroup();
|
||||
private SpriteComp selectedSprite;
|
||||
|
||||
public EditorFrame(Map map) {
|
||||
super("Level Editor");
|
||||
this.map = map;
|
||||
this.setSize(600, 600);
|
||||
this.setPreferredSize(getSize());
|
||||
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
this.setLocationRelativeTo(null);
|
||||
this.addWindowListener(this);
|
||||
JPanel content = new JPanel();
|
||||
content.setLayout(new BorderLayout());
|
||||
this.setContentPane(content);
|
||||
this.setVisible(true);
|
||||
this.setVisible(false);
|
||||
|
||||
JMenu fichier = new JMenu("Fichier");
|
||||
fichier.setMnemonic(KeyEvent.VK_F + KeyEvent.ALT_DOWN_MASK);
|
||||
|
||||
JMenuItem nouveau = new JMenuItem("Nouveau");
|
||||
nouveau.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_DOWN_MASK, true));
|
||||
nouveau.addActionListener(new CreateMapListener());
|
||||
fichier.add(nouveau);
|
||||
|
||||
JMenuItem open = new JMenuItem("Ouvrir");
|
||||
open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK, true));
|
||||
open.addActionListener(new OpenMapListener());
|
||||
fichier.add(open);
|
||||
|
||||
fichier.addSeparator();
|
||||
|
||||
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK, true));
|
||||
save.addActionListener(this);
|
||||
fichier.add(save);
|
||||
|
||||
saveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK, true));
|
||||
saveAs.addActionListener(this);
|
||||
fichier.add(saveAs);
|
||||
|
||||
fichier.addSeparator();
|
||||
|
||||
exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK, true));
|
||||
exit.addActionListener(this);
|
||||
fichier.add(exit);
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
menuBar.add(fichier);
|
||||
|
||||
pen.setSelected(true);
|
||||
pen.addActionListener(this);
|
||||
pot.addActionListener(this);
|
||||
group.add(pen);
|
||||
group.add(pot);
|
||||
JMenu selectionMode = new JMenu("Mode de s\u00e9lection");
|
||||
selectionMode.add(pen);
|
||||
selectionMode.add(pot);
|
||||
|
||||
JMenu tools = new JMenu("Outils");
|
||||
tools.setMnemonic(KeyEvent.VK_O + KeyEvent.ALT_DOWN_MASK);
|
||||
|
||||
tools.add(selectionMode);
|
||||
|
||||
menuBar.add(tools);
|
||||
|
||||
this.setJMenuBar(menuBar);
|
||||
|
||||
mapPanel = new MapPanel(this);
|
||||
mapPanel.addMouseListener(new MapMouseListener(mapPanel, this));
|
||||
mapPanel.addMouseMotionListener(new MapMouseListener(mapPanel, this));
|
||||
|
||||
tabColl = new CollidPanel(this);
|
||||
tabColl.addMouseListener(new CollidMapMouseListener(tabColl, this));
|
||||
tabColl.addMouseMotionListener(new CollidMapMouseListener(tabColl, this));
|
||||
|
||||
JScrollPane scrollMap = new JScrollPane(mapPanel);
|
||||
scrollMap.getHorizontalScrollBar().setUnitIncrement(34);
|
||||
scrollMap.getVerticalScrollBar().setUnitIncrement(34);
|
||||
JScrollPane scrollCollidMap = new JScrollPane(tabColl);
|
||||
scrollCollidMap.getHorizontalScrollBar().setUnitIncrement(34);
|
||||
scrollCollidMap.getVerticalScrollBar().setUnitIncrement(34);
|
||||
|
||||
tabs.addTab("Carte", scrollMap);
|
||||
JPanel tabEvents = new JPanel();
|
||||
tabs.addTab("\u00c9vennments", new JScrollPane(tabEvents));
|
||||
tabs.addTab("Collisions", scrollCollidMap);
|
||||
tabs.addChangeListener(this);
|
||||
|
||||
content.add(tabs, BorderLayout.CENTER);
|
||||
|
||||
couche1.setLayout(new WrapLayout(WrapLayout.LEFT));
|
||||
couche2.setLayout(new WrapLayout(WrapLayout.LEFT));
|
||||
couche3.setLayout(new WrapLayout(WrapLayout.LEFT));
|
||||
|
||||
JScrollPane scroll1 = new JScrollPane(couche1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
JScrollPane scroll2 = new JScrollPane(couche2, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
JScrollPane scroll3 = new JScrollPane(couche3, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
scroll1.getHorizontalScrollBar().setMaximum(0);
|
||||
scroll2.getHorizontalScrollBar().setMaximum(0);
|
||||
scroll3.getHorizontalScrollBar().setMaximum(0);
|
||||
|
||||
resources.addTab("", new ImageIcon(new File("assets/leveleditor/textures/layer 1.png").getAbsolutePath()), scroll1);
|
||||
resources.addTab("", new ImageIcon(new File("assets/leveleditor/textures/layer 2.png").getAbsolutePath()), scroll2);
|
||||
resources.addTab("", new ImageIcon(new File("assets/leveleditor/textures/layer 3.png").getAbsolutePath()), scroll3);
|
||||
resources.addChangeListener(this);
|
||||
resources.setBackgroundAt(0, Color.white);
|
||||
resources.setBackgroundAt(1, Color.white);
|
||||
resources.setBackgroundAt(2, Color.white);
|
||||
|
||||
content.add(resources, BorderLayout.EAST);
|
||||
|
||||
resize();
|
||||
|
||||
drawResources();
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void drawResources() {
|
||||
couche1.removeAll();
|
||||
couche2.removeAll();
|
||||
couche3.removeAll();
|
||||
|
||||
if (couche1.getComponents().length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (couche1.getWidth() == 0 || couche2.getWidth() == 0 || couche3.getWidth() == 0) {
|
||||
couche1.repaint();
|
||||
couche2.repaint();
|
||||
couche3.repaint();
|
||||
}
|
||||
|
||||
for (Category cat : SpriteRegister.getAllCategories()) {
|
||||
for (Sprite spr : cat.getSprites()) {
|
||||
SpriteComp sprc1 = new SpriteComp(spr, 0);
|
||||
SpriteComp sprc2 = new SpriteComp(spr, 1);
|
||||
SpriteComp sprc3 = new SpriteComp(spr, 2);
|
||||
sprc1.addMouseListener(new SpriteMouseListener(sprc1, this));
|
||||
sprc2.addMouseListener(new SpriteMouseListener(sprc2, this));
|
||||
sprc3.addMouseListener(new SpriteMouseListener(sprc3, this));
|
||||
couche1.add(sprc1);
|
||||
couche2.add(sprc2);
|
||||
couche3.add(sprc3);
|
||||
}
|
||||
}
|
||||
|
||||
couche1.revalidate();
|
||||
couche2.revalidate();
|
||||
couche3.revalidate();
|
||||
couche1.repaint();
|
||||
couche2.repaint();
|
||||
couche3.repaint();
|
||||
}
|
||||
|
||||
public void resize() {
|
||||
|
||||
int cursorPos = ((JScrollPane) resources.getSelectedComponent()).getVerticalScrollBar().getValue();
|
||||
tabs.setPreferredSize(new Dimension(getWidth(), getHeight() / 5));
|
||||
tabs.setLocation(0, 0);
|
||||
BufferedImage img = getMap().getFont();
|
||||
int width = img.getWidth() * 2;
|
||||
int height = img.getHeight() * 2;
|
||||
mapPanel.setPreferredSize(new Dimension(width, height));
|
||||
mapPanel.setLocation(0, getHeight() / 5);
|
||||
tabColl.setPreferredSize(new Dimension(width, height));
|
||||
tabColl.setLocation(0, getHeight() / 5);
|
||||
resources.setPreferredSize(new Dimension(getWidth() / 4 - 15, getHeight() / 5 * 4 - 40));
|
||||
resources.setLocation(getWidth() / 4 * 3, getHeight() / 5);
|
||||
|
||||
JScrollPane scroll1 = (JScrollPane) resources.getComponent(0);
|
||||
JScrollPane scroll2 = (JScrollPane) resources.getComponent(1);
|
||||
JScrollPane scroll3 = (JScrollPane) resources.getComponent(2);
|
||||
|
||||
scroll1.getHorizontalScrollBar().setMaximum(0);
|
||||
scroll2.getHorizontalScrollBar().setMaximum(0);
|
||||
scroll3.getHorizontalScrollBar().setMaximum(0);
|
||||
|
||||
drawResources();
|
||||
|
||||
((JScrollPane) resources.getSelectedComponent()).getVerticalScrollBar().setValue(cursorPos);
|
||||
}
|
||||
|
||||
public Map getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public SpriteComp getSelectedSprite() {
|
||||
return selectedSprite;
|
||||
}
|
||||
|
||||
public void setSelectedSprite(SpriteComp sprite) {
|
||||
this.selectedSprite = sprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent event) {
|
||||
if (event.getSource() == resources) {
|
||||
if (getSelectedLayerIndex() == 0) {
|
||||
resources.setBackgroundAt(0, Color.white);
|
||||
resources.setBackgroundAt(1, Color.white);
|
||||
resources.setBackgroundAt(2, Color.white);
|
||||
} else if (getSelectedLayerIndex() == 1) {
|
||||
resources.setBackgroundAt(0, Color.black);
|
||||
resources.setBackgroundAt(1, Color.white);
|
||||
resources.setBackgroundAt(2, Color.white);
|
||||
} else if (getSelectedLayerIndex() == 2) {
|
||||
resources.setBackgroundAt(0, Color.black);
|
||||
resources.setBackgroundAt(1, Color.black);
|
||||
resources.setBackgroundAt(2, Color.white);
|
||||
}
|
||||
|
||||
repaint();
|
||||
} else if (event.getSource() == tabs) {
|
||||
resources.setEnabled(tabs.getSelectedIndex() == 0);
|
||||
couche1.setEnabled(resources.isEnabled());
|
||||
couche2.setEnabled(resources.isEnabled());
|
||||
couche3.setEnabled(resources.isEnabled());
|
||||
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public int getSelectedLayerIndex() {
|
||||
return resources.getSelectedIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
if (event.getSource() == save) {
|
||||
EditorAPI.save(RawMap.create(map));
|
||||
} else if (event.getSource() == saveAs) {
|
||||
EditorAPI.saveAs(RawMap.create(map));
|
||||
} else if (event.getSource() == exit) {
|
||||
int result = JOptionPane.showConfirmDialog(null, "Voulez-vous sauvegarder votre carte avant de quitter ? Toute modification sera perdue", "Confirmation", JOptionPane.YES_NO_CANCEL_OPTION);
|
||||
|
||||
if (result == 0)
|
||||
save.doClick();
|
||||
|
||||
if (result != 2)
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public int getSelectedPaintingMode() {
|
||||
return pen.isSelected() ? 0 : pot.isSelected() ? 1 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowActivated(WindowEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosed(WindowEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent event) {
|
||||
int result = JOptionPane.showConfirmDialog(null, "Voulez-vous sauvegarder avant de quitter ?", "Confirmation", JOptionPane.YES_NO_CANCEL_OPTION);
|
||||
|
||||
if (result == 0) {
|
||||
EditorAPI.save(RawMap.create(map));
|
||||
}
|
||||
|
||||
if (result != 2) {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowOpened(WindowEvent event) {
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package fr.ynerant.leveleditor.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Case;
|
||||
import fr.ynerant.leveleditor.api.editor.RawCase;
|
||||
import fr.ynerant.leveleditor.api.editor.RawMap;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Map {
|
||||
@Deprecated
|
||||
private static List<Case> cases;
|
||||
private final EditorFrame frame;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final java.util.Map<Integer, java.util.Map<Integer, Case>> casesMap = new HashMap<>();
|
||||
private final transient BufferedImage font;
|
||||
|
||||
public Map(RawMap raw) {
|
||||
cases = new ArrayList<>();
|
||||
this.width = raw.getWidth();
|
||||
this.height = raw.getHeight();
|
||||
this.font = raw.getFont();
|
||||
|
||||
for (RawCase rc : raw.getCases()) {
|
||||
cases.add(Case.create(rc.getPosX(), rc.getPosY(), SpriteRegister.getCategory(rc.getCoucheOne().getCategory()).getSprites().get(rc.getCoucheOne().getIndex()), SpriteRegister.getCategory(rc.getCoucheTwo().getCategory()).getSprites().get(rc.getCoucheTwo().getIndex()), SpriteRegister.getCategory(rc.getCoucheThree().getCategory()).getSprites().get(rc.getCoucheThree().getIndex()), rc.getCollision()));
|
||||
}
|
||||
|
||||
reorganizeMap();
|
||||
|
||||
frame = new EditorFrame(this);
|
||||
|
||||
getFrame().setVisible(true);
|
||||
}
|
||||
|
||||
public EditorFrame getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Case getCase(int x, int y) {
|
||||
return casesMap.getOrDefault(x, new HashMap<>()).get(y);
|
||||
}
|
||||
|
||||
public void setCase(int x, int y, Case c) {
|
||||
casesMap.get(x).put(y, c);
|
||||
}
|
||||
|
||||
public BufferedImage getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
private void reorganizeMap() {
|
||||
for (int i = 0; i < width; ++i) {
|
||||
casesMap.put(i, new HashMap<>());
|
||||
}
|
||||
|
||||
for (Case c : cases) {
|
||||
setCase(c.getPosX(), c.getPosY(), c);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Case> getAllCases() {
|
||||
List<Case> list = new ArrayList<>();
|
||||
|
||||
for (java.util.Map<Integer, Case> l : casesMap.values()) {
|
||||
list.addAll(l.values());
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package fr.ynerant.leveleditor.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Case;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class MapPanel extends JPanel {
|
||||
private static final long serialVersionUID = 2629019576253690557L;
|
||||
|
||||
private final EditorFrame frame;
|
||||
|
||||
public MapPanel(EditorFrame frame) {
|
||||
super();
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
public Map getMap() {
|
||||
return frame.getMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
BufferedImage img = getMap().getFont();
|
||||
int x = getWidth() / 2 - img.getWidth();
|
||||
int y = getHeight() / 2 - img.getHeight();
|
||||
int width = img.getWidth() * 2;
|
||||
int height = img.getHeight() * 2;
|
||||
g.drawImage(getMap().getFont(), x, y, width, height, null);
|
||||
|
||||
for (Case c : getMap().getAllCases()) {
|
||||
// BufferedImage image;
|
||||
|
||||
if (!isEmpty(c.getCoucheOne().getImage())) {
|
||||
g.drawImage(c.getCoucheOne().getImage(), x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}
|
||||
/* if (frame.getSelectedLayerIndex() != 0)
|
||||
{
|
||||
image = recalculateAplha(c.getCoucheOne().getImage(), 0);
|
||||
g.drawImage(image, x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}*/
|
||||
|
||||
if (!isEmpty(c.getCoucheTwo().getImage()) && frame.getSelectedLayerIndex() >= 1) {
|
||||
g.drawImage(c.getCoucheTwo().getImage(), x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}
|
||||
/* if (frame.getSelectedLayerIndex() != 1)
|
||||
{
|
||||
image = recalculateAplha(c.getCoucheTwo().getImage(), 1);
|
||||
g.drawImage(image, x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}*/
|
||||
|
||||
if (!isEmpty(c.getCoucheThree().getImage()) && frame.getSelectedLayerIndex() == 2) {
|
||||
g.drawImage(c.getCoucheThree().getImage(), x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}
|
||||
/* if (frame.getSelectedLayerIndex() != 2)
|
||||
{
|
||||
image = recalculateAplha(c.getCoucheThree().getImage(), 2);
|
||||
g.drawImage(image, x + c.getPosX() * 34 + 2, y + c.getPosY() * 34 + 2, 32, 32, null);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean isEmpty(BufferedImage image) {
|
||||
int allrgba = 0;
|
||||
|
||||
for (int x = 0; x < image.getWidth(); ++x) {
|
||||
for (int y = 0; y < image.getHeight(); ++y) {
|
||||
allrgba += image.getRGB(x, y) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return allrgba == 0;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package fr.ynerant.leveleditor.editor;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class SpriteComp extends JComponent {
|
||||
private static final long serialVersionUID = -6512257366877053285L;
|
||||
|
||||
private final Sprite sprite;
|
||||
private final int couche;
|
||||
private boolean selected;
|
||||
|
||||
public SpriteComp(Sprite sprite, int couche) {
|
||||
super();
|
||||
this.sprite = sprite;
|
||||
this.couche = couche;
|
||||
this.setMinimumSize(new Dimension(32, 32));
|
||||
this.setMaximumSize(new Dimension(32, 32));
|
||||
this.setPreferredSize(new Dimension(32, 32));
|
||||
this.setSize(new Dimension(32, 32));
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
public Sprite getSprite() {
|
||||
return sprite;
|
||||
}
|
||||
|
||||
public int getCouche() {
|
||||
return couche;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
|
||||
g.setColor(Color.white);
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
g.drawImage(sprite.getImage(), 0, 0, 32, 32, Color.white, null);
|
||||
|
||||
if (isSelected()) {
|
||||
g.setColor(Color.black);
|
||||
g.drawLine(0, 0, getWidth() - 1, 0);
|
||||
g.drawLine(0, 0, 0, getHeight() - 1);
|
||||
g.drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1);
|
||||
g.drawLine(getWidth() - 1, 0, getWidth() - 1, getHeight() - 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package fr.ynerant.leveleditor.editor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class WrapLayout extends FlowLayout {
|
||||
private static final long serialVersionUID = 8777237960365591646L;
|
||||
|
||||
public WrapLayout(int align) {
|
||||
super(align);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(Container target) {
|
||||
return layoutSize(target, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension minimumLayoutSize(Container target) {
|
||||
Dimension minimum = layoutSize(target, false);
|
||||
minimum.width -= (getHgap() + 1);
|
||||
return minimum;
|
||||
}
|
||||
|
||||
private Dimension layoutSize(Container target, boolean preferred) {
|
||||
synchronized (target.getTreeLock()) {
|
||||
int targetWidth = target.getSize().width;
|
||||
|
||||
if (targetWidth == 0)
|
||||
targetWidth = Integer.MAX_VALUE;
|
||||
|
||||
int hgap = getHgap();
|
||||
int vgap = getVgap();
|
||||
Insets insets = target.getInsets();
|
||||
int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
|
||||
int maxWidth = targetWidth - horizontalInsetsAndGap;
|
||||
|
||||
Dimension dim = new Dimension(0, 0);
|
||||
int rowWidth = 0;
|
||||
int rowHeight = 0;
|
||||
|
||||
int nmembers = target.getComponentCount();
|
||||
|
||||
for (int i = 0; i < nmembers; i++) {
|
||||
Component m = target.getComponent(i);
|
||||
|
||||
if (m.isVisible()) {
|
||||
Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
|
||||
|
||||
if (rowWidth + d.width > maxWidth) {
|
||||
addRow(dim, rowWidth, rowHeight);
|
||||
rowWidth = 0;
|
||||
rowHeight = 0;
|
||||
}
|
||||
|
||||
if (rowWidth != 0) {
|
||||
rowWidth += hgap;
|
||||
}
|
||||
|
||||
rowWidth += d.width;
|
||||
rowHeight = Math.max(rowHeight, d.height);
|
||||
}
|
||||
}
|
||||
|
||||
addRow(dim, rowWidth, rowHeight);
|
||||
|
||||
dim.width += horizontalInsetsAndGap;
|
||||
dim.height += insets.top + insets.bottom + vgap * 2;
|
||||
|
||||
Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
|
||||
if (scrollPane != null) {
|
||||
dim.width -= (hgap + 1);
|
||||
}
|
||||
|
||||
return dim;
|
||||
}
|
||||
}
|
||||
|
||||
private void addRow(Dimension dim, int rowWidth, int rowHeight) {
|
||||
dim.width = Math.max(dim.width, rowWidth);
|
||||
|
||||
if (dim.height > 0) {
|
||||
dim.height += getVgap();
|
||||
}
|
||||
|
||||
dim.height += rowHeight;
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame;
|
||||
|
||||
import fr.ynerant.leveleditor.client.main.Main;
|
||||
import fr.ynerant.leveleditor.frame.listeners.ChangeLAFListener;
|
||||
import fr.ynerant.leveleditor.frame.listeners.CreateMapListener;
|
||||
import fr.ynerant.leveleditor.frame.listeners.OpenMapListener;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* Fenêtre principale du jeu
|
||||
*
|
||||
* @author ÿnérant
|
||||
*/
|
||||
public class MainFrame extends JFrame {
|
||||
/**
|
||||
* ID de série
|
||||
*/
|
||||
private static final long serialVersionUID = -3168760121879418534L;
|
||||
|
||||
/**
|
||||
* Instance unique principale
|
||||
*
|
||||
* @see #MainFrame()
|
||||
* @see #getInstance()
|
||||
*/
|
||||
private static MainFrame INSTANCE;
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
*
|
||||
* @see Main#launchFrame()
|
||||
*/
|
||||
@SuppressWarnings("JavadocReference")
|
||||
private MainFrame() {
|
||||
super();
|
||||
System.out.println("Initialisation de la fen\u00eatre");
|
||||
this.setTitle("Level Editor");
|
||||
this.setPreferredSize(new Dimension(1000, 800));
|
||||
this.setSize(800, 700);
|
||||
this.setLocationRelativeTo(null);
|
||||
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
JMenu fichier = new JMenu("Fichier");
|
||||
fichier.setMnemonic(KeyEvent.VK_F + KeyEvent.ALT_DOWN_MASK);
|
||||
JMenu display = new JMenu("Affichage");
|
||||
display.setMnemonic(KeyEvent.VK_A + KeyEvent.ALT_DOWN_MASK);
|
||||
|
||||
JMenuItem createMap = new JMenuItem("Cr\u00e9er");
|
||||
createMap.addActionListener(new CreateMapListener());
|
||||
JMenu editMaps = new JMenu("Cartes");
|
||||
editMaps.add(createMap);
|
||||
JMenuItem openMap = new JMenuItem("Ouvrir");
|
||||
openMap.addActionListener(new OpenMapListener());
|
||||
editMaps.add(openMap);
|
||||
|
||||
fichier.add(editMaps);
|
||||
|
||||
JMenuItem systemLAF = new JMenuItem("Apparence syst\u00e8me");
|
||||
systemLAF.addActionListener(new ChangeLAFListener(systemLAF, this));
|
||||
JMenu changeLAF = new JMenu("Modfier l'apparence");
|
||||
changeLAF.add(systemLAF);
|
||||
JMenuItem javaLAF = new JMenuItem("Apparence Java");
|
||||
javaLAF.addActionListener(new ChangeLAFListener(javaLAF, this));
|
||||
changeLAF.add(javaLAF);
|
||||
JMenuItem darkLAF = new JMenuItem("Apparence sombre");
|
||||
darkLAF.addActionListener(new ChangeLAFListener(darkLAF, this));
|
||||
changeLAF.add(darkLAF);
|
||||
|
||||
display.add(changeLAF);
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
menuBar.add(fichier);
|
||||
menuBar.add(display);
|
||||
|
||||
this.setJMenuBar(menuBar);
|
||||
|
||||
JButton start = new JButton("Commencer la partie !");
|
||||
start.addActionListener(actionEvent -> {
|
||||
if (Main.launchGameMode())
|
||||
getInstance().dispose();
|
||||
});
|
||||
this.setContentPane(start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cet accesseur renvoie l'accesseur unique de la classe
|
||||
*
|
||||
* @return l'instance unique de la classe
|
||||
* @see #INSTANCE
|
||||
* @see #MainFrame()
|
||||
*/
|
||||
public static MainFrame getInstance() {
|
||||
if (INSTANCE == null)
|
||||
return INSTANCE = new MainFrame();
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners;
|
||||
|
||||
import fr.ynerant.leveleditor.frame.MainFrame;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class ChangeLAFListener implements ActionListener {
|
||||
private final JMenuItem item;
|
||||
private final JFrame frame;
|
||||
|
||||
public ChangeLAFListener(JMenuItem LAF, MainFrame f) {
|
||||
this.item = LAF;
|
||||
this.frame = f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
if (item.getText().toLowerCase().contains("sys")) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace();
|
||||
System.err.print("Caused by ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
SwingUtilities.updateComponentTreeUI(frame);
|
||||
} else if (item.getText().toLowerCase().contains("java")) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace();
|
||||
System.err.print("Caused by ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
SwingUtilities.updateComponentTreeUI(frame);
|
||||
} else if (item.getText().toLowerCase().contains("sombre")) {
|
||||
try {
|
||||
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
|
||||
} catch (Exception e) {
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace();
|
||||
System.err.print("Caused by ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
SwingUtilities.updateComponentTreeUI(frame);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Case;
|
||||
import fr.ynerant.leveleditor.api.editor.Collision;
|
||||
import fr.ynerant.leveleditor.editor.CollidPanel;
|
||||
import fr.ynerant.leveleditor.editor.EditorFrame;
|
||||
import fr.ynerant.leveleditor.editor.Map;
|
||||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public class CollidMapMouseListener extends MouseAdapter {
|
||||
private final EditorFrame frame;
|
||||
private final CollidPanel panel;
|
||||
|
||||
public CollidMapMouseListener(CollidPanel panel, EditorFrame frame) {
|
||||
this.frame = frame;
|
||||
this.panel = panel;
|
||||
}
|
||||
|
||||
public EditorFrame getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent event) {
|
||||
Map map = getFrame().getMap();
|
||||
|
||||
int x = panel.getWidth() / 2 - map.getFont().getWidth();
|
||||
int y = panel.getHeight() / 2 - map.getFont().getHeight();
|
||||
Case c;
|
||||
|
||||
if ((c = map.getCase((event.getX() - x + 2) / 34, (event.getY() - y + 2) / 34)) != null && event.getX() - x >= 2 && event.getY() - y >= 2) {
|
||||
int colIndex = c.getCollision().ordinal();
|
||||
int newColIndex = colIndex + 1;
|
||||
if (newColIndex >= Collision.values().length)
|
||||
newColIndex = 0;
|
||||
Collision col = Collision.values()[newColIndex];
|
||||
Case n = Case.create(c.getPosX(), c.getPosY(), c.getCoucheOne(), c.getCoucheTwo(), c.getCoucheThree(), col);
|
||||
|
||||
map.setCase((event.getX() - x + 2) / 34, (event.getY() - y + 2) / 34, n);
|
||||
panel.repaint();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners;
|
||||
|
||||
import fr.ynerant.leveleditor.client.main.Main;
|
||||
import fr.ynerant.leveleditor.frame.MainFrame;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
/**
|
||||
* @author ÿnérant
|
||||
*/
|
||||
public class CreateMapListener implements ActionListener {
|
||||
/* !CodeTemplates.overridecomment.nonjd!
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
if (Main.launchEditMode())
|
||||
MainFrame.getInstance().dispose();
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Case;
|
||||
import fr.ynerant.leveleditor.editor.EditorFrame;
|
||||
import fr.ynerant.leveleditor.editor.Map;
|
||||
import fr.ynerant.leveleditor.editor.MapPanel;
|
||||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public class MapMouseListener extends MouseAdapter {
|
||||
private final EditorFrame frame;
|
||||
private final MapPanel panel;
|
||||
|
||||
public MapMouseListener(MapPanel panel, EditorFrame frame) {
|
||||
this.frame = frame;
|
||||
this.panel = panel;
|
||||
}
|
||||
|
||||
public EditorFrame getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent event) {
|
||||
if (frame.getSelectedPaintingMode() == 0) {
|
||||
Map map = getFrame().getMap();
|
||||
|
||||
int x = panel.getWidth() / 2 - map.getFont().getWidth();
|
||||
int y = panel.getHeight() / 2 - map.getFont().getHeight();
|
||||
Case c;
|
||||
|
||||
if ((c = map.getCase((event.getX() - x + 2) / 34, (event.getY() - y + 2) / 34)) != null && event.getX() - x >= 2 && event.getY() - y >= 2) {
|
||||
if (getFrame().getSelectedSprite() != null) {
|
||||
Case n;
|
||||
|
||||
switch (getFrame().getSelectedSprite().getCouche()) {
|
||||
case 0:
|
||||
n = Case.create(c.getPosX(), c.getPosY(), getFrame().getSelectedSprite().getSprite(), c.getCoucheTwo(), c.getCoucheThree(), c.getCollision());
|
||||
break;
|
||||
case 1:
|
||||
n = Case.create(c.getPosX(), c.getPosY(), c.getCoucheOne(), getFrame().getSelectedSprite().getSprite(), c.getCoucheThree(), c.getCollision());
|
||||
break;
|
||||
case 2:
|
||||
n = Case.create(c.getPosX(), c.getPosY(), c.getCoucheOne(), c.getCoucheTwo(), getFrame().getSelectedSprite().getSprite(), c.getCollision());
|
||||
break;
|
||||
default:
|
||||
n = c;
|
||||
break;
|
||||
}
|
||||
|
||||
map.setCase(n.getPosX(), n.getPosY(), n);
|
||||
panel.repaint();
|
||||
}
|
||||
}
|
||||
} else if (frame.getSelectedPaintingMode() == 1) {
|
||||
for (Case c : getFrame().getMap().getAllCases()) {
|
||||
Map map = getFrame().getMap();
|
||||
|
||||
if (getFrame().getSelectedSprite() != null) {
|
||||
if (getFrame().getSelectedSprite().getCouche() - 1 > getFrame().getSelectedLayerIndex())
|
||||
return;
|
||||
|
||||
Case n;
|
||||
|
||||
switch (getFrame().getSelectedSprite().getCouche()) {
|
||||
case 0:
|
||||
n = Case.create(c.getPosX(), c.getPosY(), getFrame().getSelectedSprite().getSprite(), c.getCoucheTwo(), c.getCoucheThree(), c.getCollision());
|
||||
break;
|
||||
case 1:
|
||||
n = Case.create(c.getPosX(), c.getPosY(), c.getCoucheOne(), getFrame().getSelectedSprite().getSprite(), c.getCoucheThree(), c.getCollision());
|
||||
break;
|
||||
case 2:
|
||||
n = Case.create(c.getPosX(), c.getPosY(), c.getCoucheOne(), c.getCoucheTwo(), getFrame().getSelectedSprite().getSprite(), c.getCollision());
|
||||
break;
|
||||
default:
|
||||
n = c;
|
||||
break;
|
||||
}
|
||||
|
||||
map.setCase(n.getPosX(), n.getPosY(), n);
|
||||
}
|
||||
}
|
||||
|
||||
panel.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent event) {
|
||||
if (frame.getSelectedPaintingMode() == 0) {
|
||||
mouseClicked(event);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.EditorAPI;
|
||||
import fr.ynerant.leveleditor.frame.MainFrame;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class OpenMapListener implements ActionListener {
|
||||
/* !CodeTemplates.overridecomment.nonjd!
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
if (EditorAPI.open() != null)
|
||||
MainFrame.getInstance().dispose();
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners;
|
||||
|
||||
import fr.ynerant.leveleditor.editor.EditorFrame;
|
||||
import fr.ynerant.leveleditor.editor.SpriteComp;
|
||||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
public class SpriteMouseListener extends MouseAdapter {
|
||||
private final SpriteComp sprite;
|
||||
private final EditorFrame frame;
|
||||
|
||||
public SpriteMouseListener(SpriteComp sprc, EditorFrame frame) {
|
||||
this.sprite = sprc;
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent event) {
|
||||
if (frame.getSelectedSprite() != null) {
|
||||
frame.getSelectedSprite().setSelected(false);
|
||||
frame.getSelectedSprite().repaint();
|
||||
}
|
||||
frame.setSelectedSprite(sprite);
|
||||
sprite.setSelected(true);
|
||||
sprite.repaint();
|
||||
}
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Collision;
|
||||
import fr.ynerant.leveleditor.api.editor.RawCase;
|
||||
import fr.ynerant.leveleditor.api.editor.RawMap;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
|
||||
import fr.ynerant.leveleditor.editor.CollidPanel;
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob;
|
||||
import fr.ynerant.leveleditor.game.towers.AutoTower;
|
||||
import fr.ynerant.leveleditor.game.towers.BasicTower;
|
||||
import fr.ynerant.leveleditor.game.towers.NullTower;
|
||||
import fr.ynerant.leveleditor.game.towers.Tower;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
public class GameFrame extends JFrame {
|
||||
private final Random RANDOM = new Random();
|
||||
private final RawMap map;
|
||||
|
||||
private int round = 0;
|
||||
private int hp = 5;
|
||||
private int reward = 20;
|
||||
private final List<Mob> mobs = new ArrayList<>();
|
||||
private final List<Tower> towers = new ArrayList<>();
|
||||
|
||||
private final JRadioButton basicTower;
|
||||
private final JRadioButton nullTower;
|
||||
private final JRadioButton autoTower;
|
||||
private final JLabel waveLabel;
|
||||
private final JLabel nbMobsLabel;
|
||||
private final JLabel hpLabel;
|
||||
private final JLabel rewardLabel;
|
||||
private final JLabel winLabel;
|
||||
|
||||
public GameFrame(RawMap map) {
|
||||
super("Jeu");
|
||||
|
||||
this.map = map;
|
||||
this.setSize(600, 600);
|
||||
this.setPreferredSize(getSize());
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
|
||||
this.setLocationRelativeTo(null);
|
||||
|
||||
JPanel root = new JPanel();
|
||||
root.setLayout(new BorderLayout());
|
||||
this.setContentPane(root);
|
||||
|
||||
JPanel pane = new JPanel();
|
||||
pane.setLayout(new GridLayout(8, 1));
|
||||
root.add(pane, BorderLayout.SOUTH);
|
||||
|
||||
Grid grid = new Grid();
|
||||
grid.setSize(map.getWidth(), map.getHeight());
|
||||
grid.setPreferredSize(grid.getSize());
|
||||
grid.setMinimumSize(grid.getSize());
|
||||
grid.setMaximumSize(grid.getSize());
|
||||
root.add(grid, BorderLayout.CENTER);
|
||||
|
||||
ButtonGroup towerSelect = new ButtonGroup();
|
||||
|
||||
basicTower = new JRadioButton("Tour basique (" + new BasicTower(0, 0).getPrice() + " pièces)");
|
||||
basicTower.setSelected(true);
|
||||
towerSelect.add(basicTower);
|
||||
pane.add(basicTower);
|
||||
|
||||
nullTower = new JRadioButton("Tour nulle (" + new NullTower(0, 0).getPrice() + " pièces)");
|
||||
towerSelect.add(nullTower);
|
||||
pane.add(nullTower);
|
||||
|
||||
autoTower = new JRadioButton("Tour automatique (" + new AutoTower(0, 0).getPrice() + " pièces)");
|
||||
towerSelect.add(autoTower);
|
||||
pane.add(autoTower);
|
||||
|
||||
waveLabel = new JLabel();
|
||||
pane.add(waveLabel);
|
||||
|
||||
nbMobsLabel = new JLabel();
|
||||
pane.add(nbMobsLabel);
|
||||
|
||||
hpLabel = new JLabel();
|
||||
pane.add(hpLabel);
|
||||
|
||||
rewardLabel = new JLabel();
|
||||
pane.add(rewardLabel);
|
||||
|
||||
winLabel = new JLabel();
|
||||
pane.add(winLabel);
|
||||
|
||||
setVisible(true);
|
||||
|
||||
new Thread(() -> {
|
||||
while (hp > 0 && (round < 4 || !mobs.isEmpty())) {
|
||||
tick();
|
||||
|
||||
try {
|
||||
Thread.sleep(50L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
public RawMap getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if (mobs.isEmpty() && round < 4) {
|
||||
++round;
|
||||
int nb_mobs = round * (RANDOM.nextInt(16) + 1);
|
||||
for (int i = 1; i <= nb_mobs; ++i) {
|
||||
Mob mob = Mob.getRandomMob();
|
||||
do
|
||||
mob.move(RANDOM.nextInt(getMap().getWidth() / 16), RANDOM.nextInt(getMap().getHeight() / 16));
|
||||
while (getMap().getCase(mob.getX(), mob.getY()).getCollision() != Collision.ANY);
|
||||
getMap().getCase(mob.getX(), mob.getY()).setCollision(Collision.PARTIAL);
|
||||
mobs.add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
for (Tower tower : towers) {
|
||||
for (Mob mob : tower.filterDetectedMobs(mobs))
|
||||
mob.hit(tower.getDamagePerShot());
|
||||
}
|
||||
|
||||
for (Mob mob : new ArrayList<>(mobs)) {
|
||||
getMap().getCase(mob.getX(), mob.getY()).setCollision(Collision.ANY);
|
||||
mob.tick(this);
|
||||
if (mob.getX() < 0 || mob.isDead()) {
|
||||
mobs.remove(mob);
|
||||
if (mob.getX() < 0) {
|
||||
--hp;
|
||||
if (hp == 0) {
|
||||
winLabel.setForeground(Color.red);
|
||||
winLabel.setText("Vous avez perdu !");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
reward += mob.getReward();
|
||||
}
|
||||
else
|
||||
getMap().getCase(mob.getX(), mob.getY()).setCollision(Collision.PARTIAL);
|
||||
}
|
||||
|
||||
waveLabel.setText("Vague " + round);
|
||||
nbMobsLabel.setText(mobs.size() + " mob" + (mobs.size() > 1 ? "s" : "") + " restant" + (mobs.size() > 1 ? "s" : ""));
|
||||
hpLabel.setText("Points de vie : " + hp);
|
||||
rewardLabel.setText("Butin : " + reward);
|
||||
|
||||
if (round == 4 && mobs.isEmpty()) {
|
||||
winLabel.setForeground(Color.green.darker());
|
||||
winLabel.setText("Vous avez gagné !");
|
||||
}
|
||||
}
|
||||
|
||||
private class Grid extends JComponent implements MouseListener {
|
||||
public Grid() {
|
||||
addMouseListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics _g) {
|
||||
Graphics2D g = (Graphics2D) _g;
|
||||
|
||||
if (getMap().getFont() != null)
|
||||
g.drawImage(getMap().getFont(), null, null);
|
||||
|
||||
SpriteRegister.refreshAllSprites();
|
||||
int SPRITE_SIZE = 32;
|
||||
for (RawCase c : getMap().getCases()) {
|
||||
Sprite s1 = SpriteRegister.getCategory(c.getCoucheOne().getCategory()).getSprites().get(c.getCoucheOne().getIndex());
|
||||
Sprite s2 = SpriteRegister.getCategory(c.getCoucheTwo().getCategory()).getSprites().get(c.getCoucheTwo().getIndex());
|
||||
Sprite s3 = SpriteRegister.getCategory(c.getCoucheThree().getCategory()).getSprites().get(c.getCoucheThree().getIndex());
|
||||
g.drawImage(s1.getImage(), SPRITE_SIZE * c.getPosX(), SPRITE_SIZE * c.getPosY(), SPRITE_SIZE, SPRITE_SIZE, Color.white, null);
|
||||
if (!CollidPanel.isEmpty(s2.getImage()))
|
||||
g.drawImage(s2.getImage(), SPRITE_SIZE * c.getPosX(), SPRITE_SIZE * c.getPosY(), SPRITE_SIZE, SPRITE_SIZE, null, null);
|
||||
if (!CollidPanel.isEmpty(s3.getImage()))
|
||||
g.drawImage(s3.getImage(), SPRITE_SIZE * c.getPosX(), SPRITE_SIZE * c.getPosY(), SPRITE_SIZE, SPRITE_SIZE, null, null);
|
||||
}
|
||||
|
||||
for (Mob mob : new ArrayList<>(mobs)) {
|
||||
Sprite s = mob.getSprite();
|
||||
g.drawImage(s.getImage(), SPRITE_SIZE * mob.getX(), SPRITE_SIZE * mob.getY(), SPRITE_SIZE, SPRITE_SIZE, null, null);
|
||||
}
|
||||
|
||||
for (Tower tower : towers) {
|
||||
Sprite s = tower.getSprite();
|
||||
g.drawImage(s.getImage(), SPRITE_SIZE * tower.getX(), SPRITE_SIZE * tower.getY(), SPRITE_SIZE, SPRITE_SIZE, null, null);
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent event) {}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent event) {}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent event) {
|
||||
int x = event.getX() / 32, y = event.getY() / 32;
|
||||
Tower tower = basicTower.isSelected() ? new BasicTower(x, y) :
|
||||
nullTower.isSelected() ? new NullTower(x, y) :
|
||||
autoTower.isSelected() ? new AutoTower(x, y) :
|
||||
null;
|
||||
if (tower == null || tower.getPrice() > reward)
|
||||
return;
|
||||
|
||||
RawCase c = getMap().getCase(x, y);
|
||||
if (c == null || c.getCollision() != Collision.ANY)
|
||||
return;
|
||||
c.setCollision(Collision.FULL);
|
||||
|
||||
reward -= tower.getPrice();
|
||||
towers.add(tower);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent event) {}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent event) {}
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.mobs;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.RawCase;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
|
||||
import fr.ynerant.leveleditor.game.GameFrame;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class Mob {
|
||||
private static final Random RANDOM = new Random();
|
||||
private Sprite sprite;
|
||||
private int x;
|
||||
private int y;
|
||||
private int hp;
|
||||
private long tickRemains;
|
||||
|
||||
public Mob() {
|
||||
this.hp = getMaxHP();
|
||||
this.tickRemains = getSlowness();
|
||||
}
|
||||
|
||||
public abstract int getMaxHP();
|
||||
|
||||
public abstract long getSlowness();
|
||||
|
||||
public abstract int getReward();
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public Sprite getSprite() {
|
||||
if (sprite == null)
|
||||
sprite = SpriteRegister.getCategory(getName()).getSprites().get(0);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void move(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getHP() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public boolean isDead() {
|
||||
return hp <= 0;
|
||||
}
|
||||
|
||||
public void setHP(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public boolean hit(int damage) {
|
||||
if (!isDead()) {
|
||||
this.hp -= damage;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void tick(GameFrame game) {
|
||||
if (tickRemains > 0)
|
||||
--tickRemains;
|
||||
else {
|
||||
tickRemains = getSlowness();
|
||||
RawCase current = game.getMap().getCase(getX(), getY());
|
||||
|
||||
if (current.getPosX() == 0) {
|
||||
move(-1, getY());
|
||||
return;
|
||||
}
|
||||
|
||||
List<RawCase> visited = new ArrayList<>();
|
||||
Queue<RawCase> queue = new ArrayDeque<>();
|
||||
Map<RawCase, RawCase> pred = new HashMap<>();
|
||||
RawCase last = null;
|
||||
queue.add(current);
|
||||
while (!queue.isEmpty()) {
|
||||
RawCase visiting = queue.poll();
|
||||
visited.add(visiting);
|
||||
for (RawCase neighbour : game.getMap().getNeighbours(visiting)) {
|
||||
if (visited.contains(neighbour))
|
||||
continue;
|
||||
|
||||
pred.put(neighbour, visiting);
|
||||
queue.add(neighbour);
|
||||
|
||||
if (neighbour.getPosX() == 0) {
|
||||
last = neighbour;
|
||||
queue.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (last != null) {
|
||||
while (pred.get(last) != current)
|
||||
last = pred.get(last);
|
||||
move(last.getPosX(), last.getPosY());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Mob{" +
|
||||
"sprite=" + sprite +
|
||||
", x=" + x +
|
||||
", y=" + y +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Mob getRandomMob() {
|
||||
switch (RANDOM.nextInt(3)) {
|
||||
case 1:
|
||||
return new Mob1();
|
||||
case 2:
|
||||
return new Mob2();
|
||||
default:
|
||||
return new MobCancer();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.mobs;
|
||||
|
||||
public class Mob1 extends Mob {
|
||||
@Override
|
||||
public int getMaxHP() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSlowness() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReward() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "mob1";
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.mobs;
|
||||
|
||||
public class Mob2 extends Mob {
|
||||
@Override
|
||||
public int getMaxHP() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSlowness() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReward() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "mob2";
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.mobs;
|
||||
|
||||
public class MobCancer extends Mob {
|
||||
@Override
|
||||
public int getMaxHP() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSlowness() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReward() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "mobcancer";
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.towers;
|
||||
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class AutoTower extends Tower {
|
||||
public AutoTower(int x, int y) {
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "autotower";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDamagePerShot() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPeriod() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrice() {
|
||||
return 142;
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Mob> _filterDetectedMobs(Collection<Mob> mobs) {
|
||||
return mobs;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.towers;
|
||||
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class BasicTower extends Tower {
|
||||
public BasicTower(int x, int y) {
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "basictower";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDamagePerShot() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPeriod() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrice() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Mob> _filterDetectedMobs(Collection<Mob> mobs) {
|
||||
List<Mob> filtered = new ArrayList<>();
|
||||
|
||||
for (Mob mob : mobs) {
|
||||
if ((mob.getX() == getX() || mob.getY() == getY())
|
||||
&& Math.abs(mob.getX() - getX()) <= 3 && Math.abs(mob.getY() - getY()) <= 3)
|
||||
filtered.add(mob);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.towers;
|
||||
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class NullTower extends Tower {
|
||||
public NullTower(int x, int y) {
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "nulltower";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDamagePerShot() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPeriod() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrice() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Mob> _filterDetectedMobs(Collection<Mob> mobs) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package fr.ynerant.leveleditor.game.towers;
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Tower {
|
||||
private final Sprite sprite;
|
||||
private final int x;
|
||||
private final int y;
|
||||
private long remainingTicks;
|
||||
|
||||
public Tower(int x, int y) {
|
||||
this.sprite = SpriteRegister.getCategory(getName()).getSprites().get(0);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public Sprite getSprite() {
|
||||
return sprite;
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract int getDamagePerShot();
|
||||
|
||||
public abstract long getPeriod();
|
||||
|
||||
public abstract int getPrice();
|
||||
|
||||
abstract Collection<Mob> _filterDetectedMobs(Collection<Mob> mobs);
|
||||
|
||||
public Collection<Mob> filterDetectedMobs(Collection<Mob> mobs) {
|
||||
if (remainingTicks > 0) {
|
||||
--remainingTicks;
|
||||
return new ArrayList<>();
|
||||
}
|
||||
else {
|
||||
remainingTicks = getPeriod();
|
||||
return _filterDetectedMobs(mobs);
|
||||
}
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
Manifest-Version: 1.0
|
||||
Main-Class: fr.ynerant.leveleditor.client.main.Main
|
||||
|
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 697 B After Width: | Height: | Size: 697 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 760 B After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 732 B After Width: | Height: | Size: 732 B |
|
@ -325,16 +325,34 @@
|
|||
"mob2": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobcancer": [
|
||||
"mobstrong": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobhealer": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobbreaker": [
|
||||
[0, 0]
|
||||
],
|
||||
"mobspeeder": [
|
||||
[0, 0]
|
||||
],
|
||||
"basictower": [
|
||||
[0, 0]
|
||||
],
|
||||
"nulltower": [
|
||||
"walltower": [
|
||||
[0, 0]
|
||||
],
|
||||
"autotower": [
|
||||
"freezertower": [
|
||||
[0, 0]
|
||||
],
|
||||
"explodertower": [
|
||||
[0, 0]
|
||||
],
|
||||
"upgradetower": [
|
||||
[0, 0]
|
||||
],
|
||||
"lasertower": [
|
||||
[0, 0]
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 697 B |
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration package="log4j.test" status="info">
|
||||
<Loggers>
|
||||
<Root level="info">
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
|
@ -0,0 +1,40 @@
|
|||
package fr.ynerant.leveleditor.api.editor
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite
|
||||
|
||||
|
||||
object Case {
|
||||
def create(posX: Int, posY: Int, couche1: Sprite, couche2: Sprite, couche3: Sprite, collision: String): Case = {
|
||||
val c = new Case
|
||||
c.x = posX
|
||||
c.y = posY
|
||||
c.couche1 = couche1
|
||||
c.couche2 = couche2
|
||||
c.couche3 = couche3
|
||||
c.collision = collision
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
class Case {
|
||||
private var x = 0
|
||||
private var y = 0
|
||||
private var couche1 = null: Sprite
|
||||
private var couche2 = null: Sprite
|
||||
private var couche3 = null: Sprite
|
||||
private var collision = null: String
|
||||
|
||||
def getPosX: Int = x
|
||||
|
||||
def getPosY: Int = y
|
||||
|
||||
def getCoucheOne: Sprite = couche1
|
||||
|
||||
def getCoucheTwo: Sprite = couche2
|
||||
|
||||
def getCoucheThree: Sprite = couche3
|
||||
|
||||
def getCollision: String = collision
|
||||
|
||||
override def toString: String = "{Case x=" + x + " y=" + y + " couche1=" + couche1 + " couche2=" + couche2 + " couche3=" + couche3 + " collision=" + collision.toString.toUpperCase + "}\n"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package fr.ynerant.leveleditor.api.editor
|
||||
|
||||
object Collision {
|
||||
val FULL: String = "FULL"
|
||||
val PARTIAL: String = "PARTIAL"
|
||||
val ANY: String = "ANY"
|
||||
|
||||
val values: IndexedSeq[String] = IndexedSeq(FULL, PARTIAL, ANY)
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package fr.ynerant.leveleditor.api.editor
|
||||
|
||||
import java.awt.Color
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io._
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.zip.{GZIPInputStream, GZIPOutputStream}
|
||||
|
||||
import fr.ynerant.leveleditor.editor.GMap
|
||||
import javax.swing.JFileChooser
|
||||
import javax.swing.filechooser.FileNameExtensionFilter
|
||||
import net.liftweb.json._
|
||||
|
||||
object EditorAPI {
|
||||
private var LAST_FILE = null: File
|
||||
|
||||
def toRawMap(width: Int, height: Int): RawMap = {
|
||||
var cases = Nil: List[RawCase]
|
||||
var y = 1
|
||||
while ( {
|
||||
y < height
|
||||
}) {
|
||||
var x = 1
|
||||
while ( {
|
||||
x < width
|
||||
}) {
|
||||
val c = RawCase.create(x / 16, y / 16, RawSprite.BLANK, RawSprite.BLANK, RawSprite.BLANK, Collision.ANY)
|
||||
cases ::= c
|
||||
|
||||
x += 16
|
||||
}
|
||||
|
||||
y += 16
|
||||
}
|
||||
RawMap.create(cases, width, height)
|
||||
}
|
||||
|
||||
def createJFC: JFileChooser = {
|
||||
val jfc = new JFileChooser
|
||||
jfc.setFileFilter(new FileNameExtensionFilter("Fichiers monde (*.gmap, *.dat)", "gmap", "dat"))
|
||||
jfc.setFileHidingEnabled(true)
|
||||
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY)
|
||||
val dir = new File("maps")
|
||||
assert(dir.isDirectory || dir.mkdirs)
|
||||
jfc.setCurrentDirectory(dir)
|
||||
jfc
|
||||
}
|
||||
|
||||
def saveAs(map: RawMap): Unit = {
|
||||
val jfc = createJFC
|
||||
var file = null: File
|
||||
jfc.showSaveDialog(null)
|
||||
file = jfc.getSelectedFile
|
||||
if (file == null) return
|
||||
if (!file.getName.toLowerCase.endsWith(".gmap") && !file.getName.toLowerCase.endsWith(".dat")) file = new File(file.getParentFile, file.getName + ".gmap")
|
||||
LAST_FILE = file
|
||||
save(file, map)
|
||||
}
|
||||
|
||||
def save(map: RawMap): Unit = {
|
||||
if (LAST_FILE != null) save(LAST_FILE, map)
|
||||
else saveAs(map)
|
||||
}
|
||||
|
||||
def save(file: File, map: RawMap): Unit = {
|
||||
implicit val formats: DefaultFormats.type = DefaultFormats
|
||||
val json = Serialization.writePretty(map)
|
||||
try {
|
||||
assert(file.exists() || file.createNewFile)
|
||||
val bos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(file)))
|
||||
bos.write(json.getBytes(StandardCharsets.UTF_8))
|
||||
bos.close()
|
||||
} catch {
|
||||
case ex: IOException =>
|
||||
ex.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
def open: GMap = {
|
||||
val jfc = createJFC
|
||||
var file = null: File
|
||||
jfc.showOpenDialog(null)
|
||||
file = jfc.getSelectedFile
|
||||
if (file == null) return null
|
||||
LAST_FILE = file
|
||||
open(file)
|
||||
}
|
||||
|
||||
def getRawMap(f: File): RawMap = {
|
||||
var json = null: String
|
||||
try {
|
||||
val gis = new GZIPInputStream(new BufferedInputStream(new FileInputStream(f)))
|
||||
val bytes = new Array[Byte](512 * 1024)
|
||||
var count = 0
|
||||
val text = new StringBuilder
|
||||
while ( {
|
||||
count = gis.read(bytes)
|
||||
count != -1
|
||||
}) text.append(new String(bytes, 0, count, StandardCharsets.UTF_8))
|
||||
gis.close()
|
||||
json = text.toString
|
||||
} catch {
|
||||
case e: IOException =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
implicit val formats: DefaultFormats.type = DefaultFormats
|
||||
parse(json).extract[RawMap]
|
||||
}
|
||||
|
||||
def open(f: File): GMap = open(getRawMap(f))
|
||||
|
||||
def open(map: RawMap): GMap = {
|
||||
if (map.getFont == null) {
|
||||
val baseWidth = map.getWidth
|
||||
val baseHeight = map.getHeight
|
||||
val width = baseWidth + (baseWidth / 16) + 1
|
||||
val height = baseHeight + (baseHeight / 16) + 1
|
||||
val image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = image.createGraphics
|
||||
g.setColor(Color.white)
|
||||
g.fillRect(0, 0, width, height)
|
||||
g.setColor(Color.black)
|
||||
g.drawLine(0, 0, width, 0)
|
||||
g.drawLine(0, 0, 0, height)
|
||||
var x = 17
|
||||
while ( {
|
||||
x <= width
|
||||
}) {
|
||||
g.drawLine(x, 0, x, height)
|
||||
|
||||
x += 17
|
||||
}
|
||||
var y = 17
|
||||
while ( {
|
||||
y <= height
|
||||
}) {
|
||||
g.drawLine(0, y, width, y)
|
||||
|
||||
y += 17
|
||||
}
|
||||
map.setFont(image)
|
||||
}
|
||||
new GMap(map)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package fr.ynerant.leveleditor.api.editor
|
||||
|
||||
object RawCase {
|
||||
def create(posX: Int, posY: Int, couche1: RawSprite, couche2: RawSprite, couche3: RawSprite, collision: String): RawCase = {
|
||||
new RawCase(posX, posY, couche1, couche2, couche3, collision)
|
||||
}
|
||||
|
||||
def create(c: Case): RawCase = {
|
||||
new RawCase(c.getPosX, c.getPosY, RawSprite.create(c.getCoucheOne), RawSprite.create(c.getCoucheTwo), RawSprite.create(c.getCoucheThree), c.getCollision)
|
||||
}
|
||||
}
|
||||
|
||||
case class RawCase(var x: Int, var y: Int, var couche1: RawSprite, var couche2: RawSprite, var couche3: RawSprite, var collision: String) {
|
||||
def getPosX: Int = x
|
||||
|
||||
def getPosY: Int = y
|
||||
|
||||
def getCoucheOne: RawSprite = couche1
|
||||
|
||||
def getCoucheTwo: RawSprite = couche2
|
||||
|
||||
def getCoucheThree: RawSprite = couche3
|
||||
|
||||
def getCollision: String = collision // FULL, PARTIAL or ANY
|
||||
|
||||
def setCollision(collision: String): Unit = {
|
||||
this.collision = collision
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package fr.ynerant.leveleditor.api.editor
|
||||
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
import fr.ynerant.leveleditor.editor.GMap
|
||||
import net.liftweb.json._
|
||||
|
||||
|
||||
object RawMap {
|
||||
def create(cases: List[RawCase], width: Int, height: Int): RawMap = {
|
||||
new RawMap(cases, width, height)
|
||||
}
|
||||
|
||||
def create(map: GMap): RawMap = {
|
||||
val raw = new RawMap(Nil, map.getWidth, map.getHeight)
|
||||
map.getAllCases.foreach(c => raw.cases ::= RawCase.create(c))
|
||||
raw
|
||||
}
|
||||
}
|
||||
|
||||
case class RawMap(var cases: List[RawCase], var width: Int, var height: Int) {
|
||||
private var cases_map = null: Map[Integer, RawCase]
|
||||
private var font = null: BufferedImage
|
||||
|
||||
def getNeighbours(c: RawCase): Iterable[RawCase] = {
|
||||
var list = Nil: List[RawCase]
|
||||
list ::= getCase(c.getPosX, c.getPosY - 1)
|
||||
list ::= getCase(c.getPosX + 1, c.getPosY)
|
||||
list ::= getCase(c.getPosX, c.getPosY + 1)
|
||||
list ::= getCase(c.getPosX - 1, c.getPosY)
|
||||
list.filter((_c: RawCase) => _c != null)
|
||||
}
|
||||
|
||||
def getCase(x: Int, y: Int): RawCase = {
|
||||
if (cases_map == null) {
|
||||
cases_map = Map()
|
||||
getCases.foreach(c => cases_map = cases_map.updated(c.getPosY * width + c.getPosX, c))
|
||||
}
|
||||
cases_map.getOrElse(y * getWidth + x, null)
|
||||
}
|
||||
|
||||
def getCases: List[RawCase] = cases
|
||||
|
||||
def getWidth: Int = width
|
||||
|
||||
def getHeight: Int = height
|
||||
|
||||
def getFont: BufferedImage = font
|
||||
|
||||
def setFont(font: BufferedImage): Unit = {
|
||||
this.font = font
|
||||
}
|
||||
|
||||
override def toString: String = {
|
||||
implicit val formats: DefaultFormats.type = DefaultFormats
|
||||
Serialization.writePretty(this)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package fr.ynerant.leveleditor.api.editor
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite
|
||||
|
||||
|
||||
object RawSprite {
|
||||
val BLANK = new RawSprite("blank", 0)
|
||||
|
||||
def create(spr: Sprite): RawSprite = {
|
||||
new RawSprite(spr.getCategory.getName, spr.getIndex)
|
||||
}
|
||||
}
|
||||
|
||||
case class RawSprite(var category: String, protected var index: Int) {
|
||||
if (category == null) category = "blank"
|
||||
|
||||
def getCategory: String = category
|
||||
|
||||
def getIndex: Int = index
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package fr.ynerant.leveleditor.api.editor.sprites
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object Category {
|
||||
def create(name: String, sprites: ListBuffer[Sprite]): Category = {
|
||||
val c = new Category
|
||||
c.name = name
|
||||
c.sprites = sprites
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
class Category private() {
|
||||
private var sprites = null: ListBuffer[Sprite]
|
||||
private var name = null: String
|
||||
|
||||
def getName: String = name
|
||||
|
||||
def getSprites: ListBuffer[Sprite] = sprites
|
||||
|
||||
def addSprite(s: Sprite): Unit = {
|
||||
this.sprites += s
|
||||
}
|
||||
|
||||
override def toString: String = name
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fr.ynerant.leveleditor.api.editor.sprites
|
||||
|
||||
import java.awt._
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object Sprite {
|
||||
val BLANK = new Sprite(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), Category.create("blank", ListBuffer()), 0)
|
||||
|
||||
val g: Graphics2D = BLANK.getImage.createGraphics
|
||||
g.setComposite(AlphaComposite.Clear)
|
||||
g.setColor(new Color(0, true))
|
||||
g.fillRect(0, 0, 16, 16)
|
||||
|
||||
}
|
||||
|
||||
class Sprite(val img: BufferedImage, val cat: Category, val index: Int) {
|
||||
if (!this.cat.getSprites.contains(this)) this.cat.addSprite(this)
|
||||
|
||||
def getImage: BufferedImage = this.img
|
||||
|
||||
def getCategory: Category = cat
|
||||
|
||||
def getIndex: Int = index
|
||||
|
||||
override def hashCode: Int = cat.hashCode ^ getIndex
|
||||
|
||||
override def equals(o: Any): Boolean = {
|
||||
if (!o.isInstanceOf[Sprite]) return false
|
||||
val other = o.asInstanceOf[Sprite]
|
||||
hashCode == other.hashCode
|
||||
}
|
||||
|
||||
override def toString: String = "{Sprite img=" + img + " cat=" + cat.getName + "}"
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package fr.ynerant.leveleditor.api.editor.sprites
|
||||
|
||||
import java.io.{BufferedInputStream, File, FileInputStream, IOException}
|
||||
import java.net.{URISyntaxException, URLDecoder}
|
||||
import java.nio.file.{Files, Paths}
|
||||
import java.util.Objects
|
||||
import java.util.jar.JarFile
|
||||
|
||||
import fr.ynerant.leveleditor.client.main.Main
|
||||
import javax.imageio.ImageIO
|
||||
import net.liftweb.json._
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object SpriteRegister {
|
||||
private var nameToCoords = Map(): Map[String, List[List[Int]]]
|
||||
private var sprites = Map(): Map[String, Category]
|
||||
|
||||
@throws[IOException]
|
||||
def unpack(): Unit = {
|
||||
if (Main.isInDevelopmentMode) try {
|
||||
val dir = new File(getClass.getResource("/assets").toURI)
|
||||
unpackDir(dir)
|
||||
} catch {
|
||||
case e: URISyntaxException =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
else {
|
||||
@SuppressWarnings(Array("deprecation")) val path = URLDecoder.decode(getClass.getProtectionDomain.getCodeSource.getLocation.getPath, "UTF-8")
|
||||
val jarFile = new File(path)
|
||||
if (jarFile.isFile) {
|
||||
val jar = new JarFile(jarFile)
|
||||
val entries = jar.entries
|
||||
while ( {
|
||||
entries.hasMoreElements
|
||||
}) {
|
||||
val je = entries.nextElement
|
||||
val name = je.getName
|
||||
if (name.startsWith("assets/")) {
|
||||
val f = new File(name)
|
||||
if (name.endsWith("/")) {
|
||||
if (!f.mkdirs && !f.isDirectory) throw new IOException("Unable to make dir: " + f)
|
||||
}
|
||||
else if (!f.isFile) Files.copy(jar.getInputStream(je), Paths.get(f.toURI))
|
||||
}
|
||||
}
|
||||
jar.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@throws[IOException]
|
||||
private def unpackDir(dir: File): Unit = {
|
||||
for (f <- Objects.requireNonNull(dir.listFiles)) {
|
||||
if (f.isDirectory) {
|
||||
unpackDir(f)
|
||||
}
|
||||
else {
|
||||
val path = f.getAbsolutePath.substring(f.getAbsolutePath.indexOf(File.separatorChar + "assets") + 1)
|
||||
val local = new File(path)
|
||||
assert(local.getParentFile.isDirectory || local.getParentFile.mkdirs)
|
||||
assert(!local.exists || local.delete)
|
||||
Files.copy(Paths.get(f.toURI), Paths.get(local.toURI))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings(Array("unchecked")) def refreshAllSprites(): Unit = {
|
||||
if (nameToCoords != null && nameToCoords.nonEmpty && sprites.nonEmpty) return
|
||||
val assetsDir = new File("assets")
|
||||
var assets = Nil: List[String]
|
||||
for (dir <- Objects.requireNonNull(assetsDir.listFiles)) {
|
||||
assets ::= dir.getName
|
||||
}
|
||||
|
||||
assets.foreach(asset => {
|
||||
try {
|
||||
val f = new File(assetsDir.getAbsolutePath + "/" + asset + "/textures/sprites")
|
||||
assert(f.isDirectory || f.mkdirs)
|
||||
val json = Files.readString(new File(f, "sprites.json").toPath)
|
||||
implicit val formats: DefaultFormats.type = DefaultFormats
|
||||
nameToCoords = parse(json).extract[Map[String, List[List[Int]]]]
|
||||
nameToCoords.keySet.foreach(key => {
|
||||
try {
|
||||
val is = new BufferedInputStream(new FileInputStream(new File(f, key + ".png")))
|
||||
val img = ImageIO.read(is)
|
||||
val cat = Category.create(key, ListBuffer())
|
||||
nameToCoords(key).foreach(list => {
|
||||
val x = list.head.intValue
|
||||
val y = list(1).intValue
|
||||
val child = img.getSubimage(x, y, 16, 16)
|
||||
new Sprite(child, cat, nameToCoords(key).toIndexedSeq.indexOf(list))
|
||||
})
|
||||
sprites += (key -> cat)
|
||||
} catch {
|
||||
case t: Throwable =>
|
||||
System.err.println("Erreur lors de la lecture du sprite '" + key + "'")
|
||||
t.printStackTrace()
|
||||
}
|
||||
})
|
||||
} catch {
|
||||
case e: IOException =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
def getCategory(name: String): Category = sprites(name)
|
||||
|
||||
def getAllCategories: List[Category] = sprites.values.toList
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package fr.ynerant.leveleditor.client.main
|
||||
|
||||
import java.awt._
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.{File, IOException}
|
||||
import java.net.{URISyntaxException, URL}
|
||||
import java.util.Locale
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.EditorAPI
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister
|
||||
import fr.ynerant.leveleditor.frame.MainFrame
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
import javax.swing._
|
||||
|
||||
|
||||
/**
|
||||
* Class principale qui lance le jeu
|
||||
*
|
||||
* @author ÿnérant
|
||||
* @see #main(String...)
|
||||
*/
|
||||
object Main {
|
||||
/**
|
||||
* Variable disant si le jeu est lancé en développement ou non.
|
||||
*
|
||||
* @see #isInDevelopmentMode()
|
||||
* @see #main(String...)
|
||||
* @since 0.1-aplha
|
||||
*/
|
||||
private var DEV = false
|
||||
|
||||
/**
|
||||
* Accesseur disant si le jeu est lancé en développement ou non.
|
||||
*
|
||||
* @see #DEV
|
||||
* @since 0.1-alpha
|
||||
*/
|
||||
def isInDevelopmentMode: Boolean = DEV
|
||||
|
||||
/**
|
||||
* @param args arguments du jeu. Possibilités :<br> <strong>--edit</strong> lancera un éditeur<br> <strong>--help</strong> lance l'aide affichant toutes les options possibles
|
||||
* @see #launchEditMode()
|
||||
* @since 0.1-alpha
|
||||
*/
|
||||
def main(args: Array[String]): Unit = {
|
||||
System.setProperty("sun.java2d.noddraw", "true")
|
||||
Locale.setDefault(Locale.FRANCE)
|
||||
try UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName)
|
||||
catch {
|
||||
case e: Exception =>
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace()
|
||||
System.err.print("Caused by ")
|
||||
e.printStackTrace()
|
||||
}
|
||||
try {
|
||||
new File(getClass.getResource("/assets").toURI)
|
||||
DEV = true
|
||||
} catch {
|
||||
case t: Throwable =>
|
||||
DEV = false
|
||||
}
|
||||
|
||||
try SpriteRegister.unpack()
|
||||
catch {
|
||||
case e: IOException =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
SpriteRegister.refreshAllSprites()
|
||||
|
||||
launchFrame()
|
||||
}
|
||||
|
||||
private def checkJava(): Unit = {
|
||||
if (GraphicsEnvironment.isHeadless) {
|
||||
val ex = new HeadlessException("Impossible de lancer un jeu sans \u00e9cran !")
|
||||
System.err.println("Cette application est un jeu, sans écran, elle aura du mal \u00e0 tourner ...")
|
||||
ex.printStackTrace()
|
||||
System.exit(1)
|
||||
}
|
||||
try classOf[Map[_, _]].getDeclaredMethod("getOrDefault", classOf[Any], classOf[Any])
|
||||
catch {
|
||||
case ex: NoSuchMethodException =>
|
||||
ex.printStackTrace()
|
||||
JOptionPane.showMessageDialog(null, "<html>Cette application requiert <strong>Java 8</strong>.<br />La page de t\u00e9l\u00e9chargement va maintenant s'ouvrir.</html>")
|
||||
JOptionPane.showMessageDialog(null, "<html>Si vous êtes certain que Java 8 est installé sur votre machine, assurez-vous qu'il n'y a pas de versions obsolètes de Java,<br />ou si vous êtes plus expérimentés si le path vers Java est bien défini vers la bonne version.</html>")
|
||||
try if (Desktop.isDesktopSupported) Desktop.getDesktop.browse(new URL("http://java.com/download").toURI)
|
||||
else JOptionPane.showMessageDialog(null, "<html>Votre machine ne supporte pas la classe Desktop, impossible d'ouvrir la page.<br />Rendez-vous y manuellement sur <a href=\"http://java.com/download\">http://java.com/download</a> pour installer Java.</html>")
|
||||
catch {
|
||||
case e@(_: IOException | _: URISyntaxException) =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
System.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lance la fenêtre principale
|
||||
*
|
||||
* @see #main(String...)
|
||||
* @see #launchEditMode()
|
||||
*/
|
||||
private def launchFrame(): Unit = {
|
||||
MainFrame.getInstance.setVisible(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de lancer l'éditeur de carte
|
||||
*
|
||||
* @see #main(String...)
|
||||
* @see #launchFrame()
|
||||
* @since 0.1-aplha
|
||||
*/
|
||||
def launchEditMode: Boolean = {
|
||||
System.out.println("Lancement de l'\u00e9diteur de monde ...")
|
||||
var baseWidth = 0
|
||||
var baseHeight = 0
|
||||
var width = 0
|
||||
var height = 0
|
||||
while (baseWidth <= 0) {
|
||||
try {
|
||||
val baseWidthStr = JOptionPane.showInputDialog(null, "Veuillez entrez le nombre de cases longueur de votre carte (0 pour annuler) :")
|
||||
if (baseWidthStr == null) return false
|
||||
baseWidth = baseWidthStr.toInt * 16
|
||||
if (baseWidth < 0) throw new NumberFormatException
|
||||
if (baseWidth == 0) return false
|
||||
} catch {
|
||||
case ignored: NumberFormatException =>
|
||||
|
||||
}
|
||||
}
|
||||
while (baseHeight <= 0) {
|
||||
try {
|
||||
val baseHeightStr = JOptionPane.showInputDialog("Veuillez entrez le nombre de cases hauteur de votre carte (0 pour annuler) :")
|
||||
if (baseHeightStr == null) return false
|
||||
baseHeight = baseHeightStr.toInt * 16
|
||||
if (baseHeight < 0) throw new NumberFormatException
|
||||
if (baseHeight == 0) return false
|
||||
} catch {
|
||||
case ignored: NumberFormatException =>
|
||||
}
|
||||
}
|
||||
width = baseWidth + (baseWidth / 16) + 1
|
||||
height = baseHeight + (baseHeight / 16) + 1
|
||||
val image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = image.createGraphics
|
||||
g.setColor(Color.white)
|
||||
g.fillRect(0, 0, width, height)
|
||||
g.setColor(Color.black)
|
||||
g.drawLine(0, 0, width, 0)
|
||||
g.drawLine(0, 0, 0, height)
|
||||
var x = 17
|
||||
while ( {
|
||||
x <= width
|
||||
}) {
|
||||
g.drawLine(x, 0, x, height)
|
||||
|
||||
x += 17
|
||||
}
|
||||
var y = 17
|
||||
while ( {
|
||||
y <= height
|
||||
}) {
|
||||
g.drawLine(0, y, width, y)
|
||||
|
||||
y += 17
|
||||
}
|
||||
val rm = EditorAPI.toRawMap(baseWidth, baseHeight)
|
||||
rm.setFont(image)
|
||||
EditorAPI.open(rm)
|
||||
true
|
||||
}
|
||||
|
||||
def launchGameMode: Boolean = {
|
||||
println("Lancement du jeu ...")
|
||||
val jfc = EditorAPI.createJFC
|
||||
jfc.showOpenDialog(MainFrame.getInstance)
|
||||
if (jfc.getSelectedFile == null) return false
|
||||
val map = EditorAPI.getRawMap(jfc.getSelectedFile)
|
||||
new GameFrame(map)
|
||||
true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package fr.ynerant.leveleditor.editor
|
||||
|
||||
import java.awt._
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Collision
|
||||
import javax.swing._
|
||||
|
||||
|
||||
@SerialVersionUID(-138754019431984881L)
|
||||
object CollidPanel {
|
||||
def isEmpty(image: BufferedImage): Boolean = {
|
||||
var allrgba = 0
|
||||
for (x <- 0 until image.getWidth) {
|
||||
for (y <- 0 until image.getHeight) {
|
||||
allrgba += image.getRGB(x, y) + 1
|
||||
}
|
||||
}
|
||||
allrgba == 0
|
||||
}
|
||||
}
|
||||
|
||||
@SerialVersionUID(-138754019431984881L)
|
||||
class CollidPanel(val frame: EditorFrame) extends JPanel {
|
||||
override def paintComponent(g: Graphics): Unit = {
|
||||
g.fillRect(0, 0, getWidth, getHeight)
|
||||
val img = getMap.getFont
|
||||
val x = getWidth / 2 - img.getWidth
|
||||
val y = getHeight / 2 - img.getHeight
|
||||
val width = img.getWidth * 2
|
||||
val height = img.getHeight * 2
|
||||
g.drawImage(getMap.getFont, x, y, width, height, null)
|
||||
getMap.getAllCases.foreach(c => {
|
||||
if (!CollidPanel.isEmpty(c.getCoucheOne.getImage)) g.drawImage(c.getCoucheOne.getImage, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
if (!CollidPanel.isEmpty(c.getCoucheTwo.getImage)) g.drawImage(c.getCoucheTwo.getImage, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
if (!CollidPanel.isEmpty(c.getCoucheThree.getImage)) g.drawImage(c.getCoucheThree.getImage, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
})
|
||||
|
||||
getMap.getAllCases.foreach(c => {
|
||||
if (!c.getCollision.equals(Collision.ANY)) {
|
||||
val alpha = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB)
|
||||
if (c.getCollision.equals(Collision.FULL)) {
|
||||
val grap = alpha.createGraphics
|
||||
grap.setColor(new Color(0, 0, 0, 100))
|
||||
grap.fillRect(0, 0, 16, 16)
|
||||
grap.dispose()
|
||||
}
|
||||
else if (c.getCollision.equals(Collision.PARTIAL)) {
|
||||
val grap = alpha.createGraphics
|
||||
grap.setColor(new Color(255, 0, 255, 70))
|
||||
grap.fillRect(0, 0, 16, 16)
|
||||
grap.dispose()
|
||||
}
|
||||
g.drawImage(alpha, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
def getMap: GMap = frame.getMap
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
package fr.ynerant.leveleditor.editor
|
||||
|
||||
import java.awt._
|
||||
import java.awt.event._
|
||||
import java.io.File
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister
|
||||
import fr.ynerant.leveleditor.api.editor.{EditorAPI, RawMap}
|
||||
import fr.ynerant.leveleditor.frame.listeners._
|
||||
import javax.swing._
|
||||
import javax.swing.event.{ChangeEvent, ChangeListener}
|
||||
|
||||
|
||||
@SerialVersionUID(-2705122356101556462L)
|
||||
class EditorFrame(val map: GMap) extends JFrame("Level Editor") with ChangeListener with ActionListener with WindowListener {
|
||||
final private val save = new JMenuItem("Sauvegarder")
|
||||
final private val saveAs = new JMenuItem("Sauvegarder sous ...")
|
||||
final private val exit = new JMenuItem("Quitter")
|
||||
final private val pen = new JRadioButtonMenuItem("Pinceau")
|
||||
final private val pot = new JRadioButtonMenuItem("Pot de peinture")
|
||||
final private val tabs = new JTabbedPane
|
||||
final private var tabColl = null: CollidPanel
|
||||
final private var mapPanel = null: MapPanel
|
||||
final private val resources = new JTabbedPane
|
||||
final private val couche1 = new JPanel
|
||||
final private val couche2 = new JPanel
|
||||
final private val couche3 = new JPanel
|
||||
final private[editor] val group = new ButtonGroup
|
||||
private var selectedSprite = null: SpriteComp
|
||||
|
||||
this.setSize(1000, 1000)
|
||||
this.setPreferredSize(getSize)
|
||||
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
|
||||
this.setExtendedState(Frame.MAXIMIZED_BOTH)
|
||||
this.setLocationRelativeTo(null)
|
||||
this.addWindowListener(this)
|
||||
val content = new JPanel
|
||||
content.setLayout(new BorderLayout)
|
||||
this.setContentPane(content)
|
||||
this.setVisible(true)
|
||||
this.setVisible(false)
|
||||
val fichier = new JMenu("Fichier")
|
||||
fichier.setMnemonic(KeyEvent.VK_F + KeyEvent.VK_ALT)
|
||||
val nouveau = new JMenuItem("Nouveau")
|
||||
nouveau.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.VK_CONTROL, true))
|
||||
nouveau.addActionListener(new CreateMapListener)
|
||||
fichier.add(nouveau)
|
||||
val open = new JMenuItem("Ouvrir")
|
||||
open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.VK_CONTROL, true))
|
||||
open.addActionListener(new OpenMapListener)
|
||||
fichier.add(open)
|
||||
fichier.addSeparator()
|
||||
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.VK_CONTROL, true))
|
||||
save.addActionListener(this)
|
||||
fichier.add(save)
|
||||
saveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.VK_CONTROL + KeyEvent.VK_SHIFT, true))
|
||||
saveAs.addActionListener(this)
|
||||
fichier.add(saveAs)
|
||||
fichier.addSeparator()
|
||||
exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.VK_CONTROL, true))
|
||||
exit.addActionListener(this)
|
||||
fichier.add(exit)
|
||||
val bar: JMenuBar = new JMenuBar
|
||||
bar.add(fichier)
|
||||
pen.setSelected(true)
|
||||
pen.addActionListener(this)
|
||||
pot.addActionListener(this)
|
||||
group.add(pen)
|
||||
group.add(pot)
|
||||
val selectionMode = new JMenu("Mode de s\u00e9lection")
|
||||
selectionMode.add(pen)
|
||||
selectionMode.add(pot)
|
||||
val tools = new JMenu("Outils")
|
||||
tools.setMnemonic(KeyEvent.VK_O + KeyEvent.VK_ALT)
|
||||
tools.add(selectionMode)
|
||||
bar.add(tools)
|
||||
this.setJMenuBar(bar)
|
||||
mapPanel = new MapPanel(this)
|
||||
mapPanel.addMouseListener(new MapMouseListener(mapPanel, this))
|
||||
mapPanel.addMouseMotionListener(new MapMouseListener(mapPanel, this))
|
||||
tabColl = new CollidPanel(this)
|
||||
tabColl.addMouseListener(new CollidMapMouseListener(tabColl, this))
|
||||
tabColl.addMouseMotionListener(new CollidMapMouseListener(tabColl, this))
|
||||
val scrollMap = new JScrollPane(mapPanel)
|
||||
scrollMap.getHorizontalScrollBar.setUnitIncrement(34)
|
||||
scrollMap.getVerticalScrollBar.setUnitIncrement(34)
|
||||
val scrollCollidMap = new JScrollPane(tabColl)
|
||||
scrollCollidMap.getHorizontalScrollBar.setUnitIncrement(34)
|
||||
scrollCollidMap.getVerticalScrollBar.setUnitIncrement(34)
|
||||
tabs.addTab("Carte", scrollMap)
|
||||
val tabEvents = new JPanel
|
||||
tabs.addTab("\u00c9vennments", new JScrollPane(tabEvents))
|
||||
tabs.addTab("Collisions", scrollCollidMap)
|
||||
tabs.addChangeListener(this)
|
||||
content.add(tabs, BorderLayout.CENTER)
|
||||
couche1.setLayout(new WrapLayout(FlowLayout.LEFT))
|
||||
couche2.setLayout(new WrapLayout(FlowLayout.LEFT))
|
||||
couche3.setLayout(new WrapLayout(FlowLayout.LEFT))
|
||||
val scroll1 = new JScrollPane(couche1, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)
|
||||
val scroll2 = new JScrollPane(couche2, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)
|
||||
val scroll3 = new JScrollPane(couche3, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)
|
||||
scroll1.getHorizontalScrollBar.setMaximum(0)
|
||||
scroll2.getHorizontalScrollBar.setMaximum(0)
|
||||
scroll3.getHorizontalScrollBar.setMaximum(0)
|
||||
resources.addTab("", new ImageIcon(new File("assets/leveleditor/textures/layer 1.png").getAbsolutePath), scroll1)
|
||||
resources.addTab("", new ImageIcon(new File("assets/leveleditor/textures/layer 2.png").getAbsolutePath), scroll2)
|
||||
resources.addTab("", new ImageIcon(new File("assets/leveleditor/textures/layer 3.png").getAbsolutePath), scroll3)
|
||||
resources.addChangeListener(this)
|
||||
resources.setBackgroundAt(0, Color.white)
|
||||
resources.setBackgroundAt(1, Color.white)
|
||||
resources.setBackgroundAt(2, Color.white)
|
||||
content.add(resources, BorderLayout.EAST)
|
||||
resize()
|
||||
drawResources()
|
||||
revalidate()
|
||||
repaint()
|
||||
|
||||
private def drawResources(): Unit = {
|
||||
couche1.removeAll()
|
||||
couche2.removeAll()
|
||||
couche3.removeAll()
|
||||
if (couche1.getComponents.length > 0) return
|
||||
if (couche1.getWidth == 0 || couche2.getWidth == 0 || couche3.getWidth == 0) {
|
||||
couche1.repaint()
|
||||
couche2.repaint()
|
||||
couche3.repaint()
|
||||
}
|
||||
SpriteRegister.getAllCategories.foreach(cat => {
|
||||
cat.getSprites.foreach(spr => {
|
||||
val sprc1 = new SpriteComp(spr, 0)
|
||||
val sprc2 = new SpriteComp(spr, 1)
|
||||
val sprc3 = new SpriteComp(spr, 2)
|
||||
sprc1.addMouseListener(new SpriteMouseListener(sprc1, this))
|
||||
sprc2.addMouseListener(new SpriteMouseListener(sprc2, this))
|
||||
sprc3.addMouseListener(new SpriteMouseListener(sprc3, this))
|
||||
couche1.add(sprc1)
|
||||
couche2.add(sprc2)
|
||||
couche3.add(sprc3)
|
||||
})
|
||||
})
|
||||
couche1.revalidate()
|
||||
couche2.revalidate()
|
||||
couche3.revalidate()
|
||||
couche1.repaint()
|
||||
couche2.repaint()
|
||||
couche3.repaint()
|
||||
}
|
||||
|
||||
def resize(): Unit = {
|
||||
val cursorPos = resources.getSelectedComponent.asInstanceOf[JScrollPane].getVerticalScrollBar.getValue
|
||||
tabs.setPreferredSize(new Dimension(getWidth, getHeight / 5))
|
||||
tabs.setLocation(0, 0)
|
||||
val img = getMap.getFont
|
||||
val width = img.getWidth * 2
|
||||
val height = img.getHeight * 2
|
||||
mapPanel.setPreferredSize(new Dimension(width, height))
|
||||
mapPanel.setLocation(0, getHeight / 5)
|
||||
tabColl.setPreferredSize(new Dimension(width, height))
|
||||
tabColl.setLocation(0, getHeight / 5)
|
||||
resources.setPreferredSize(new Dimension(getWidth / 4 - 15, getHeight / 5 * 4 - 40))
|
||||
resources.setLocation(getWidth / 4 * 3, getHeight / 5)
|
||||
val scroll1 = resources.getComponent(0).asInstanceOf[JScrollPane]
|
||||
val scroll2 = resources.getComponent(1).asInstanceOf[JScrollPane]
|
||||
val scroll3 = resources.getComponent(2).asInstanceOf[JScrollPane]
|
||||
scroll1.getHorizontalScrollBar.setMaximum(0)
|
||||
scroll2.getHorizontalScrollBar.setMaximum(0)
|
||||
scroll3.getHorizontalScrollBar.setMaximum(0)
|
||||
drawResources()
|
||||
resources.getSelectedComponent.asInstanceOf[JScrollPane].getVerticalScrollBar.setValue(cursorPos)
|
||||
}
|
||||
|
||||
def getMap: GMap = map
|
||||
|
||||
def getSelectedSprite: SpriteComp = selectedSprite
|
||||
|
||||
def setSelectedSprite(sprite: SpriteComp): Unit = {
|
||||
this.selectedSprite = sprite
|
||||
}
|
||||
|
||||
override def stateChanged(event: ChangeEvent): Unit = {
|
||||
if (event.getSource eq resources) {
|
||||
if (getSelectedLayerIndex == 0) {
|
||||
resources.setBackgroundAt(0, Color.white)
|
||||
resources.setBackgroundAt(1, Color.white)
|
||||
resources.setBackgroundAt(2, Color.white)
|
||||
}
|
||||
else if (getSelectedLayerIndex == 1) {
|
||||
resources.setBackgroundAt(0, Color.black)
|
||||
resources.setBackgroundAt(1, Color.white)
|
||||
resources.setBackgroundAt(2, Color.white)
|
||||
}
|
||||
else if (getSelectedLayerIndex == 2) {
|
||||
resources.setBackgroundAt(0, Color.black)
|
||||
resources.setBackgroundAt(1, Color.black)
|
||||
resources.setBackgroundAt(2, Color.white)
|
||||
}
|
||||
repaint()
|
||||
}
|
||||
else if (event.getSource eq tabs) {
|
||||
resources.setEnabled(tabs.getSelectedIndex == 0)
|
||||
couche1.setEnabled(resources.isEnabled)
|
||||
couche2.setEnabled(resources.isEnabled)
|
||||
couche3.setEnabled(resources.isEnabled)
|
||||
repaint()
|
||||
}
|
||||
}
|
||||
|
||||
def getSelectedLayerIndex: Int = resources.getSelectedIndex
|
||||
|
||||
override def actionPerformed(event: ActionEvent): Unit = {
|
||||
if (event.getSource eq save) EditorAPI.save(RawMap.create(map))
|
||||
else if (event.getSource eq saveAs) EditorAPI.saveAs(RawMap.create(map))
|
||||
else if (event.getSource eq exit) {
|
||||
val result = JOptionPane.showConfirmDialog(null, "Voulez-vous sauvegarder votre carte avant de quitter ? Toute modification sera perdue", "Confirmation", JOptionPane.YES_NO_CANCEL_OPTION)
|
||||
if (result == 0) save.doClick()
|
||||
if (result != 2) dispose()
|
||||
}
|
||||
}
|
||||
|
||||
def getSelectedPaintingMode: Int = if (pen.isSelected) 0
|
||||
else if (pot.isSelected) 1
|
||||
else -1
|
||||
|
||||
override def windowActivated(event: WindowEvent): Unit = {
|
||||
}
|
||||
|
||||
override def windowClosed(event: WindowEvent): Unit = {
|
||||
}
|
||||
|
||||
override def windowClosing(event: WindowEvent): Unit = {
|
||||
val result = JOptionPane.showConfirmDialog(null, "Voulez-vous sauvegarder avant de quitter ?", "Confirmation", JOptionPane.YES_NO_CANCEL_OPTION)
|
||||
if (result == 0) EditorAPI.save(RawMap.create(map))
|
||||
if (result != 2) dispose()
|
||||
}
|
||||
|
||||
override def windowDeactivated(event: WindowEvent): Unit = {
|
||||
}
|
||||
|
||||
override def windowDeiconified(event: WindowEvent): Unit = {
|
||||
}
|
||||
|
||||
override def windowIconified(event: WindowEvent): Unit = {
|
||||
}
|
||||
|
||||
override def windowOpened(event: WindowEvent): Unit = {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package fr.ynerant.leveleditor.editor
|
||||
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister
|
||||
import fr.ynerant.leveleditor.api.editor.{Case, RawMap}
|
||||
|
||||
|
||||
object GMap {
|
||||
private var cases = Nil: List[Case]
|
||||
}
|
||||
|
||||
class GMap(val raw: RawMap) {
|
||||
final private var frame = null: EditorFrame
|
||||
final private var width = 0
|
||||
final private var height = 0
|
||||
private var casesMap = Map(): Map[Int, Map[Int, Case]]
|
||||
final private var font = null: BufferedImage
|
||||
|
||||
GMap.cases = Nil
|
||||
this.width = raw.getWidth
|
||||
this.height = raw.getHeight
|
||||
this.font = raw.getFont
|
||||
|
||||
raw.getCases.foreach(rc =>
|
||||
GMap.cases = Case.create(rc.getPosX, rc.getPosY, SpriteRegister.getCategory(rc.getCoucheOne.getCategory).getSprites(rc.getCoucheOne.getIndex), SpriteRegister.getCategory(rc.getCoucheTwo.getCategory).getSprites(rc.getCoucheTwo.getIndex), SpriteRegister.getCategory(rc.getCoucheThree.getCategory).getSprites(rc.getCoucheThree.getIndex), rc.getCollision) :: GMap.cases
|
||||
)
|
||||
|
||||
reorganizeMap()
|
||||
frame = new EditorFrame(this)
|
||||
getFrame.setVisible(true)
|
||||
|
||||
def getFrame: EditorFrame = frame
|
||||
|
||||
def getWidth: Int = width
|
||||
|
||||
def getHeight: Int = height
|
||||
|
||||
def getCase(x: Int, y: Int): Case = casesMap.getOrElse(x, Map()).getOrElse(y, null)
|
||||
|
||||
def getAllCases: List[Case] = {
|
||||
var list = Nil: List[Case]
|
||||
casesMap.values.foreach(l => list = list.appendedAll(l.values))
|
||||
list
|
||||
}
|
||||
|
||||
def getFont: BufferedImage = font
|
||||
|
||||
private def reorganizeMap(): Unit = {
|
||||
for (i <- 0 until width) {
|
||||
casesMap += (i -> Map())
|
||||
}
|
||||
GMap.cases.foreach(c => setCase(c.getPosX, c.getPosY, c))
|
||||
}
|
||||
|
||||
def setCase(x: Int, y: Int, c: Case): Unit = {
|
||||
var map = casesMap(x)
|
||||
map = map + (y -> c)
|
||||
casesMap = casesMap.updated(x, map)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package fr.ynerant.leveleditor.editor
|
||||
|
||||
import java.awt._
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
import javax.swing._
|
||||
|
||||
|
||||
@SerialVersionUID(2629019576253690557L)
|
||||
class MapPanel(val frame: EditorFrame) extends JPanel {
|
||||
override def paintComponent(g: Graphics): Unit = {
|
||||
g.fillRect(0, 0, getWidth, getHeight)
|
||||
val img = getMap.getFont
|
||||
val x = getWidth / 2 - img.getWidth
|
||||
val y = getHeight / 2 - img.getHeight
|
||||
val width = img.getWidth * 2
|
||||
val height = img.getHeight * 2
|
||||
g.drawImage(getMap.getFont, x, y, width, height, null)
|
||||
getMap.getAllCases.foreach(c => { // BufferedImage image;
|
||||
if (!isEmpty(c.getCoucheOne.getImage)) g.drawImage(c.getCoucheOne.getImage, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
if (!isEmpty(c.getCoucheTwo.getImage) && frame.getSelectedLayerIndex >= 1) g.drawImage(c.getCoucheTwo.getImage, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
if (!isEmpty(c.getCoucheThree.getImage) && frame.getSelectedLayerIndex == 2) g.drawImage(c.getCoucheThree.getImage, x + c.getPosX * 34 + 2, y + c.getPosY * 34 + 2, 32, 32, null)
|
||||
})
|
||||
}
|
||||
|
||||
def getMap: GMap = frame.getMap
|
||||
|
||||
@SuppressWarnings(Array("BooleanMethodIsAlwaysInverted")) private def isEmpty(image: BufferedImage) = {
|
||||
var allrgba = 0
|
||||
for (x <- 0 until image.getWidth) {
|
||||
for (y <- 0 until image.getHeight) {
|
||||
allrgba += image.getRGB(x, y) + 1
|
||||
}
|
||||
}
|
||||
allrgba == 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package fr.ynerant.leveleditor.editor
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.Sprite
|
||||
import javax.swing._
|
||||
import java.awt._
|
||||
|
||||
|
||||
@SerialVersionUID(-6512257366877053285L)
|
||||
class SpriteComp(val sprite: Sprite, val couche: Int) extends JComponent {
|
||||
this.setMinimumSize(new Dimension(32, 32))
|
||||
this.setMaximumSize(new Dimension(32, 32))
|
||||
this.setPreferredSize(new Dimension(32, 32))
|
||||
this.setSize(new Dimension(32, 32))
|
||||
repaint()
|
||||
private var selected = false
|
||||
|
||||
def getSprite: Sprite = sprite
|
||||
|
||||
def getCouche: Int = couche
|
||||
|
||||
def isSelected: Boolean = selected
|
||||
|
||||
def setSelected(selected: Boolean): Unit = {
|
||||
this.selected = selected
|
||||
}
|
||||
|
||||
override def paintComponent(g: Graphics): Unit = {
|
||||
super.paintComponent(g)
|
||||
g.setColor(Color.white)
|
||||
g.fillRect(0, 0, getWidth, getHeight)
|
||||
g.drawImage(sprite.getImage, 0, 0, 32, 32, Color.white, null)
|
||||
if (isSelected) {
|
||||
g.setColor(Color.black)
|
||||
g.drawLine(0, 0, getWidth - 1, 0)
|
||||
g.drawLine(0, 0, 0, getHeight - 1)
|
||||
g.drawLine(0, getHeight - 1, getWidth - 1, getHeight - 1)
|
||||
g.drawLine(getWidth - 1, 0, getWidth - 1, getHeight - 1)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package fr.ynerant.leveleditor.editor
|
||||
|
||||
import javax.swing._
|
||||
import java.awt._
|
||||
|
||||
|
||||
@SerialVersionUID(8777237960365591646L)
|
||||
class WrapLayout(val alignment: Int) extends FlowLayout(alignment) {
|
||||
override def preferredLayoutSize(target: Container): Dimension = layoutSize(target, preferred = true)
|
||||
|
||||
override def minimumLayoutSize(target: Container): Dimension = {
|
||||
val minimum = layoutSize(target, preferred = false)
|
||||
minimum.width -= (getHgap + 1)
|
||||
minimum
|
||||
}
|
||||
|
||||
private def layoutSize(target: Container, preferred: Boolean) = {
|
||||
var targetWidth = target.getSize.width
|
||||
if (targetWidth == 0) targetWidth = Integer.MAX_VALUE
|
||||
val hgap = getHgap
|
||||
val vgap = getVgap
|
||||
val insets = target.getInsets
|
||||
val horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2)
|
||||
val maxWidth = targetWidth - horizontalInsetsAndGap
|
||||
val dim = new Dimension(0, 0)
|
||||
var rowWidth = 0
|
||||
var rowHeight = 0
|
||||
val nmembers = target.getComponentCount
|
||||
for (i <- 0 until nmembers) {
|
||||
val m = target.getComponent(i)
|
||||
if (m.isVisible) {
|
||||
val d = if (preferred) m.getPreferredSize
|
||||
else m.getMinimumSize
|
||||
if (rowWidth + d.width > maxWidth) {
|
||||
addRow(dim, rowWidth, rowHeight)
|
||||
rowWidth = 0
|
||||
rowHeight = 0
|
||||
}
|
||||
if (rowWidth != 0) rowWidth += hgap
|
||||
rowWidth += d.width
|
||||
rowHeight = Math.max(rowHeight, d.height)
|
||||
}
|
||||
}
|
||||
addRow(dim, rowWidth, rowHeight)
|
||||
dim.width += horizontalInsetsAndGap
|
||||
dim.height += insets.top + insets.bottom + vgap * 2
|
||||
val scrollPane = SwingUtilities.getAncestorOfClass(classOf[JScrollPane], target)
|
||||
if (scrollPane != null) dim.width -= (hgap + 1)
|
||||
dim
|
||||
|
||||
}
|
||||
|
||||
private def addRow(dim: Dimension, rowWidth: Int, rowHeight: Int): Unit = {
|
||||
dim.width = Math.max(dim.width, rowWidth)
|
||||
if (dim.height > 0) dim.height += getVgap
|
||||
dim.height += rowHeight
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package fr.ynerant.leveleditor.frame
|
||||
|
||||
import fr.ynerant.leveleditor.frame.listeners.ChangeLAFListener
|
||||
import fr.ynerant.leveleditor.frame.listeners.CreateMapListener
|
||||
import fr.ynerant.leveleditor.frame.listeners.OpenMapListener
|
||||
import javax.swing._
|
||||
import java.awt._
|
||||
import java.awt.event.{ActionEvent, KeyEvent}
|
||||
|
||||
import fr.ynerant.leveleditor.client.main.Main
|
||||
|
||||
|
||||
/**
|
||||
* Fenêtre principale du jeu
|
||||
*
|
||||
* @author ÿnérant
|
||||
*/
|
||||
@SerialVersionUID(-3168760121879418534L)
|
||||
object MainFrame {
|
||||
/**
|
||||
* Instance unique principale
|
||||
*
|
||||
* @see #MainFrame()
|
||||
* @see #getInstance()
|
||||
*/
|
||||
private var INSTANCE = null: MainFrame
|
||||
|
||||
/**
|
||||
* Cet accesseur renvoie l'accesseur unique de la classe
|
||||
*
|
||||
* @return l'instance unique de la classe
|
||||
* @see #INSTANCE
|
||||
* @see #MainFrame()
|
||||
*/
|
||||
def getInstance: MainFrame = {
|
||||
if (INSTANCE == null) INSTANCE = new MainFrame
|
||||
INSTANCE
|
||||
}
|
||||
}
|
||||
|
||||
@SerialVersionUID(-3168760121879418534L)
|
||||
class MainFrame @SuppressWarnings(Array("JavadocReference")) private()
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
*
|
||||
* @see Main#launchFrame()
|
||||
*/
|
||||
extends JFrame {
|
||||
println("Initialisation de la fen\u00eatre")
|
||||
this.setTitle("Level Editor")
|
||||
this.setPreferredSize(new Dimension(1000, 800))
|
||||
this.setSize(800, 700)
|
||||
this.setLocationRelativeTo(null)
|
||||
this.setExtendedState(Frame.MAXIMIZED_BOTH)
|
||||
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
|
||||
val fichier = new JMenu("Fichier")
|
||||
fichier.setMnemonic(KeyEvent.VK_F + KeyEvent.VK_ALT)
|
||||
val display = new JMenu("Affichage")
|
||||
display.setMnemonic(KeyEvent.VK_A + KeyEvent.VK_ALT)
|
||||
val createMap = new JMenuItem("Cr\u00e9er")
|
||||
createMap.addActionListener(new CreateMapListener)
|
||||
val editMaps = new JMenu("Cartes")
|
||||
editMaps.add(createMap)
|
||||
val openMap = new JMenuItem("Ouvrir")
|
||||
openMap.addActionListener(new OpenMapListener)
|
||||
editMaps.add(openMap)
|
||||
fichier.add(editMaps)
|
||||
val systemLAF = new JMenuItem("Apparence syst\u00e8me")
|
||||
systemLAF.addActionListener(new ChangeLAFListener(systemLAF, this))
|
||||
val changeLAF = new JMenu("Modfier l'apparence")
|
||||
changeLAF.add(systemLAF)
|
||||
val javaLAF = new JMenuItem("Apparence Java")
|
||||
javaLAF.addActionListener(new ChangeLAFListener(javaLAF, this))
|
||||
changeLAF.add(javaLAF)
|
||||
val darkLAF = new JMenuItem("Apparence sombre")
|
||||
darkLAF.addActionListener(new ChangeLAFListener(darkLAF, this))
|
||||
changeLAF.add(darkLAF)
|
||||
display.add(changeLAF)
|
||||
val bar = new JMenuBar
|
||||
bar.add(fichier)
|
||||
bar.add(display)
|
||||
this.setJMenuBar(bar)
|
||||
val start = new JButton("Commencer la partie !")
|
||||
start.addActionListener((actionEvent: ActionEvent) => {
|
||||
if (Main.launchGameMode) MainFrame.getInstance.dispose()
|
||||
})
|
||||
this.setContentPane(start)
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners
|
||||
|
||||
import javax.swing._
|
||||
import java.awt.event.ActionEvent
|
||||
import java.awt.event.ActionListener
|
||||
|
||||
|
||||
class ChangeLAFListener(val item: JMenuItem, val frame: JFrame) extends ActionListener {
|
||||
override def actionPerformed(event: ActionEvent): Unit = {
|
||||
if (item.getText.toLowerCase.contains("sys")) {
|
||||
try UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName)
|
||||
catch {
|
||||
case e: Exception =>
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace()
|
||||
System.err.print("Caused by ")
|
||||
e.printStackTrace()
|
||||
}
|
||||
SwingUtilities.updateComponentTreeUI(frame)
|
||||
}
|
||||
else if (item.getText.toLowerCase.contains("java")) {
|
||||
try UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName)
|
||||
catch {
|
||||
case e: Exception =>
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace()
|
||||
System.err.print("Caused by ")
|
||||
e.printStackTrace()
|
||||
}
|
||||
SwingUtilities.updateComponentTreeUI(frame)
|
||||
}
|
||||
else if (item.getText.toLowerCase.contains("sombre")) {
|
||||
try UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel")
|
||||
catch {
|
||||
case e: Exception =>
|
||||
new ExceptionInInitializerError("Erreur lors du changement de 'look and feel'").printStackTrace()
|
||||
System.err.print("Caused by ")
|
||||
e.printStackTrace()
|
||||
}
|
||||
SwingUtilities.updateComponentTreeUI(frame)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners
|
||||
|
||||
import java.awt.event.{MouseAdapter, MouseEvent}
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.{Case, Collision}
|
||||
import fr.ynerant.leveleditor.editor.{CollidPanel, EditorFrame}
|
||||
|
||||
|
||||
class CollidMapMouseListener(val panel: CollidPanel, val frame: EditorFrame) extends MouseAdapter {
|
||||
def getFrame: EditorFrame = frame
|
||||
|
||||
override def mouseReleased(event: MouseEvent): Unit = {
|
||||
val map = getFrame.getMap
|
||||
val x = panel.getWidth / 2 - map.getFont.getWidth
|
||||
val y = panel.getHeight / 2 - map.getFont.getHeight
|
||||
val c = map.getCase((event.getX - x + 2) / 34, (event.getY - y + 2) / 34)
|
||||
if (c != null && event.getX - x >= 2 && event.getY - y >= 2) {
|
||||
val col = c.getCollision match {
|
||||
case Collision.ANY => Collision.PARTIAL
|
||||
case Collision.PARTIAL => Collision.FULL
|
||||
case Collision.FULL => Collision.ANY
|
||||
}
|
||||
val n = Case.create(c.getPosX, c.getPosY, c.getCoucheOne, c.getCoucheTwo, c.getCoucheThree, col)
|
||||
map.setCase((event.getX - x + 2) / 34, (event.getY - y + 2) / 34, n)
|
||||
panel.repaint()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners
|
||||
|
||||
import java.awt.event.ActionEvent
|
||||
import java.awt.event.ActionListener
|
||||
|
||||
import fr.ynerant.leveleditor.client.main.Main
|
||||
import fr.ynerant.leveleditor.frame.MainFrame
|
||||
|
||||
|
||||
/**
|
||||
* @author ÿnérant
|
||||
*/
|
||||
class CreateMapListener extends ActionListener {
|
||||
/* !CodeTemplates.overridecomment.nonjd!
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/ override def actionPerformed(event: ActionEvent): Unit = {
|
||||
if (Main.launchEditMode) MainFrame.getInstance.dispose()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners
|
||||
|
||||
import java.awt.event.{MouseAdapter, MouseEvent}
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.Case
|
||||
import fr.ynerant.leveleditor.editor.{EditorFrame, MapPanel}
|
||||
|
||||
|
||||
class MapMouseListener(val panel: MapPanel, val frame: EditorFrame) extends MouseAdapter {
|
||||
def getFrame: EditorFrame = frame
|
||||
|
||||
override def mouseClicked(event: MouseEvent): Unit = {
|
||||
if (frame.getSelectedPaintingMode == 0) {
|
||||
val map = getFrame.getMap
|
||||
val x = panel.getWidth / 2 - map.getFont.getWidth
|
||||
val y = panel.getHeight / 2 - map.getFont.getHeight
|
||||
val c = map.getCase((event.getX - x + 2) / 34, (event.getY - y + 2) / 34): Case
|
||||
if (c != null && event.getX - x >= 2 && event.getY - y >= 2) if (getFrame.getSelectedSprite != null) {
|
||||
var n = null: Case
|
||||
getFrame.getSelectedSprite.getCouche match {
|
||||
case 0 =>
|
||||
n = Case.create(c.getPosX, c.getPosY, getFrame.getSelectedSprite.getSprite, c.getCoucheTwo, c.getCoucheThree, c.getCollision)
|
||||
|
||||
case 1 =>
|
||||
n = Case.create(c.getPosX, c.getPosY, c.getCoucheOne, getFrame.getSelectedSprite.getSprite, c.getCoucheThree, c.getCollision)
|
||||
|
||||
case 2 =>
|
||||
n = Case.create(c.getPosX, c.getPosY, c.getCoucheOne, c.getCoucheTwo, getFrame.getSelectedSprite.getSprite, c.getCollision)
|
||||
|
||||
case _ =>
|
||||
n = c
|
||||
}
|
||||
map.setCase(n.getPosX, n.getPosY, n)
|
||||
panel.repaint()
|
||||
}
|
||||
}
|
||||
else if (frame.getSelectedPaintingMode == 1) {
|
||||
getFrame.getMap.getAllCases.foreach(c => {
|
||||
val map = getFrame.getMap
|
||||
if (getFrame.getSelectedSprite != null) {
|
||||
if (getFrame.getSelectedSprite.getCouche - 1 > getFrame.getSelectedLayerIndex) return
|
||||
var n = null: Case
|
||||
getFrame.getSelectedSprite.getCouche match {
|
||||
case 0 =>
|
||||
n = Case.create(c.getPosX, c.getPosY, getFrame.getSelectedSprite.getSprite, c.getCoucheTwo, c.getCoucheThree, c.getCollision)
|
||||
|
||||
case 1 =>
|
||||
n = Case.create(c.getPosX, c.getPosY, c.getCoucheOne, getFrame.getSelectedSprite.getSprite, c.getCoucheThree, c.getCollision)
|
||||
|
||||
case 2 =>
|
||||
n = Case.create(c.getPosX, c.getPosY, c.getCoucheOne, c.getCoucheTwo, getFrame.getSelectedSprite.getSprite, c.getCollision)
|
||||
|
||||
case _ =>
|
||||
n = c
|
||||
|
||||
}
|
||||
map.setCase(n.getPosX, n.getPosY, n)
|
||||
}
|
||||
})
|
||||
panel.repaint()
|
||||
}
|
||||
}
|
||||
|
||||
override def mouseDragged(event: MouseEvent): Unit = {
|
||||
if (frame.getSelectedPaintingMode == 0) mouseClicked(event)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners
|
||||
|
||||
import java.awt.event.ActionEvent
|
||||
import java.awt.event.ActionListener
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.EditorAPI
|
||||
import fr.ynerant.leveleditor.frame.MainFrame
|
||||
|
||||
|
||||
class OpenMapListener extends ActionListener {
|
||||
/* !CodeTemplates.overridecomment.nonjd!
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/ override def actionPerformed(event: ActionEvent): Unit = {
|
||||
if (EditorAPI.open != null) MainFrame.getInstance.dispose()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package fr.ynerant.leveleditor.frame.listeners
|
||||
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
|
||||
import fr.ynerant.leveleditor.editor.{EditorFrame, SpriteComp}
|
||||
|
||||
|
||||
class SpriteMouseListener(val sprite: SpriteComp, val frame: EditorFrame) extends MouseAdapter {
|
||||
override def mouseReleased(event: MouseEvent): Unit = {
|
||||
if (frame.getSelectedSprite != null) {
|
||||
frame.getSelectedSprite.setSelected(false)
|
||||
frame.getSelectedSprite.repaint()
|
||||
}
|
||||
frame.setSelectedSprite(sprite)
|
||||
sprite.setSelected(true)
|
||||
sprite.repaint()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
package fr.ynerant.leveleditor.game
|
||||
|
||||
import java.awt._
|
||||
import java.awt.event.{MouseEvent, MouseListener}
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister
|
||||
import fr.ynerant.leveleditor.api.editor.{Collision, RawMap}
|
||||
import fr.ynerant.leveleditor.editor.CollidPanel
|
||||
import fr.ynerant.leveleditor.game.mobs.Mob
|
||||
import fr.ynerant.leveleditor.game.towers._
|
||||
import javax.swing._
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.util.Random
|
||||
|
||||
|
||||
class GameFrame(val map: RawMap) extends JFrame("Jeu") {
|
||||
private var round = 0
|
||||
private var hp = 5
|
||||
private var reward = 20
|
||||
private var mobs = ListBuffer[Mob]()
|
||||
private var towers = ListBuffer[Tower]()
|
||||
private val pathFinder = PathFinder(this)
|
||||
final private var basicTower = null: JRadioButton
|
||||
final private var wallTower = null: JRadioButton
|
||||
final private var freezerTower = null: JRadioButton
|
||||
final private var explodeTower = null: JRadioButton
|
||||
final private var upgradeTower = null: JRadioButton
|
||||
final private var laserTower = null: JRadioButton
|
||||
final private var waveLabel = null: JLabel
|
||||
final private var nbMobsLabel = null: JLabel
|
||||
final private var hpLabel = null: JLabel
|
||||
final private var rewardLabel = null: JLabel
|
||||
final private var winLabel = null: JLabel
|
||||
|
||||
this.setSize(1000, 1000)
|
||||
this.setPreferredSize(getSize)
|
||||
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
|
||||
this.setExtendedState(Frame.MAXIMIZED_BOTH)
|
||||
this.setLocationRelativeTo(null)
|
||||
val root = new JPanel
|
||||
root.setLayout(new BorderLayout)
|
||||
this.setContentPane(root)
|
||||
val pane = new JPanel
|
||||
pane.setLayout(new GridLayout(8, 1))
|
||||
root.add(pane, BorderLayout.SOUTH)
|
||||
val grid = new Grid()
|
||||
grid.setSize(map.getWidth, map.getHeight)
|
||||
grid.setPreferredSize(grid.getSize)
|
||||
grid.setMinimumSize(grid.getSize)
|
||||
grid.setMaximumSize(grid.getSize)
|
||||
root.add(grid, BorderLayout.CENTER)
|
||||
val towerSelect = new ButtonGroup
|
||||
basicTower = new JRadioButton("Tour basique (" + new BasicTower(0, 0).getPrice + " pièces)")
|
||||
basicTower.setSelected(true)
|
||||
towerSelect.add(basicTower)
|
||||
pane.add(basicTower)
|
||||
wallTower = new JRadioButton("Tour-mur (" + new WallTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(wallTower)
|
||||
pane.add(wallTower)
|
||||
freezerTower = new JRadioButton("Tour froide (" + new FreezerTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(freezerTower)
|
||||
pane.add(freezerTower)
|
||||
explodeTower = new JRadioButton("Tour explosive (" + new ExploderTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(explodeTower)
|
||||
pane.add(explodeTower)
|
||||
upgradeTower = new JRadioButton("Tour d'amélioration (" + new UpgradeTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(upgradeTower)
|
||||
pane.add(upgradeTower)
|
||||
laserTower = new JRadioButton("Tour laser (" + new LaserTower(0, 0).getPrice + " pièces)")
|
||||
towerSelect.add(laserTower)
|
||||
pane.add(laserTower)
|
||||
waveLabel = new JLabel
|
||||
pane.add(waveLabel)
|
||||
nbMobsLabel = new JLabel
|
||||
pane.add(nbMobsLabel)
|
||||
hpLabel = new JLabel
|
||||
pane.add(hpLabel)
|
||||
rewardLabel = new JLabel
|
||||
pane.add(rewardLabel)
|
||||
winLabel = new JLabel
|
||||
pane.add(winLabel)
|
||||
setVisible(true)
|
||||
new Thread(() => {
|
||||
pathFinder.calculatePath()
|
||||
|
||||
while (hp > 0 && (round < 4 || mobs.nonEmpty)) {
|
||||
try
|
||||
tick()
|
||||
catch {
|
||||
case e: Throwable =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
try Thread.sleep(50L)
|
||||
catch {
|
||||
case e: InterruptedException =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}).start()
|
||||
repaint()
|
||||
|
||||
def getMap: RawMap = map
|
||||
|
||||
def getMobs: ListBuffer[Mob] = mobs
|
||||
|
||||
def getTowers: ListBuffer[Tower] = towers
|
||||
|
||||
def breakTower(tower: Tower): Unit = towers -= tower
|
||||
|
||||
def getPathFinder: PathFinder = pathFinder
|
||||
|
||||
def tick(): Unit = {
|
||||
if (mobs.isEmpty && round < 4) {
|
||||
round += 1
|
||||
val nb_mobs = round * (Random.nextInt(8) + 1)
|
||||
for (_ <- 1 to nb_mobs) {
|
||||
val mob = Mob.getRandomMob
|
||||
do mob.move(Random.nextInt(getMap.getWidth / 16), Random.nextInt(getMap.getHeight / 16)) while ( {
|
||||
!getMap.getCase(mob.getX, mob.getY).getCollision.equals(Collision.ANY)
|
||||
})
|
||||
getMap.getCase(mob.getX, mob.getY).setCollision(Collision.PARTIAL)
|
||||
mobs += mob
|
||||
}
|
||||
}
|
||||
towers.foreach(tower => tower.shot(this))
|
||||
mobs.foreach(mob => {
|
||||
getMap.getCase(mob.getX, mob.getY).setCollision(Collision.ANY)
|
||||
mob.tick(this)
|
||||
if (mob.getX < 0 || mob.isDead) {
|
||||
mobs -= mob
|
||||
if (mob.getX < 0) {
|
||||
hp -= 1
|
||||
if (hp == 0) {
|
||||
winLabel.setForeground(Color.red)
|
||||
winLabel.setText("Vous avez perdu !")
|
||||
return
|
||||
}
|
||||
}
|
||||
else reward += mob.getReward
|
||||
}
|
||||
else getMap.getCase(mob.getX, mob.getY).setCollision(Collision.PARTIAL)
|
||||
})
|
||||
waveLabel.setText("Vague " + round)
|
||||
nbMobsLabel.setText(mobs.size + " mob" + (if (mobs.size > 1) "s"
|
||||
else "") + " restant" + (if (mobs.size > 1) "s"
|
||||
else ""))
|
||||
hpLabel.setText("Points de vie : " + hp)
|
||||
rewardLabel.setText("Butin : " + reward)
|
||||
if (round == 4 && mobs.isEmpty) {
|
||||
winLabel.setForeground(Color.green.darker)
|
||||
winLabel.setText("Vous avez gagné !")
|
||||
}
|
||||
}
|
||||
|
||||
class Grid() extends JComponent with MouseListener {
|
||||
addMouseListener(this)
|
||||
|
||||
override def mouseReleased(event: MouseEvent): Unit = {
|
||||
val x = event.getX / 32
|
||||
val y = event.getY / 32
|
||||
val tower = if (basicTower.isSelected) new BasicTower(x, y)
|
||||
else if (wallTower.isSelected) new WallTower(x, y)
|
||||
else if (freezerTower.isSelected) new FreezerTower(x, y)
|
||||
else if (explodeTower.isSelected) new ExploderTower(x, y)
|
||||
else if (upgradeTower.isSelected) new UpgradeTower(x, y)
|
||||
else if (laserTower.isSelected) new LaserTower(x, y)
|
||||
else null
|
||||
if (tower == null || tower.getPrice > reward) return
|
||||
val c = getMap.getCase(x, y)
|
||||
if (c == null || !c.getCollision.equals(Collision.ANY)) return
|
||||
c.setCollision(Collision.FULL)
|
||||
|
||||
pathFinder.invalidate()
|
||||
|
||||
val accessible = getMap.getCases.filter(c => !Collision.FULL.equals(c.getCollision))
|
||||
if (accessible.exists(c => c.getPosX > 0 && pathFinder.nextPos(c.getPosX, c.getPosY) == null) || !accessible.exists(c => c.getPosX == 0 && !c.getCollision.equals(Collision.FULL))) {
|
||||
// We ensure that the end of the game is accessible from everywhere, the tower should not block the game
|
||||
c.setCollision(Collision.ANY)
|
||||
pathFinder.invalidate()
|
||||
}
|
||||
else {
|
||||
reward -= tower.getPrice
|
||||
towers += tower
|
||||
}
|
||||
}
|
||||
|
||||
override def mouseClicked(event: MouseEvent): Unit = {
|
||||
}
|
||||
|
||||
override def mousePressed(event: MouseEvent): Unit = {
|
||||
}
|
||||
|
||||
override protected def paintComponent(_g: Graphics): Unit = {
|
||||
val g = _g.asInstanceOf[Graphics2D]
|
||||
if (getMap.getFont != null) g.drawImage(getMap.getFont, null, null)
|
||||
SpriteRegister.refreshAllSprites()
|
||||
val SPRITE_SIZE = 32
|
||||
getMap.getCases.foreach(c => {
|
||||
val s1 = SpriteRegister.getCategory(c.getCoucheOne.getCategory).getSprites(c.getCoucheOne.getIndex)
|
||||
val s2 = SpriteRegister.getCategory(c.getCoucheTwo.getCategory).getSprites(c.getCoucheTwo.getIndex)
|
||||
val s3 = SpriteRegister.getCategory(c.getCoucheThree.getCategory).getSprites(c.getCoucheThree.getIndex)
|
||||
g.drawImage(s1.getImage, SPRITE_SIZE * c.getPosX, SPRITE_SIZE * c.getPosY, SPRITE_SIZE, SPRITE_SIZE, Color.white, null)
|
||||
if (!CollidPanel.isEmpty(s2.getImage)) g.drawImage(s2.getImage, SPRITE_SIZE * c.getPosX, SPRITE_SIZE * c.getPosY, SPRITE_SIZE, SPRITE_SIZE, null, null)
|
||||
if (!CollidPanel.isEmpty(s3.getImage)) g.drawImage(s3.getImage, SPRITE_SIZE * c.getPosX, SPRITE_SIZE * c.getPosY, SPRITE_SIZE, SPRITE_SIZE, null, null)
|
||||
})
|
||||
mobs.foreach(mob => {
|
||||
val s = mob.getSprite
|
||||
g.drawImage(s.getImage, SPRITE_SIZE * mob.getX, SPRITE_SIZE * mob.getY, SPRITE_SIZE, SPRITE_SIZE, null, null)
|
||||
})
|
||||
towers.foreach(tower => {
|
||||
val s = tower.getSprite
|
||||
g.drawImage(s.getImage, SPRITE_SIZE * tower.getX, SPRITE_SIZE * tower.getY, SPRITE_SIZE, SPRITE_SIZE, null, null)
|
||||
})
|
||||
repaint()
|
||||
}
|
||||
|
||||
override def mouseEntered(event: MouseEvent): Unit = {
|
||||
}
|
||||
|
||||
override def mouseExited(event: MouseEvent): Unit = {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package fr.ynerant.leveleditor.game
|
||||
|
||||
import java.util
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.{Collision, RawCase}
|
||||
|
||||
case class PathFinder(game: GameFrame) {
|
||||
var pred: Map[Int, RawCase] = Map(): Map[Int, RawCase]
|
||||
|
||||
def invalidate(): Unit = calculatePath()
|
||||
|
||||
def calculatePath(): Unit = {
|
||||
pred = Map()
|
||||
val queue = new util.ArrayDeque[RawCase]
|
||||
|
||||
for (i <- 0 until game.getMap.getHeight / 16) {
|
||||
val start = game.getMap.getCase(0, i)
|
||||
if (!start.getCollision.equals(Collision.FULL)) {
|
||||
pred += (coords(start) -> null)
|
||||
queue.add(start)
|
||||
}
|
||||
}
|
||||
|
||||
while (!queue.isEmpty) {
|
||||
val visiting = queue.poll
|
||||
game.getMap.getNeighbours(visiting).foreach(neighbour => {
|
||||
if (neighbour != null && !neighbour.collision.equals(Collision.FULL) && !pred.contains(coords(neighbour))) {
|
||||
pred += (coords(neighbour) -> visiting)
|
||||
queue.add(neighbour)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
def coords(rawCase: RawCase): Int = rawCase.getPosY * game.getMap.getWidth / 16 + rawCase.getPosX
|
||||
|
||||
def nextPos(x: Int, y: Int): RawCase = {
|
||||
pred.getOrElse(y * game.getMap.getWidth / 16 + x, null)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.RawCase
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.{Sprite, SpriteRegister}
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
object Mob {
|
||||
private val RANDOM = new Random
|
||||
|
||||
def getRandomMob: Mob = RANDOM.nextInt(6) match {
|
||||
case 0 =>
|
||||
new Mob1
|
||||
case 1 =>
|
||||
new Mob2
|
||||
case 2 =>
|
||||
new MobStrong
|
||||
case 3 =>
|
||||
new MobHealer
|
||||
case 4 =>
|
||||
new MobBreaker
|
||||
case 5 =>
|
||||
new MobSpeeder
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Mob() {
|
||||
private var hp = getMaxHP
|
||||
private var tickRemains = 0L
|
||||
private var sprite = null: Sprite
|
||||
private var x = 0
|
||||
private var y = 0
|
||||
private var freezeTime = 0
|
||||
private var speedMultiplier = 1
|
||||
|
||||
tickRemains = getSlowness
|
||||
|
||||
def getMaxHP: Int
|
||||
|
||||
def _getSlowness: Long
|
||||
|
||||
def getSlowness: Long = {
|
||||
(_getSlowness * Random.between(0.95, 1.05) * (if (freezeTime > 0) 2 else 1) / speedMultiplier).toLong
|
||||
}
|
||||
|
||||
def getReward: Int
|
||||
|
||||
def getName: String
|
||||
|
||||
def getSprite: Sprite = {
|
||||
if (sprite == null) sprite = SpriteRegister.getCategory(getName).getSprites.head
|
||||
sprite
|
||||
}
|
||||
|
||||
def getX: Int = x
|
||||
|
||||
def getY: Int = y
|
||||
|
||||
def move(x: Int, y: Int): Unit = {
|
||||
this.x = x
|
||||
this.y = y
|
||||
}
|
||||
|
||||
def freeze(time: Int): Unit = {
|
||||
if (freezeTime == 0)
|
||||
tickRemains *= 2
|
||||
freezeTime = time
|
||||
}
|
||||
|
||||
def speedup(multiplier: Int): Unit = speedMultiplier = multiplier
|
||||
|
||||
def heal(hp: Int): Unit = {
|
||||
this.hp = Math.min(hp + 1, getMaxHP)
|
||||
}
|
||||
|
||||
def getHP: Int = hp
|
||||
|
||||
def isDead: Boolean = hp <= 0
|
||||
|
||||
def setHP(hp: Int): Unit = {
|
||||
this.hp = hp
|
||||
}
|
||||
|
||||
def hit(damage: Int): Boolean = {
|
||||
if (!isDead) {
|
||||
this.hp -= damage
|
||||
return true
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* Called each game tick
|
||||
*/
|
||||
def tick(game: GameFrame): Unit = {
|
||||
if (freezeTime > 0)
|
||||
freezeTime -= 1
|
||||
|
||||
if (tickRemains > 0) tickRemains -= 1
|
||||
else {
|
||||
tickRemains = getSlowness
|
||||
val current = game.getMap.getCase(getX, getY)
|
||||
if (current.getPosX == 0) {
|
||||
move(-1, getY)
|
||||
return
|
||||
}
|
||||
|
||||
_tick(game)
|
||||
|
||||
val newCase: RawCase = game.getPathFinder.nextPos(getX, getY)
|
||||
move(newCase.getPosX, newCase.getPosY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom mobs override this function to do some custom stuff
|
||||
*/
|
||||
def _tick(game: GameFrame): Unit = ()
|
||||
|
||||
override def toString: String = "Mob{" + "sprite=" + sprite + ", x=" + x + ", y=" + y + '}'
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
class Mob1 extends Mob {
|
||||
override def getMaxHP = 2
|
||||
|
||||
override def _getSlowness = 50
|
||||
|
||||
override def getReward = 10
|
||||
|
||||
override def getName = "mob1"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
class Mob2 extends Mob {
|
||||
override def getMaxHP = 6
|
||||
|
||||
override def _getSlowness = 20
|
||||
|
||||
override def getReward = 20
|
||||
|
||||
override def getName = "mob2"
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class MobBreaker extends Mob {
|
||||
override def getMaxHP = 110
|
||||
|
||||
override def _getSlowness = 120
|
||||
|
||||
override def getReward = 70
|
||||
|
||||
override def getName = "mobhealer"
|
||||
|
||||
override def _tick(game: GameFrame): Unit = {
|
||||
game.getTowers.filter(tower => Math.abs(tower.getX - getX) + Math.abs(tower.getY - getY) <= 1).foreach(tower => game.breakTower(tower))
|
||||
game.getPathFinder.invalidate
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class MobHealer extends Mob {
|
||||
override def getMaxHP = 20
|
||||
|
||||
override def _getSlowness = 60
|
||||
|
||||
override def getReward = 20
|
||||
|
||||
override def getName = "mobhealer"
|
||||
|
||||
override def _tick(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9).foreach(mob => mob.heal(2))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class MobSpeeder extends Mob {
|
||||
override def getMaxHP = 25
|
||||
|
||||
override def _getSlowness = 60
|
||||
|
||||
override def getReward = 30
|
||||
|
||||
override def getName = "mobspeeder"
|
||||
|
||||
override def _tick(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9 && mob != this).foreach(mob => mob.speedup(3))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package fr.ynerant.leveleditor.game.mobs
|
||||
|
||||
class MobStrong extends Mob {
|
||||
override def getMaxHP = 50
|
||||
|
||||
override def _getSlowness = 100
|
||||
|
||||
override def getReward = 100
|
||||
|
||||
override def getName = "mobstrong"
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
class BasicTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "basictower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 3 else 1
|
||||
|
||||
override def getPeriod = 5
|
||||
|
||||
override def getPrice = 10
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
var l = game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9).toList
|
||||
l = Random.shuffle(l)
|
||||
if (l.nonEmpty)
|
||||
l.head.hit(getDamagePerShot)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
class ExploderTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "explodertower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 7 else 3
|
||||
|
||||
override def getPeriod = 20
|
||||
|
||||
override def getPrice = 70
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
var l = game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 25).toList
|
||||
l = Random.shuffle(l)
|
||||
if (l.nonEmpty) {
|
||||
val target = l.head
|
||||
target.hit(getDamagePerShot)
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - target.getX, 2) + Math.pow(mob.getX - target.getX, 2) <= 9)
|
||||
.foreach(mob => mob.hit(getDamagePerShot))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package fr.ynerant.leveleditor.game.towers;
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class FreezerTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "freezertower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 1 else 0
|
||||
|
||||
override def getPeriod = 10
|
||||
|
||||
override def getPrice = 40
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => Math.abs(mob.getX - getX) <= 3 && Math.abs(mob.getY - getY) <= 3).foreach(mob => {
|
||||
mob.freeze(if (isUpgraded) 100 else 40)
|
||||
mob.hit(getDamagePerShot)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class LaserTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "lasertower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 8 else 3
|
||||
|
||||
override def getPeriod = 40
|
||||
|
||||
override def getPrice = 80
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
game.getMobs.filter(mob => mob.getX == getX || mob.getY == getY).foreach(mob => mob.hit(getDamagePerShot))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.api.editor.sprites.{Sprite, SpriteRegister}
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
abstract class Tower(val x: Int, val y: Int) {
|
||||
final private val sprite = SpriteRegister.getCategory(getName).getSprites.head
|
||||
private var remainingTicks = 0L
|
||||
private var upgraded = false
|
||||
|
||||
def getSprite: Sprite = sprite
|
||||
|
||||
def getName: String
|
||||
|
||||
def getDamagePerShot: Int
|
||||
|
||||
def getPeriod: Long
|
||||
|
||||
def getPrice: Int
|
||||
|
||||
def upgrade: Unit = upgraded = true
|
||||
|
||||
def isUpgraded: Boolean = upgraded
|
||||
|
||||
def shot(game: GameFrame): Unit = if (remainingTicks > 0)
|
||||
remainingTicks -= 1
|
||||
else {
|
||||
remainingTicks = getPeriod
|
||||
_shot(game)
|
||||
}
|
||||
|
||||
private[towers] def _shot(game: GameFrame): Unit
|
||||
|
||||
def getX: Int = x
|
||||
|
||||
def getY: Int = y
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class UpgradeTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "upgradetower"
|
||||
|
||||
override def getDamagePerShot = if (isUpgraded) 1 else 0
|
||||
|
||||
override def getPeriod = 60
|
||||
|
||||
override def getPrice = 65
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = {
|
||||
game.getTowers.filter(tower => Math.pow(tower.getX - getX, 2) + Math.pow(tower.getY - getY, 2) <= 25 && tower != this).foreach(tower => tower.upgrade)
|
||||
if (isUpgraded)
|
||||
game.getMobs.filter(mob => Math.pow(mob.getX - getX, 2) + Math.pow(mob.getY - getY, 2) <= 9).foreach(mob => mob.hit(getDamagePerShot))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package fr.ynerant.leveleditor.game.towers
|
||||
|
||||
import fr.ynerant.leveleditor.game.GameFrame
|
||||
|
||||
class WallTower(override val x: Int, override val y: Int) extends Tower(x, y) {
|
||||
override def getName = "walltower"
|
||||
|
||||
override def getDamagePerShot: Int = Integer.MAX_VALUE
|
||||
|
||||
override def getPeriod = 1
|
||||
|
||||
override def getPrice = 5
|
||||
|
||||
override private[towers] def _shot(game: GameFrame): Unit = ()
|
||||
}
|