Compare commits

...

24 Commits
1.0 ... master

Author SHA1 Message Date
Yohann D'ANELLO 1347711d30 Readme 2020-05-29 23:51:54 +02:00
Yohann D'ANELLO def19e5750 Les mobs peuvent se déplacer en diagonale 2020-05-29 23:40:11 +02:00
Yohann D'ANELLO 7eb64985c7 Continuous moves 2020-05-26 18:40:15 +02:00
Yohann D'ANELLO 10fb067de2 Fix Java 8 2020-05-26 17:48:10 +02:00
galaxyoyo 787394ed76
Merge pull request #1 from galaxyoyo/scala
Scala
2020-05-26 16:58:49 +02:00
Yohann D'ANELLO 3e504310a9 Larger grid 2020-04-27 17:54:40 +02:00
Yohann D'ANELLO 500132a816 Use scala Random 2020-04-27 13:49:14 +02:00
Yohann D'ANELLO 3b474963a8 Fix some towers 2020-04-27 11:19:00 +02:00
Yohann D'ANELLO 6fe23277b3 PDF was missing 2020-04-10 20:45:51 +02:00
Yohann D'ANELLO 939698b21a Update Readme 2020-04-10 20:38:13 +02:00
Yohann D'ANELLO ca79095672 Add new mobs and new towers 2020-04-10 20:04:59 +02:00
Yohann D'ANELLO 37f0b663fc Fixed collisions in editor and sample map 2020-04-05 01:41:10 +02:00
Yohann D'ANELLO e50d485e4b Comments in build.sbt are useless 2020-04-05 01:16:47 +02:00
Yohann D'ANELLO 48eb15d57e Project can be launched through sbt run, project is now fully translated 2020-04-05 01:15:45 +02:00
Yohann D'ANELLO 8b745c068a Fix pathfinder, increase performance 2020-04-05 00:30:12 +02:00
Yohann D'ANELLO 3b55678835 Editor Map don't display 2020-04-04 22:22:20 +02:00
Yohann D'ANELLO 031815e055 Better Scala code 2020-04-04 21:56:14 +02:00
Yohann D'ANELLO 58509e0d5b Translated project in Scala (but the path finder seems to be broken) 2020-04-04 04:33:11 +02:00
Yohann D'ANELLO 40e0a92f9e Add libraries 2020-02-28 19:12:53 +01:00
Yohann D'ANELLO fb9902da44 Add compile script 2020-02-28 19:10:37 +01:00
Yohann D'ANELLO cf03a04786 Remove useless dependencies 2020-02-28 18:09:23 +01:00
Yohann D'ANELLO d607149097 Remove useless dependencies 2020-02-28 17:39:32 +01:00
Yohann D'ANELLO a6581cd37e Increase difficulty per wave 2020-02-28 17:14:30 +01:00
Yohann D'ANELLO 5517a10f56 Better packaging 2020-02-28 16:13:14 +01:00
94 changed files with 2291 additions and 2583 deletions

5
.gitignore vendored
View File

@ -19,4 +19,9 @@ img.png
image.png
/maps/
/assets/
lib/
out/
project/
target/
TheGame.jar

140
README.md
View File

@ -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,9 +43,125 @@ 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
Le projet est intégralement fait en Scala. On ne détaillera pas ici la partie éditeur de niveau, bien qu'elle soit
conséquente.
Une fois que l'utilisateur a choisi la carte à utilisateur via un menu de sélection, le jeu se lance dans une fenêtre
@ -67,10 +183,22 @@ 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.
### Déplacement dynamique
Le déplacement des mobs apparaît continu. Il n'est en rien dans le fond : la carte est discrétisée, et les mobs se
situent sur des coordonnées entières. La position affichée d'un mob est calculée selon sa case de départ, sa case
d'arrivée et le temps qu'il lui reste à attendre avant de pouvoir se déplacer. La vitesse varie alors selon les mobs.
### Déplacement en diagonale
Les mobs peuvent se déplacer en diagonale. Cela est comptabilisé comme un déplacement de coût 1 : la topologie de la
carte est alors un plan muni de la norme infinie. Ce n'est plus un simple parcours en largeur : à distance égale de
l'objectif, on préférera se déplacer de manière horizontale plutôt qu'en diagonale, de manière à avoir un déplacement
plus naturel.

Binary file not shown.

8
build.sbt Normal file
View File

@ -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"

Binary file not shown.

View File

@ -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";
}
}

View File

@ -1,5 +0,0 @@
package fr.ynerant.leveleditor.api.editor;
public enum Collision {
FULL, PARTIAL, ANY
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,4 +0,0 @@
/**
* @author ÿnérant
*/
package fr.ynerant.leveleditor.api.editor;

View File

@ -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;
}
}

View File

@ -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() + "}";
}
}

View File

@ -1,125 +0,0 @@
package fr.ynerant.leveleditor.api.editor.sprites;
import com.google.gson.Gson;
import fr.ynerant.leveleditor.client.main.Main;
import org.apache.logging.log4j.LogManager;
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) {
LogManager.getLogger("SpriteRegister").fatal("Erreur lors de la lecture du sprite '" + key + "'", t);
}
}
} 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());
}
}

View File

@ -1,237 +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 org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.layout.PatternLayout;
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&eacute; en d&eacute;veloppement ou non.
*
* @see #isInDevelopmentMode()
* @see #main(String...)
* @since 0.1-aplha
*/
private static boolean DEV;
/**
* @param args arguments du jeu. Possibilit&eacute;s :<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>--edit</strong> lancera un &eacute;diteur<br>&nbsp;&nbsp;&nbsp;&nbsp;<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;
}
Logger LOGGER = (Logger) LogManager.getRootLogger();
ConsoleAppender console = ConsoleAppender.newBuilder().setLayout(PatternLayout.newBuilder().withPattern("[%d{dd/MM/yyyy}] [%d{HH:mm:ss}] [%t] [%c] [%p] %m%n").build()).setName("Console").build();
console.start();
LOGGER.addAppender(console);
LOGGER.setLevel(Level.INFO);
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 !");
LogManager.getLogger("JAVAX-SWING").fatal("Cette application est un jeu, sans écran, elle aura du mal \u00e0 tourner ...");
LogManager.getLogger("JAVAX-SWING").catching(Level.FATAL, ex);
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&ecirc;tre principale
*
* @see #main(String...)
* @see #launchEditMode()
*/
private static void launchFrame() {
MainFrame.getInstance().setVisible(true);
}
/**
* Permet de lancer l'&eacute;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&eacute; en d&eacute;veloppement ou non.
*
* @see #DEV
* @since 0.1-alpha
*/
public static boolean isInDevelopmentMode() {
return DEV;
}
}

View File

@ -1,6 +0,0 @@
/**
* Ce package comprend uniquement la classe Main, qui lance l'application.
*
* @author ÿnérant
*/
package fr.ynerant.leveleditor.client.main;

View File

@ -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;
}
}

View File

@ -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) {
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -1,118 +0,0 @@
package fr.ynerant.leveleditor.frame;
import fr.ynerant.leveleditor.api.editor.EditorAPI;
import fr.ynerant.leveleditor.client.main.Main;
import fr.ynerant.leveleditor.editor.EditorFrame;
import fr.ynerant.leveleditor.frame.listeners.ChangeLAFListener;
import fr.ynerant.leveleditor.frame.listeners.CreateMapListener;
import fr.ynerant.leveleditor.frame.listeners.OpenMapListener;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
/**
* Fen&ecirc;tre principale du jeu
*
* @author ÿnérant
*/
public class MainFrame extends JFrame {
/**
* ID de s&eacute;rie
*/
private static final long serialVersionUID = -3168760121879418534L;
/**
* Instance unique principale
*
* @see #MainFrame()
* @see #getInstance()
*/
private static MainFrame INSTANCE;
/**
* Logger de la classe
*
* @see LogManager#getLogger(String)
*/
private static final Logger LOGGER = (Logger) LogManager.getLogger("MainFrame");
/**
* Constructeur
*
* @see Main#launchFrame()
*/
@SuppressWarnings("JavadocReference")
private MainFrame() {
super();
LOGGER.info("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(new ActionListener() {
@Override
public void actionPerformed(ActionEvent 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;
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -1,34 +0,0 @@
package fr.ynerant.leveleditor.game;
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;
}
}

View File

@ -1,44 +0,0 @@
package fr.ynerant.leveleditor.game;
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;
}
}

View File

@ -1,229 +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 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 List<Mob> mobs = new ArrayList<>();
private List<Tower> towers = new ArrayList<>();
private JRadioButton basicTower, nullTower, autoTower;
private JLabel waveLabel;
private JLabel nbMobsLabel;
private JLabel hpLabel;
private JLabel rewardLabel;
private 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;
for (int i = 1; i <= RANDOM.nextInt(16) + 1; ++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) {}
}
}

View File

@ -1,133 +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.sprites.Sprite;
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
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();
}
}
}

View File

@ -1,23 +0,0 @@
package fr.ynerant.leveleditor.game;
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";
}
}

View File

@ -1,23 +0,0 @@
package fr.ynerant.leveleditor.game;
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";
}
}

View File

@ -1,23 +0,0 @@
package fr.ynerant.leveleditor.game;
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";
}
}

View File

@ -1,35 +0,0 @@
package fr.ynerant.leveleditor.game;
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<>();
}
}

View File

@ -1,56 +0,0 @@
package fr.ynerant.leveleditor.game;
import fr.ynerant.leveleditor.api.editor.sprites.Sprite;
import fr.ynerant.leveleditor.api.editor.sprites.SpriteRegister;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
public abstract class Tower {
private 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;
}
}

View File

@ -1,3 +0,0 @@
Manifest-Version: 1.0
Main-Class: fr.ynerant.leveleditor.client.main.Main

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 760 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -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]
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration package="log4j.test" status="info">
<Loggers>
<Root level="info">
</Root>
</Loggers>
</Configuration>

