Commit 8db9d670 authored by Lucas Delcros's avatar Lucas Delcros

Changed corridor surface generation system (more simple)

Changed check that every room is reachable by creating a much easier and quicker function in RoomTree
Added Obsidian as a ground tile in boss room (just for fun)
parent 0bfba283
......@@ -33,6 +33,7 @@ public class TileSpriteLinker
spriteMap.put(TileType.WATER , new GroundTileSprite(SpriteLoader.getSpriteFromPath("/assets/Lava.png").getSpriteImage()));
spriteMap.put(TileType.TORCH , new GroundTileSprite(SpriteLoader.getSpriteFromPath("/assets/Torch.png").getSpriteImage()));
spriteMap.put(TileType.CHEST , new GroundTileSprite(SpriteLoader.getSpriteFromPath("/assets/chest.png").getSpriteImage()));
spriteMap.put(TileType.OBSIDIAN , new GroundTileSprite(SpriteLoader.getSpriteFromPath("/assets/obsidian.png").getSpriteImage()));
}
public Displayable[][] getSpriteOfTile(TileType type, TileSprite.TileAbstractType[][] mask)
......
package map_generation.map;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import map_generation.tiles.Tile;
import map_generation.tiles.TileType;
......@@ -99,54 +96,6 @@ public class Map implements Serializable {
return map[x][y];
}
public boolean check() {
// Application of a BFS to find the number of different surfaces in the map. If the map is correct it should be 1.
int nb=0;
boolean bb=true;
boolean[][] mask=new boolean[height][width];
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
if(map[i][j].getType()==TileType.GROUND || map[i][j].getType()==TileType.STAIRS) mask[i][j]=true;
else mask[i][j]=false;
}
}
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
if(mask[i][j]) {
nb++;
List<MapPoint> l=new ArrayList<>();
MapPoint element=new MapPoint(i,j);
l.add(element);
mask[i][j]=false;
while(l.size()>0) {
List<MapPoint> l1=new ArrayList<>();
for(int k=0;k<l.size();k++) {
int ii=l.get(k).getI();
int jj=l.get(k).getJ();
if(ii>0 && mask[ii-1][jj]) {l1.add(new MapPoint(ii-1,jj));mask[ii-1][jj]=false;}
if(ii<height-1 && mask[ii+1][jj]) {l1.add(new MapPoint(ii+1,jj));mask[ii+1][jj]=false;}
if(jj>0 && mask[ii][jj-1]) {l1.add(new MapPoint(ii,jj-1));mask[ii][jj-1]=false;}
if(jj<width-1 && mask[ii][jj+1]) {l1.add(new MapPoint(ii,jj+1));mask[ii][jj+1]=false;}
}
l.clear();
for(int k=0;k<l1.size();k++) l.add(l1.get(k));
}
}
}
}
if(nb!=1) bb=false;
for(int i=0;i<corridors.length;i++) {
for(int j=0;j<corridors.length;j++) {
if(i!=j) {
if(SurfacesMapGeneration.distanceBetweenTwoSurface(corridors[i],corridors[j])<1) {
bb=false;
}
}
}
}
return(bb);
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
......@@ -166,43 +115,4 @@ public class Map implements Serializable {
public Entity[] getEntities() {
return(entities);
}
public void addSomeCorridors() {
int nbRooms=rooms.length;
Random r=new Random();
int probability=5;
for(int i=0;i<nbRooms-1;i++) {
for(int j=i+1;j<nbRooms;j++) {
Surface corridors=SurfacesMapGeneration.creationCorridor(rooms[i], rooms[j]);
if(testCorridorAddPossibility(corridors,i,j)) {
if(r.nextInt(probability)==0) addCorridors(corridors);
}
}
}
}
private void addCorridors(Surface corridors) {
boolean bb=true;
if(!corridors.checkSurface()) bb=false;
if(bb) {
Surface[] corridorsTemp=this.corridors;
this.corridors=new Surface[corridorsTemp.length+1];
for(int i=0;i<corridorsTemp.length;i++) {
this.corridors[i]=corridorsTemp[i];
}
this.corridors[corridorsTemp.length]=corridors;
for(int i=corridors.i1;i<corridors.i2;i++) {
for(int j=corridors.j1;j<corridors.j2;j++) {
map[j][i]=new Tile(TileType.GROUND,TileType.GROUND.getTilePropertyVector());
}
}
}
}
private boolean testCorridorAddPossibility(Surface corridor,int room1,int room2) {
boolean bb=true;
for(int i=0;i<rooms.length;i++) if(i!=room1 && i!=room2 && intersection(rooms[i],corridor)) bb=false;
for(int i=0;i<this.corridors.length;i++) if(intersection(this.corridors[i],corridor)) bb=false;
return(bb);
}
private static boolean intersection(Surface surface1, Surface surface2) {
return (surface1.i1>surface2.i2+1 || surface2.i1>surface1.i2+1 || surface1.j1>surface2.j2+1 || surface2.j1>surface1.j2+1)?false:true;
}
}
......@@ -94,6 +94,7 @@ public final class MapBuilder implements Serializable{
public Map build(){
generateChestRooms();
generateEndRoom();
if (!roomTree.everyRoomIsReachable()) return null;
TileBuilder[][] map = SurfacesMapGeneration.emptyTiles(height, width);
int nbRooms=rooms.size();
Random r=new Random();
......@@ -106,12 +107,12 @@ public final class MapBuilder implements Serializable{
surface.surroundWith(map, TileType.WALL);
}
//rooms.get(3).setType(RoomType.START);
for (RoomBuilder room : rooms) {
room.build(map, this);
}
for (Surface corridor : corridors) {
corridor.fillSurfaceWith(map, TileType.GROUND);
}
for (RoomBuilder room : rooms) {
room.build(map, this);
}
Surface[] rooms = new Surface[this.rooms.size()];
for (int i = 0; i < rooms.length; i++) {
......
......@@ -15,7 +15,7 @@ public class MapGeneration implements Serializable {
while(bb) {
//nbCheck++;
map = SurfacesMapGeneration.roomsRandomGeneration(meanRoomSize,numberOfRooms);
if (map.check()) bb=false;
if (map != null ) bb=false;
}
//System.out.println("NbCheck : "+nbCheck);
//map.addSomeCorridors();
......
......@@ -40,9 +40,8 @@ public final class RoomBuilder {
}
private void addStairs(TileBuilder[][] map, MapBuilder mapB){
Random r = new Random();
int posY=r.nextInt(surface.j2-surface.j1+1)+surface.j1;
int posX=r.nextInt(surface.i2-surface.i1+1)+surface.i1;
int posY=(surface.j1+surface.j2)/2;
int posX=(surface.i1+surface.i2)/2;
map[posY][posX].setType(TileType.STAIRS);
mapB.setStairPosition(new MapPoint(posY, posX));
}
......@@ -57,7 +56,7 @@ public final class RoomBuilder {
Random r = new Random();
if(type == RoomType.NORMAL && r.nextDouble() <= p){
double pp = r.nextDouble();
if( pp <= 0.5 )setType(RoomType.FULL_LAVA);
if( pp <= 0.7 )setType(RoomType.FULL_LAVA);
else setType(RoomType.TORCHES);
}
}
......@@ -92,6 +91,7 @@ public final class RoomBuilder {
mapB.setPositionPlayerAtStart(new MapPoint(posY, posX));
break;
case END:
surface.fillSurfaceWith(map, TileType.OBSIDIAN);
addStairs(map, mapB);
mapB.addEntity(SpeciesArray.create(((surface.j1+surface.j2)/2)*Point.TileScale,((surface.i1+surface.i2)/2)*Point.TileScale,100,"Diagla","Monster "+mapB.getMaxEntities()+1));
break;
......
......@@ -50,12 +50,28 @@ public class RoomGraph {
public RoomBuilder getMostFarNode(){
buildLength();
RoomNode max = start;
for (RoomBuilder room : rooms.keySet()) {
for (RoomBuilder room : getDeadEnds()) {
RoomNode temp = rooms.get(room);
if (temp.ltostart > max.ltostart) max = temp;
}
return max.room;
}
private boolean roomIsReachablefrom(RoomBuilder room, RoomNode from){
if(from.room == room) return true;
if(from.voisins == null) return false;
for (RoomNode voisin : from.voisins) {
if(voisin.ltostart > from.ltostart){
if(roomIsReachablefrom(room, voisin)) return true;
}
}
return false;
}
public boolean everyRoomIsReachable(){
for(RoomBuilder room : rooms.keySet()){
if(!roomIsReachablefrom(room, start)) return false;
}
return true;
}
private boolean isDeadEnd(RoomBuilder room){
RoomNode node = rooms.get(room);
if (node.voisins == null) return true;
......
......@@ -39,36 +39,34 @@ public class SurfacesMapGeneration implements Serializable{
int dX=Math.max(surface1.i1-surface2.i2+2,0)+Math.max(surface2.i1-surface1.i2+2,0);
return (dY>0 && dX>0)?dX+dY+4:dX+dY; // There's an extra to the distance between rooms that aren't facing each other horizontally or vertically (to avoid corridors with corners in the MST when possible)
}
/**
*
* @param a1
* @param b1
* @param a2
* @param b2
* @return [a1,b1] INTER [a2, b2]
*/
private static int[] getInter(int a1, int b1, int a2, int b2){
int[] res ={Math.max(a1, a2), Math.min(b1, b2)};
return res;
}
public static Surface creationCorridor(Surface room1,Surface room2) {
// This method creates a corridor between two rooms
int dNorth=Math.max(room2.j1-room1.j2-1,0);
int dY=Math.max(room2.j1-room1.j2+1,0)+Math.max(room1.j1-room2.j2+1,0);
int dX=Math.max(room2.i1-room1.i2+1,0)+Math.max(room1.i1-room2.i2+1,0);
if (dX==0) {
// Case where the rooms are facing each other vertically
int xTarget=(Math.max(room1.i1,room2.i1)+Math.min(room1.i2,room2.i2))/2;
int yTop=Math.min(room1.j2,room2.j2);
int yBottom=Math.max(room1.j1,room2.j1);
return new Surface(xTarget, yTop, xTarget+1, yBottom);
}
else if (dY==0) {
// Case where the rooms are facing each other vertically
int yTarget=(Math.max(room1.j1,room2.j1)+Math.min(room1.j2,room2.j2))/2;
int xLeft=Math.min(room1.i2,room2.i2);
int xRight=Math.max(room1.i1,room2.i1);
return new Surface(xLeft, yTarget, xRight, yTarget+1);
int[] interJ = getInter(room1.j1, room1.j2, room2.j1, room2.j2);
int w = interJ[1]-interJ[0] + 1;
if(w>=2){
return new Surface(Math.min(room1.i2, room2.i2)-1, interJ[0], Math.max(room1.i1, room2.i1)+1, interJ[0]+1);
}
else {
int xTarget=-1;
int yTarget=-1;
xTarget=(room1.i1+room1.i2)/2;
yTarget=(room2.j1+room2.j2)/2;
if(dNorth>0)return new Surface(xTarget, room1.j2, xTarget+1, yTarget);
return new Surface(xTarget, room2.j2+1, xTarget+1, yTarget);
int[] interI = getInter(room1.i1, room1.i2, room2.i1, room2.i2);
w = interI[1]-interI[0] + 1;
if(w>=2){
return new Surface(interI[0], Math.min(room1.j2, room2.j2)-1, interI[0]+1, Math.max(room1.j1, room2.j1)+1);
}
return null;
}
private static void addCorridorsByMST(RoomBuilder[] rooms, MapBuilder map) {
// Considering the graph made by the rooms with edges corresponding to the distance between any two of them
// I find the MST (Math.minimum SpamMath.ming Tree) of this graph in order to create a first set of corridors that connects all the rooms
......@@ -80,8 +78,8 @@ public class SurfacesMapGeneration implements Serializable{
distance[i][j]=d;
distance[j][i]=d;
if(d<12) { // If we find two rooms with a small distance in between, we add a corridor anyway, independantly of the MST
Surface corridorsToAdd=creationCorridor(rooms[i].getSurface(),rooms[j].getSurface());
map.addCorridor(corridorsToAdd, rooms[i], rooms[j]);
Surface corridorsToAdd=creationCorridor(rooms[i].getSurface(),rooms[j].getSurface());
if(corridorsToAdd != null)map.addCorridor(corridorsToAdd, rooms[i], rooms[j]);
}
}
}
......@@ -106,8 +104,8 @@ public class SurfacesMapGeneration implements Serializable{
}
used[node2]=true;
nbConnected++;
Surface corridorsToAdd=creationCorridor(rooms[node1].getSurface(),rooms[node2].getSurface());
map.addCorridor(corridorsToAdd, rooms[node1], rooms[node2]);
Surface corridorsToAdd=creationCorridor(rooms[node1].getSurface(),rooms[node2].getSurface());
if (corridorsToAdd != null)map.addCorridor(corridorsToAdd, rooms[node1], rooms[node2]);
}
}
......
package map_generation.tests;
import map_generation.map.Map;
import map_generation.map.SurfacesMapGeneration;
import map_generation.map.MapGeneration;
/**
* A simple console test
......@@ -10,7 +10,7 @@ import map_generation.map.SurfacesMapGeneration;
public class MapGenerationTestMain {
public static void main(String[] args) {
long a = System.currentTimeMillis();
Map map = SurfacesMapGeneration.roomsRandomGeneration(10,10);
Map map = MapGeneration.mapGeneration(10, 5);
System.out.println("map was generated in "+(System.currentTimeMillis()-a)+" ms");
// Map map = (new MapBuilder(0)).buildTwoRoomsMap();
for (int i = 0; i < map.getHeight(); i++) {
......@@ -25,6 +25,12 @@ public class MapGenerationTestMain {
break;
case WATER: s = "L";
break;
case TORCH: s = "T";
break;
case OBSIDIAN: s = "O";
break;
case CHEST: s = "C";
break;
default: s = "#";
break;
}
......
package map_generation.tests;
import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import map_generation.map.Map;
import map_generation.map.MapGeneration;
import map_generation.map.SurfacesMapGeneration;
import map_generation.tiles.TileType;
import org.junit.Test;
......@@ -15,23 +15,17 @@ import core.zone.Point;
public class MapTests {
@Test
public void testEveryRoomIsReachable() {
Map map = SurfacesMapGeneration.roomsRandomGeneration(20, 500);
assertTrue("Some rooms are not reachable !", map.check());
}
@Test
public void testNoEntitiesOnWater(){
Map map = SurfacesMapGeneration.roomsRandomGeneration(20, 500);
public void testNoRonflexOnWater(){
Map map = MapGeneration.mapGeneration(20, 100);
for(Entity entity : map.getEntities()){
Point pt = Point.construct(entity.getX(), entity.getY());
assertFalse("An entity has spawn on water !",map.getTileAt(pt.toMapPoint()).getType() == TileType.WATER);
if(entity.getName().equals("Ronflex"))assertFalse("An entity has spawn on water !",map.getTileAt(pt.toMapPoint()).getType() == TileType.WATER);
}
}
@Test
public void testMapHasStartEnd(){
Map map = SurfacesMapGeneration.roomsRandomGeneration(20, 500);
Map map = MapGeneration.mapGeneration(20, 100);
assertFalse("The Map doesn't cointains any stairs !", map.getPositionStairs() == null && map.getPositionPlayerStart() == null);
}
......
......@@ -8,7 +8,7 @@ import map_generation.tiles.TilePropertyVector.TileProperty;
*
*/
public enum TileType{
EMPTY, GROUND, WALL, STAIRS, WATER, TORCH, CHEST;
EMPTY, GROUND, WALL, STAIRS, WATER, TORCH, CHEST, OBSIDIAN;
private TilePropertyVector tpv;
private String shortName;
......@@ -28,6 +28,8 @@ public enum TileType{
TORCH.shortName="T";
CHEST.tpv=new TilePropertyVector().addProperty(TileProperty.IMPASSABLE);
CHEST.shortName="C";
OBSIDIAN.tpv=new TilePropertyVector().addProperty(TileProperty.SOLID);
OBSIDIAN.shortName="O";
}
public TilePropertyVector getTilePropertyVector(){
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment