Commit e829612e authored by tgw3ff's avatar tgw3ff
Browse files

Implement Enemy Spawn Selection

The map generator will now choose random cells to be enemy spawn locations, up
to a number of spawns less than a defined percentage of the total possible
enemy spawn locations. Enemy spawns are never closer than a pre-defined
distance from the player's spawn and never directly adjecent to a hole.

The tilemap script also will ensure that enemies never spawn inside a
collidable tile. This means that enemies will never spawn trapped inside of
the level geometry.
parent 261948c4
......@@ -37,6 +37,9 @@ func move(dir: String):
# Update previous position
previous_coord = get_coord(position)
var tilemap = get_node("../../TileMap")
print(tilemap.map_gen.enemy_spawns)
ray.cast_to = inputs[dir] * tile_size
ray.force_raycast_update()
if !ray.is_colliding():
......
......@@ -21,8 +21,6 @@ var y
var content
# Stores whether or not this cell is an elligible hole spawning location
var elligible_hole = true
# Stores whether or not this cell is an elligible enemy spawning location
var elligible_enemy = true
# Stores the other hole or coordinates to which this cell's hole leads to, if
# it hosts a hole
var destination = null
......@@ -31,6 +29,8 @@ var destination = null
var distance_wall = 0
# Stores whether or not this cell is the player's spawn
var player_spawn = false
# Stores whether or not this cell is an enmey spawn
var enemy_spawn = false
func _init(coord, value):
......@@ -56,4 +56,3 @@ func set_content(value):
# Change elligible_hole and elligible_enemy if needed
if content != EMPTY:
elligible_hole = false
elligible_enemy = false
const CELL = preload("res://src/Cell.gd")
const ROOM = preload("res://src/Room.gd")
# Percentage of cells in the map that should be enemy spawns
const ENEMY_FILL_PERCENT = 0.15
# Stores the empty coordinates on the map and which "room" they are each a part of
var rooms = []
var centers = []
var minimum_tree = []
# Stores which coord contains the player spawn
var player_spawn
# Stores an array of all of the cells in the map that are enemy spawn locations
var enemy_spawns = []
# Enumerator that stores which integers represent which type of tile
# The pairings also equate to the corresponding tile group's index in the
# atlas tileset
......@@ -86,7 +90,6 @@ var grid = []
func _init():
pass
# Prepares grid by sizing it and filling with random 1's or 0's (according to fill_percent)
func initialize_grid(fill_percent, width, height):
randomize()
......@@ -105,7 +108,6 @@ func initialize_grid(fill_percent, width, height):
value = CELL.EMPTY
grid[h].append(CELL.new([w, h], value))
# Returns the number of filled cells in the grid that surround the given coordinate
func get_surrounding_wall_count(grid_x, grid_y, width, height):
var wall_count = 0;
......@@ -120,7 +122,6 @@ func get_surrounding_wall_count(grid_x, grid_y, width, height):
return wall_count
# Makes the randomly filled grid transmogrify into a cave network
func smooth_grid(width, height):
for x in range(0, width - 1):
......@@ -131,7 +132,6 @@ func smooth_grid(width, height):
elif neighborWallTiles < 4:
grid[y][x].set_content(CELL.EMPTY)
# Return a matrix of the content of the cell at the given coords and its
# surrounding 8 cells' contents
func get_surrounding(grid_x, grid_y):
......@@ -145,7 +145,6 @@ func get_surrounding(grid_x, grid_y):
return surrounding
# Returns the value of the given matrix if it were rotated 90 degrees clockwise
# n times
func rotate_matrix(matrix=[[]], n=1):
......@@ -186,7 +185,6 @@ func rotate_matrix(matrix=[[]], n=1):
return matrix_p
# Returns the value of the given matrix if it were mirrored
# The boolean signifies wether the mirror is vertically or not
func mirror_matrix(matrix=[[]], v=false):
......@@ -219,7 +217,6 @@ func replace_3x3_grid(grid_x, grid_y, replacement):
for r_x in range(0, 3):
grid[grid_y + r_y - 1][grid_x + r_x - 1].set_content(replacement[r_y][r_x])
# Replace invalid submatrices in the grid/map
func replace_invalids(width, height):
var valid = false
......@@ -262,7 +259,6 @@ func replace_invalids(width, height):
valid = true
replace_3x3_grid(x, y, FILLED)
# Returns whether or not all of the coordinates in the rooms dictionary have been assigned a room
func assign_rooms_completed():
var all_assigned = true
......@@ -278,9 +274,10 @@ func assign_rooms_completed():
return all_assigned
# Iterates through all rooms to see if the given coord is in any of them
func is_coord_in_rooms(coord):
var in_rooms = false
# Iterates through all rooms to see what room the coord is in. Returns null if
# the coord is not in any of them
func coord_in_what_room(coord):
var room_location = null
var coord_vector = Vector2()
for room in rooms:
......@@ -291,9 +288,9 @@ func is_coord_in_rooms(coord):
coord_vector = coord
if coord_vector in room.cells.keys():
in_rooms = true
return in_rooms
room_location = room
return room_location
# Assigns rooms to each of the coordinate keys in the rooms dictionary
func assign_rooms(width, height):
......@@ -309,7 +306,7 @@ func assign_rooms(width, height):
unexplored.append(Vector2(x, y))
for coord in unexplored:
if !is_coord_in_rooms(coord):
if coord_in_what_room(coord) == null:
queue.append(coord)
while !queue.empty():
......@@ -330,7 +327,6 @@ func assign_rooms(width, height):
curr_room_id += 1
centers.append(rooms.back().center)
# A modified Kruskal's algorithm to find close to the minimum spanning tree
# between all room centers while also trying to ensuring that the larger rooms
# have the most branching off points.
......@@ -436,9 +432,30 @@ func spawn_player():
return spawn_coord
# Spawn enemies
func spawn_enemies():
var total_elligible_count = 0
var elligible_spawns = []
for room in rooms:
for coord in room.get_elligible_enemy_spawns():
elligible_spawns.append(coord)
total_elligible_count += 1
while (enemy_spawns.size() * 1.0) / total_elligible_count <= ENEMY_FILL_PERCENT && !elligible_spawns.empty():
randomize()
var i = randi() % elligible_spawns.size()
var spawn = elligible_spawns[i]
elligible_spawns.remove(i)
if coord_in_what_room(spawn).find_distance_individual(spawn, "PLAYER") < 4:
enemy_spawns.append(spawn)
# Generates a new map
func generate_map(fill_percent, width, height):
rooms.clear()
enemy_spawns.clear()
initialize_grid(fill_percent, width, height)
for i in range(0, 3):
......@@ -453,4 +470,5 @@ func generate_map(fill_percent, width, height):
player_spawn = spawn_player()
spawn_holes()
spawn_enemies()
const CELL = preload("res://src/Cell.gd")
const BOULDER_RANGE = 2
const BOULDER_FILL_PERCENT = 0.25
const BOULDER_FILL_PERCENT = 0.15
const MUSHROOM_CLUSTER_RADIUS = 4
const MUSHROOM_CLUSTER_FILL_PERCENT = 0.15
const MUSHROOM_ROOM_FILL_PERCENT = 0.15
const MUSHROOM_ROOM_FILL_PERCENT = 0.10
# Stores the id of the room
var id
# Stores a dictionary with the keys being Vector2's that represent coordinates
......@@ -53,27 +53,40 @@ func get_surrounding_coords(coord, radius):
return neighbors
# Return the given cell's distance from the nearest cell with the given content
# value
# Return the given cell's distance from the nearest cell with the given content
# value, or, if the value is "PLAYER", it will find the distance from the
# player spawn cell. It will return the max integer value if the distance from
# the player spawn cell is being searched for but the room does not contain it
func find_distance_individual(coord, value):
var distance_current = -1
var distance_found = false
while !distance_found:
var surrounding_contents = []
distance_current += 1
for x_mod in range (-distance_current, distance_current + 1):
for y_mod in range (-distance_current, distance_current + 1):
if cells.keys().has(Vector2(coord.x + x_mod, coord.y + y_mod)):
surrounding_contents.append(cells[Vector2(coord.x + x_mod, coord.y + y_mod)].content)
elif value == CELL.WALL:
distance_found = true
if value in surrounding_contents:
distance_found = true
if str(value) != "PLAYER":
var surrounding_contents = []
distance_current += 1
for x_mod in range (-distance_current, distance_current + 1):
for y_mod in range (-distance_current, distance_current + 1):
if cells.keys().has(Vector2(coord.x + x_mod, coord.y + y_mod)):
surrounding_contents.append(cells[Vector2(coord.x + x_mod, coord.y + y_mod)].content)
elif value == CELL.WALL:
distance_found = true
if value in surrounding_contents:
distance_found = true
surrounding_contents = []
surrounding_contents = []
else:
if !spawn_room:
distance_current = 9223372036854775806
distance_found = true
else:
distance_current += 1
for x_mod in range (-distance_current, distance_current + 1):
for y_mod in range (-distance_current, distance_current + 1):
if cells.keys().has(Vector2(coord.x + x_mod, coord.y + y_mod)) && cells[Vector2(coord.x + x_mod, coord.y + y_mod)].player_spawn:
distance_found = true
return distance_current
......@@ -171,3 +184,13 @@ func spawn_hole(hole_coord, destination_coord):
for neighbor in get_surrounding_coords(hole_coord, 1):
cells[neighbor].elligible_hole = false
count_elligible_hole -= 1
# Returns an array of all cells in the room that are elligible enemy spawns
func get_elligible_enemy_spawns():
var elligible_spawns = []
for cell in cells.keys():
if cells[cell].elligible_hole == true && cells[cell].enemy_spawn == false && cells[cell].player_spawn == false:
elligible_spawns.append(cell)
return elligible_spawns
......@@ -224,6 +224,9 @@ func update_map():
line.free()
map_gen.generate_map(fill_percent, width, height)
# Make sure enemies do not spawn inside a collidable tile
for coord in map_gen.enemy_spawns:
break_obstacle(coord.x, coord.y)
var player = get_node("../ActorManager/Player")
var spawn_coord = map_gen.player_spawn
......
Supports Markdown
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