View File

@ -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"
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,62 @@
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 ::= getCase(c.getPosX - 1, c.getPosY + 1)
list ::= getCase(c.getPosX - 1, c.getPosY - 1)
list ::= getCase(c.getPosX + 1, c.getPosY + 1)
list ::= getCase(c.getPosX + 1, c.getPosY - 1)
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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 + "}"
}

View File

@ -0,0 +1,112 @@
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
import scala.io.Source
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 = Source.fromFile(new File(f, "sprites.json")).mkString
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
}

View File

@ -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&eacute; en d&eacute;veloppement ou non.
*
* @see #isInDevelopmentMode()
* @see #main(String...)
* @since 0.1-aplha
*/
private var DEV = false
/**
* Accesseur disant si le jeu est lanc&eacute; en d&eacute;veloppement ou non.
*
* @see #DEV
* @since 0.1-alpha
*/
def isInDevelopmentMode: Boolean = DEV
/**
* @param args arguments du jeu. Possibilit&eacute;s :<br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>--edit</strong> lancera un &eacute;diteur<br>&nbsp;&nbsp;&nbsp;&nbsp;<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&ecirc;tre principale
*
* @see #main(String...)
* @see #launchEditMode()
*/
private def launchFrame(): Unit = {
MainFrame.getInstance.setVisible(true)
}
/**
* Permet de lancer l'&eacute;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
}
}

View File

@ -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
}

View File

@ -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 = {
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -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
}
}

View File

@ -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&ecirc;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)
}

View File

@ -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)
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -0,0 +1,242 @@
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
val nextCase = getPathFinder.nextPos(mob.getX, mob.getY)
var nextX = 0
var nextY = 0
if (nextCase != null) {
nextX = nextCase.getPosX
nextY = nextCase.getPosY
}
else {
nextX = mob.getX - 1
nextY = mob.getY
}
val progress = mob.progress
val newX = progress * mob.getX + (1 - progress) * nextX
val newY = progress * mob.getY + (1 - progress) * nextY
g.drawImage(s.getImage, (SPRITE_SIZE * newX).toInt, (SPRITE_SIZE * newY).toInt, 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 = {
}
}
}

View File

@ -0,0 +1,67 @@
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 queueactu = new util.ArrayDeque[RawCase]
val queuesuivdroit = new util.ArrayDeque[(RawCase, RawCase)]
val queuesuivdiag = new util.ArrayDeque[(RawCase, RawCase)]
var edges = List(): List[(RawCase, 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)
queueactu.add(start)
}
}
while (!queueactu.isEmpty) {
val visiting = queueactu.poll
game.getMap.getNeighbours(visiting).foreach(neighbour => {
if ((neighbour != null && !neighbour.collision.equals(Collision.FULL)) && !edges.contains(visiting, neighbour)
&& (!game.getMap.getCase(neighbour.getPosX, visiting.getPosY).collision.equals(Collision.FULL)
&& !game.getMap.getCase(visiting.getPosX, neighbour.getPosY).collision.equals(Collision.FULL))) {
edges ::= (visiting, neighbour)
if (visiting.getPosY == neighbour.getPosY || visiting.getPosX == neighbour.getPosX) {
queuesuivdroit.add((neighbour, visiting))
}
else {
queuesuivdiag.add((neighbour, visiting))
}
}
})
if (queueactu.isEmpty) {
while (!queuesuivdroit.isEmpty) {
val (actu, prev) = queuesuivdroit.poll
if (!pred.contains(coords(actu))) {
pred += (coords(actu) -> prev)
queueactu.add(actu)
}
}
while (!queuesuivdiag.isEmpty) {
val (actu, prev) = queuesuivdiag.poll
if (!pred.contains(coords(actu))) {
pred += (coords(actu) -> prev)
queueactu.add(actu)
}
}
}
}
}
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)
}
}

View File

@ -0,0 +1,129 @@
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 initialTicks = 0L
private var sprite = null: Sprite
private var x = 0
private var y = 0
private var freezeTime = 0
private var speedMultiplier = 1
initialTicks = getSlowness
tickRemains = initialTicks
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 progress: Float = tickRemains.toFloat / initialTicks.toFloat
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) {
initialTicks += tickRemains
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 {
initialTicks = getSlowness
tickRemains = initialTicks
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 + '}'
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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
}
}

View File

@ -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))
}
}

View File

@ -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))
}
}

View File

@ -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"
}

View File

@ -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)
}
}

View File

@ -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))
}
}
}

View File

@ -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)
})
}
}

View File

@ -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))
}
}

View File

@ -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
}

View File

@ -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))
}
}

View File

@ -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 = ()
}

View File

@ -1,33 +0,0 @@
package fr.ynerant.leveleditor;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest extends TestCase {
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(AppTest.class);
}
/**
* Rigourous Test :-)
*/
public void testApp() {
assertTrue(true);
}
}