Autor: Alejandro Seguí Díaz
Tutores: Gonzalo A. Aranda Corral y Daniel Márquez Quintanilla
{(c,b)Software} de {(c,b)entretenimiento}
{(c,b)Mercado lider} indiscutible a {(c,b)nivel internacional}
La industria cinematográfica deja paso a la industria del videojuego
Videojuegos requieren {(c){(b)mapas}}
{(c,b)Consumo de recursos} (horas/persona)
|
|
Elaborar un {(c,b)generador de mapas}
$\implies$ ahorro de recursos
Cada juego tiene sus {(c,b)reglas} y {(c,b)mecánicas}
{(pf)El sistema {(c,b)generador} debe estar {(c,b)adaptado}}Especificaciones de este proyecto han sido impuestas por
Captura de Action Hollywood, publicado por TCH en 1995 para recreativas
Campo emergente en la aplicación a videojuegos:
Representación física de mapas y habitaciones: matriz de dos dimensiones
$\begin{matrix} 0 & 1 & 1 & 1 & 0 \\ 0 & 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{matrix}$ | $\leftrightarrow$ | ![]() |
{(c,b)Lista de puertas} que servirán para conectar habitaciones
Representación dividida en:
También nos referiremos como clase o modelo.
Contiene la {(c,b)matriz 2D} asociada al modelo de habitación.
{(c,b)Puertas potenciales} precomputadas
Puertas potenciales mostradas como tiles azules
$o(x,y) = outer(x,y)$: tile vacío exterior
$i(x,y) = inner(x,y)$: tile vacío interior
$s(x,y) = solid(x,y)$: tile sólido (pared)
Contiene un {(c,b)subconjunto} de todas las {(c,b)puertas potenciales} del modelo asociado
{(pf)Referencia al modelo}Además,
$$\bigcup_{r \in RR}posiblesConexiones(map, r)$$
$$RR = habitacionesRestantes$$
$possibleConnections(map, r) =$
$\bigcup_{p \in rooms(map)} \left\{ cx(map,r,p,u,v,w) : \neg col(map, r, w) \right\}$
$w = v - u + \begin{cases}
(-1,0) \\
(+1,0) \\
(0,-1) \\
(0,+1) \\
\end{cases}$
$potentialDoor(u, r), potentialDoor(v, p)$
Ilustración de posible conexión entre habitación restante y mapa
interface IMovementSelector {
Movimiento ElegirMovimiento( Mapa mapa, List<Movimiento> movimientos );
}
Mapa GenerarMapa( List<Habitacion> habitaciones, IMovementSelector mapSolver ) {
Mapa mapa = MapaVacio();
while( !habitaciones.isEmpty() ) {
List<Movimiento> movimientos = GenerarMovimientos( mapa, habitaciones );
Movimiento elegido = mapSolver.ElegirMovimiento( mapa, movimientos );
mapa.InsertarHabitacion( elegido.habitacion, elegido.posicion );
habitaciones.remove( elegido.habitacion );
GuardarMovimiento( elegido );
}
EstablecerRecorridoPrincipal( mapa );
return mapa;
}
Ejemplo de mapa generado por RandomSelector
interface IFitnessSolver {
float ComputarFitness( Mapa mapa, Movimiento m );
}
class SearchMovementSelector implements IMovementSelector {
IFitnessSolver fitnessSolver;
Movimiento ElegirMovimiento( Mapa mapa, List<Movimiento> movimientos ) {
List<Float> fitness;
for( Movimiento m : movimientos ) {
fitness[m.index] = fitnessSolver.ComputarFitness( mapa, m );
}
Movimiento elegido = ObtenerMejor( movimientos, fitness );
return elegido;
}
}
interface IFitnessCombinator {
float Combinar( float[] fitnesses );
}
class MultiObjectiveFitnessSolver implements IFitnessSolver {
IFitnessCombinator fitnessCombinator;
float ComputarFitness( Mapa mapa, Movimiento m ) {
float fitness = new float[3];
fitness[0] = ComputarObjetivo0( mapa, m );
fitness[1] = ComputarObjetivo1( mapa, m );
fitness[2] = ComputarObjetivo2( mapa, m );
fitnessCombinator.Combinar( fitness );
}
}
Ejemplo de fallo de caché con objetivo de bifurcaciones
interface IFitnessCache {
Fitness Get( Movimiento m );
void Cachear( Movimiento m, float fitness );
}
class SearchMovementSelector implements IMovementSelector {
IFitnessSolver fitnessSolver;
IFitnessCache fitnessCache;
Movimiento ElegirMovimiento( Mapa mapa, List<Movimiento> movimientos ) {
List<Float> fitness;
for( Movimiento m : movimientos ) {
Fitness f = fitnessCache.Get(m);
if( f != null ) {
fitness[m.index] = fitnessSolver.ComputarFitness( mapa, m );
fitnessCache.Cachear( m, fitness[m.index] );
} else {
fitness[m.index] = f;
}
}
Movimiento elegido = ObtenerMejor( movimientos, fitness );
return elegido;
}
}
{(c,b)Nombre} |
{(c,b)Descripción} |
Dummy | No interviene en la selección de prefab |
Probabilidad | Probabilidad de que se elija cada prefab |
Ciclo | Alterna entre prefabs |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Propiedad |
Valor |
DoorGenType | ALL |
SolverType | BestSearch |
CacheType | NO CACHE |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
Divisor 0.75 |
Divisor 0.85 |
Divisor 0.95 |
10 | 2 | 20 | 40 | 0.1762 | 0.1967 | 0.3667 |
10 | 2 | 30 | 60 | 0.4944 | 0.6254 | 1.4391 |
10 | 4 | 20 | 80 | 1.2335 | 1.6429 | 4.0735 |
10 | 4 | 30 | 120 | 4.8804 | 6.6693 | 18.185 |
Propiedad |
Valor |
DoorGenType | RANDOM |
SolverType | BestSearch |
Divisor de movimientos | 1.0 |
CacheType | NO CACHE |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
40% puertas |
60% puertas |
80% puertas |
10 | 4 | 8 | 32 | 1.7974 | 3.3016 | 4.6551 |
10 | 4 | 10 | 40 | 4.1856 | 8.2365 | 9.8173 |
10 | 6 | 8 | 48 | 15.4529 | 20.9266 | 29.2930 |
10 | 6 | 10 | 60 | 34.6856 | 57.3447 | 69.2746 |
Propiedad |
Valor |
DoorGenType | ALL |
SolverType | BestSearch |
Divisor de movimientos | 1.0 |
CacheType | REFRESHER |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
Refresher 2 |
Refresher 5 |
Refresher 10 |
6 | 4 | 10 | 40 | 1.3768 | 1.0284 | 0.7652 |
6 | 4 | 15 | 60 | 6.7212 | 5.5230 | 3.4247 |
6 | 6 | 10 | 60 | 8.7299 | 6.7348 | 5.5665 |
6 | 6 | 15 | 90 | 43.7861 | 35.1948 | 26.3090 |
Propiedad |
Valor |
DoorGenType | ALL |
SolverType | BestSearch |
Divisor de movimientos | 1.0 |
CacheType | ALWAYS |
Propiedad |
Valor |
DoorGenType | ALL |
SolverType | BestSearch |
Divisor de movimientos | 1.0 |
CacheType | NO CACHE |
Propiedad |
Valor |
DoorGenType | RANDOM |
% puertas generadas | 0.5 |
CacheType | REFRESHER |
Divisor de refresco | 10 |
SolverType | BestSearch |
Divisor de movimientos | 0.9 |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
No Caché |
Always Caché |
Personaliz. |
8 | 4 | 2 | 8 | 0.0333 | 0.0173 | 0.0030 |
8 | 4 | 4 | 16 | 0.2818 | 0.0648 | 0.0122 |
8 | 4 | 6 | 24 | 1.2533 | 0.1948 | 0.0353 |
8 | 4 | 8 | 32 | 3.3726 | 0.4230 | 0.0779 |
8 | 6 | 2 | 12 | 0.1696 | 0.0666 | 0.0107 |
8 | 6 | 4 | 24 | 1.7436 | 0.2855 | 0.0480 |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
No Caché |
Always Caché |
Personaliz. |
8 | 6 | 6 | 36 | 8.6427 | 1.0330 | 0.1302 |
8 | 6 | 8 | 48 | 19.8587 | 2.7444 | 0.3154 |
8 | 8 | 2 | 16 | 0.5825 | 0.2523 | 0.0210 |
8 | 8 | 4 | 32 | 7.3916 | 1.1891 | 0.1030 |
8 | 8 | 6 | 48 | 33.7261 | 3.6201 | 0.3438 |
8 | 8 | 8 | 64 | 107.0143 | 9.6228 | 0.8998 |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
Tiempo |
6 | 5 | 1 | 5 | 0.0007 |
6 | 5 | 2 | 10 | 0.0029 |
6 | 5 | 3 | 15 | 0.0072 |
6 | 5 | 4 | 20 | 0.0167 |
6 | 10 | 1 | 10 | 0.0050 |
6 | 10 | 2 | 20 | 0.0265 |
6 | 10 | 3 | 30 | 0.0678 |
6 | 10 | 4 | 40 | 0.1601 |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
Tiempo |
6 | 15 | 1 | 15 | 0.0156 |
6 | 15 | 2 | 30 | 0.0905 |
6 | 15 | 3 | 45 | 0.3026 |
6 | 15 | 4 | 60 | 0.6858 |
6 | 20 | 1 | 20 | 0.0398 |
6 | 20 | 2 | 40 | 0.2525 |
6 | 20 | 3 | 60 | 0.7766 |
6 | 20 | 4 | 80 | 2.0803 |
Tam. habs. |
Num. modelos |
Instancias / modelo |
Total habs. |
Tiempo |
10 | 5 | 1 | 5 | 0.00348 |
10 | 5 | 2 | 10 | 0.01271 |
10 | 5 | 3 | 15 | 0.0245 |
10 | 10 | 1 | 10 | 0.0257 |
10 | 10 | 2 | 20 | 0.1215 |
10 | 10 | 3 | 30 | 0.1667 |
10 | 15 | 1 | 15 | 0.1143 |
10 | 15 | 2 | 30 | 0.3775 |
10 | 15 | 3 | 45 | 0.8163 |
Tam. habs. |
Num. modelos |
Instancias/modelo |
Total habs. |
Tiempo ejec. |
6 | 20 | 1 | 20 | 0.0395 |
6 | 20 | 2 | 40 | 0.2504 |
6 | 30 | 1 | 30 | 0.1479 |
6 | 30 | 2 | 60 | 0.9845 |
6 | 40 | 1 | 40 | 0.4307 |
6 | 40 | 2 | 80 | 2.9425 |
6 | 50 | 1 | 50 | 0.9979 |
6 | 50 | 2 | 100 | 7.6388 |
Propiedad |
Valor |
DoorGenType | RANDOM |
SolverType | BestSearch |
Divisor de movimientos | 0.5 |
CacheType | ALWAYS |
% puertas generadas | 0.3 |
Tam. habs. |
Num. modelos |
Instancias/modelo |
Total habs. |
Tiempo |
6 | 50 | 2 | 100 | 1.6345024 |