v0.6.0: rewrote perimeter rooms

This commit is contained in:
Evan Debenham 2017-05-04 21:36:12 -04:00
parent af90cb7f73
commit 8c30dad29f
2 changed files with 132 additions and 71 deletions

View File

@ -73,6 +73,30 @@ public abstract class Painter {
fill( level, rect.left + l, rect.top + t, rect.width() - (l + r), rect.height() - (t + b), value );
}
public static void drawLine( Level level, Point from, Point to, int value){
float x = from.x;
float y = from.y;
float dx = to.x - from.x;
float dy = to.y - from.y;
boolean movingbyX = Math.abs(dx) >= Math.abs(dy);
//normalize
if (movingbyX){
dy /= Math.abs(dx);
dx /= Math.abs(dx);
} else {
dx /= Math.abs(dy);
dy /= Math.abs(dy);
}
set(level, Math.round(x), Math.round(y), value);
while((movingbyX && to.x != x) || (!movingbyX && to.y != y)){
x += dx;
y += dy;
set(level, Math.round(x), Math.round(y), value);
}
}
public static Point drawInside( Level level, Room room, Point from, int n, int value ) {
Point step = new Point();

View File

@ -23,101 +23,138 @@ package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.connection;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.watabou.utils.Point;
import java.util.ArrayList;
import java.util.Collections;
//tunnels along the room's perimeter
//FIXME should be refactored, like shop rooms (which use perimiter logic for item placement)
public class PerimeterRoom extends ConnectionRoom {
private static int pasWidth;
private static int pasHeight;
public void paint( Level level ) {
pasWidth = width() - 3;
pasHeight = height() - 3;
int floor = level.tunnelTile();
ArrayList<Integer> joints = new ArrayList<Integer>();
ArrayList<Point> pointsToFill = new ArrayList<>();
for (Point door : connected.values()) {
joints.add( xy2p( this, door ) );
}
Collections.sort( joints );
int nJoints = joints.size();
int perimeter = pasWidth * 2 + pasHeight * 2;
int start = 0;
int maxD = joints.get( 0 ) + perimeter - joints.get( nJoints - 1 );
for (int i=1; i < nJoints; i++) {
int d = joints.get( i ) - joints.get( i - 1 );
if (d > maxD) {
maxD = d;
start = i;
Point p = new Point(door);
if (p.y == top){
p.y++;
} else if (p.y == bottom) {
p.y--;
} else if (p.x == left){
p.x++;
} else {
p.x--;
}
pointsToFill.add( p );
}
int end = (start + nJoints - 1) % nJoints;
ArrayList<Point> pointsFilled = new ArrayList<>();
pointsFilled.add(pointsToFill.remove(0));
int p = joints.get( start );
do {
Painter.set( level, p2xy( this, p ), floor );
p = (p + 1) % perimeter;
} while (p != joints.get( end ));
Painter.set( level, p2xy( this, p ), floor );
Point from = null, to = null;
int shortestDistance;
while(!pointsToFill.isEmpty()){
shortestDistance = Integer.MAX_VALUE;
for (Point f : pointsFilled){
for (Point t : pointsToFill){
int dist = distanceBetweenPoints(f, t);
if (dist < shortestDistance){
from = f;
to = t;
shortestDistance = dist;
}
}
}
fillBetweenPoints(level, from, to, floor);
pointsFilled.add(to);
pointsToFill.remove(to);
}
for (Door door : connected.values()) {
door.set( Door.Type.TUNNEL );
}
}
private static int xy2p( Room room, Point xy ) {
if (xy.y == room.top) {
return (xy.x - room.left - 1);
} else if (xy.x == room.right) {
return (xy.y - room.top - 1) + pasWidth;
} else if (xy.y == room.bottom) {
return (room.right - xy.x - 1) + pasWidth + pasHeight;
} else {
if (xy.y == room.top + 1) {
return 0;
} else {
return (room.bottom - xy.y - 1) + pasWidth * 2 + pasHeight;
}
}
private int spaceBetween(int a, int b){
return Math.abs(a - b)-1;
}
private static Point p2xy( Room room, int p ) {
if (p < pasWidth) {
return new Point( room.left + 1 + p, room.top + 1);
} else if (p < pasWidth + pasHeight) {
return new Point( room.right - 1, room.top + 1 + (p - pasWidth) );
} else if (p < pasWidth * 2 + pasHeight) {
return new Point( room.right - 1 - (p - (pasWidth + pasHeight)), room.bottom - 1 );
} else {
return new Point( room.left + 1, room.bottom - 1 - (p - (pasWidth * 2 + pasHeight)) );
//gets the path distance between two points
private int distanceBetweenPoints(Point a, Point b){
//on the same side
if (a.y == b.y || a.x == b.x){
return Math.max(spaceBetween(a.x, b.x), spaceBetween(a.y, b.y));
}
//otherwise...
//subtract 1 at the end to account for overlap
return
Math.min(spaceBetween(left, a.x) + spaceBetween(left, b.x),
spaceBetween(right, a.x) + spaceBetween(right, b.x))
+
Math.min(spaceBetween(top, a.y) + spaceBetween(top, b.y),
spaceBetween(bottom, a.y) + spaceBetween(bottom, b.y))
-
1;
}
private Point[] corners;
//picks the smallest path to fill between two points
private void fillBetweenPoints(Level level, Point from, Point to, int floor){
//doors are along the same side
if (from.y == to.y || from.x == to.x){
Painter.fill(level,
Math.min(from.x, to.x),
Math.min(from.y, to.y),
spaceBetween(from.x, to.x) + 2,
spaceBetween(from.y, to.y) + 2,
floor);
return;
}
//set up corners
if (corners == null){
corners = new Point[4];
corners[0] = new Point(left+1, top+1);
corners[1] = new Point(right-1, top+1);
corners[2] = new Point(right-1, bottom-1);
corners[3] = new Point(left+1, bottom-1);
}
//doors on adjacent sides
for (Point c : corners){
if ((c.x == from.x || c.y == from.y) && (c.x == to.x || c.y == to.y)){
Painter.drawLine(level, from, c, floor);
Painter.drawLine(level, c, to, floor);
return;
}
}
//doors on opposite sides
Point side;
if (from.y == top+1 || from.y == bottom-1){
//connect along the left, or right side
if (spaceBetween(left, from.x) + spaceBetween(left, to.x) <=
spaceBetween(right, from.x) + spaceBetween(right, to.x)){
side = new Point(left+1, top + height()/2);
} else {
side = new Point(right-1, top + height()/2);
}
} else {
//connect along the top, or bottom side
if (spaceBetween(top, from.y) + spaceBetween(top, to.y) <=
spaceBetween(bottom, from.y) + spaceBetween(bottom, to.y)){
side = new Point(left + width()/2, top+1);
} else {
side = new Point(left + width()/2, bottom-1);
}
}
//treat this as two connections with adjacent sides
fillBetweenPoints(level, from, side, floor);
fillBetweenPoints(level, side, to, floor);
}
}