forked from 2121578/gai-ca2
Added exploration behavior
parent
268f2c0ce1
commit
57db80e685
File diff suppressed because one or more lines are too long
|
@ -15,6 +15,9 @@ enum Event {
|
||||||
PLAYER_DROPPED_ITEM,
|
PLAYER_DROPPED_ITEM,
|
||||||
PLAYER_USED_ITEM,
|
PLAYER_USED_ITEM,
|
||||||
GAME_STATE_WIN,
|
GAME_STATE_WIN,
|
||||||
|
NEW_EXPLORATION_GOAL,
|
||||||
|
EXPLORATION_GOAL_REACHED,
|
||||||
|
TEMPERATURE_COLD,
|
||||||
};
|
};
|
||||||
#
|
#
|
||||||
static var events: Array[TrackedEvent] = []
|
static var events: Array[TrackedEvent] = []
|
||||||
|
@ -74,6 +77,12 @@ static func populate_visual_log_create_label(event: TrackedEvent, container: Con
|
||||||
text = "Boat complete"
|
text = "Boat complete"
|
||||||
elif event_id == Event.GAME_STATE_WIN:
|
elif event_id == Event.GAME_STATE_WIN:
|
||||||
text = "Game won"
|
text = "Game won"
|
||||||
|
elif event_id == Event.NEW_EXPLORATION_GOAL:
|
||||||
|
text = "New exploration goal " + str(params["goal"])
|
||||||
|
elif event_id == Event.EXPLORATION_GOAL_REACHED:
|
||||||
|
text = "Exploration goal reached " + str(params["goal"])
|
||||||
|
elif event_id == Event.TEMPERATURE_COLD:
|
||||||
|
text = "Temperature is cold: -" + str(params["temperature"])
|
||||||
else:
|
else:
|
||||||
text = "Something happened..."
|
text = "Something happened..."
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
class_name TaskPlannedExploration
|
||||||
|
extends Task
|
||||||
|
|
||||||
|
var last_goals: Array[Vector2i] = []
|
||||||
|
var current_goal: Vector2i = tilemap_types.NO_TILE_FOUND
|
||||||
|
|
||||||
|
|
||||||
|
func run(blackboard: Dictionary) -> void:
|
||||||
|
var world: World = blackboard["world"]
|
||||||
|
var player: PlayerManager = blackboard["player"]
|
||||||
|
var navigation: TilemapNavigation = blackboard["navigation"]
|
||||||
|
|
||||||
|
# check if player distance is < 2 to the current goal
|
||||||
|
if current_goal != tilemap_types.NO_TILE_FOUND:
|
||||||
|
if TilemapNavigation.manhattan_distance(player.board_position, current_goal) < 3:
|
||||||
|
EventsTracker.track(EventsTracker.Event.EXPLORATION_GOAL_REACHED, {"goal": current_goal})
|
||||||
|
current_goal = tilemap_types.NO_TILE_FOUND
|
||||||
|
|
||||||
|
if current_goal == tilemap_types.NO_TILE_FOUND:
|
||||||
|
find_new_goal(world, player, navigation)
|
||||||
|
if current_goal != tilemap_types.NO_TILE_FOUND:
|
||||||
|
EventsTracker.track(EventsTracker.Event.NEW_EXPLORATION_GOAL, {"goal": current_goal})
|
||||||
|
|
||||||
|
if current_goal == tilemap_types.NO_TILE_FOUND:
|
||||||
|
status = Task.FAILURE
|
||||||
|
status_reason = "No goal found"
|
||||||
|
return
|
||||||
|
|
||||||
|
StepVisualization.add_circle_tileset(current_goal, 2, StepVisualization.CircleType.GOAL)
|
||||||
|
StepVisualization.add_line_tileset(player.board_position, current_goal, StepVisualization.LineType.SEARCH_SELECTED)
|
||||||
|
|
||||||
|
var path: Array[Vector2i] = navigation.cached_path_allow_neighbors(blackboard, "exploration_goal", current_goal)
|
||||||
|
if path.size() == 0:
|
||||||
|
status = Task.FAILURE
|
||||||
|
status_reason = "No path found"
|
||||||
|
return
|
||||||
|
|
||||||
|
blackboard["path"] = path
|
||||||
|
|
||||||
|
status = Task.SUCCESS
|
||||||
|
status_reason = "goal: " + str(current_goal)
|
||||||
|
|
||||||
|
|
||||||
|
func find_new_goal(world: World, player: PlayerManager, navigation: TilemapNavigation) -> void:
|
||||||
|
if last_goals.size() == 0:
|
||||||
|
last_goals.append(world.camp_manager.camp)
|
||||||
|
|
||||||
|
# perform search for a new goal X times, pick the one that is furthest away from the last goal
|
||||||
|
var best_goal: Vector2i = tilemap_types.NO_TILE_FOUND
|
||||||
|
var best_distance: float = 0
|
||||||
|
|
||||||
|
for i in range(4):
|
||||||
|
var goal_consideration: Vector2i = determine_an_interesting_goal(world)
|
||||||
|
if goal_consideration == tilemap_types.NO_TILE_FOUND:
|
||||||
|
continue
|
||||||
|
StepVisualization.add_circle_tileset(goal_consideration, 2, StepVisualization.CircleType.GOAL_CONSIDERATION)
|
||||||
|
StepVisualization.add_line_tileset(player.board_position, goal_consideration, StepVisualization.LineType.SEARCH_BASE)
|
||||||
|
|
||||||
|
var distance: float = TilemapNavigation.manhattan_distance(goal_consideration, navigation.manhattan_distance_closest(last_goals, goal_consideration))
|
||||||
|
if distance > best_distance:
|
||||||
|
best_goal = goal_consideration
|
||||||
|
best_distance = distance
|
||||||
|
|
||||||
|
if best_goal != tilemap_types.NO_TILE_FOUND:
|
||||||
|
last_goals.append(best_goal)
|
||||||
|
current_goal = best_goal
|
||||||
|
|
||||||
|
|
||||||
|
func determine_an_interesting_goal(world: World) -> Vector2i:
|
||||||
|
# starting from the camp position (world.camp_manager.camp),
|
||||||
|
# pick a random direction (360 degrees, random on x and y then normalize),
|
||||||
|
# then step in that direction until the last walkable tile is found
|
||||||
|
# (if not walkable, check every step for the next 10 tiles again and only stop if none of them are walkable)
|
||||||
|
# then, pick a random walkable tile in the area around that last walkable tile,
|
||||||
|
# and check if the player can get there using the navigation system.
|
||||||
|
|
||||||
|
var camp_position: Vector2 = Vector2(world.camp_manager.camp)
|
||||||
|
var direction: Vector2 = Vector2(randf() * 2 - 1, randf() * 2 - 1).normalized()
|
||||||
|
|
||||||
|
var last_walkable: Vector2i = Vector2i(0, 0)
|
||||||
|
var iterations_no_walkable: int = 0
|
||||||
|
|
||||||
|
for i in range(5000):
|
||||||
|
var check_position: Vector2i = camp_position + (direction * i).floor()
|
||||||
|
if not world.is_walkable(check_position):
|
||||||
|
iterations_no_walkable += 1
|
||||||
|
else:
|
||||||
|
iterations_no_walkable = 0
|
||||||
|
last_walkable = check_position
|
||||||
|
|
||||||
|
if iterations_no_walkable > 10:
|
||||||
|
break
|
||||||
|
|
||||||
|
if last_walkable == Vector2i(0, 0):
|
||||||
|
return tilemap_types.NO_TILE_FOUND
|
||||||
|
|
||||||
|
var picked_goal: Vector2i = Vector2i(0, 0)
|
||||||
|
for i in range(10):
|
||||||
|
var check_position: Vector2i = last_walkable + Vector2i(randi_range(-10, 10), randi_range(-10, 10))
|
||||||
|
if world.is_walkable(check_position):
|
||||||
|
picked_goal = check_position
|
||||||
|
break
|
||||||
|
|
||||||
|
return picked_goal
|
|
@ -0,0 +1,14 @@
|
||||||
|
class_name TaskRandomWalking
|
||||||
|
extends Task
|
||||||
|
|
||||||
|
func run(blackboard: Dictionary) -> void:
|
||||||
|
var player: PlayerManager = blackboard["player"]
|
||||||
|
var navigation: TilemapNavigation = blackboard["navigation"]
|
||||||
|
|
||||||
|
var direction: Vector2i = navigation.walking_directions[randi() % navigation.walking_directions.size()]
|
||||||
|
var target: Vector2i = player.board_position + direction
|
||||||
|
|
||||||
|
player.walk_towards(target)
|
||||||
|
|
||||||
|
status = SUCCESS
|
||||||
|
status_reason = "Walking towards " + str(target)
|
|
@ -1,13 +1,27 @@
|
||||||
class_name TaskCheckTemperatureCold
|
class_name TaskCheckTemperatureCold
|
||||||
extends Task
|
extends Task
|
||||||
|
|
||||||
|
var last_temperature: float = 0
|
||||||
|
|
||||||
|
|
||||||
func run(blackboard: Dictionary) -> void:
|
func run(blackboard: Dictionary) -> void:
|
||||||
var player: PlayerManager = blackboard["player"]
|
var player: PlayerManager = blackboard["player"]
|
||||||
|
|
||||||
if player.get_current_temperature() > 0:
|
var current_temperature: int = player.get_current_temperature()
|
||||||
|
|
||||||
|
var temperature_changed: bool = current_temperature != last_temperature
|
||||||
|
var temperature_cold: bool = current_temperature > 0
|
||||||
|
|
||||||
|
if temperature_changed and temperature_cold:
|
||||||
|
EventsTracker.track(EventsTracker.Event.TEMPERATURE_COLD, {"temperature": current_temperature})
|
||||||
|
|
||||||
|
if temperature_changed:
|
||||||
|
last_temperature = current_temperature
|
||||||
|
|
||||||
|
if temperature_cold:
|
||||||
status = SUCCESS
|
status = SUCCESS
|
||||||
status_reason = "cold: " + str(player.get_current_temperature())
|
status_reason = "cold: " + str(current_temperature)
|
||||||
return
|
return
|
||||||
|
|
||||||
status = FAILURE
|
status = FAILURE
|
||||||
status_reason = "not cold: " + str(player.get_current_temperature())
|
status_reason = "not cold: " + str(current_temperature)
|
||||||
|
|
|
@ -5,7 +5,7 @@ static var game_manager: GameManager
|
||||||
static var world: World
|
static var world: World
|
||||||
#
|
#
|
||||||
enum LineType { SEARCH_BASE, SEARCH_SELECTED, SEARCH_FAILED }
|
enum LineType { SEARCH_BASE, SEARCH_SELECTED, SEARCH_FAILED }
|
||||||
enum CircleType { PLAYER_VIEW }
|
enum CircleType { PLAYER_VIEW, GOAL_CONSIDERATION, GOAL }
|
||||||
#
|
#
|
||||||
# Dictionary[Array[Vector2i], LineType] ([from, to], line_type)
|
# Dictionary[Array[Vector2i], LineType] ([from, to], line_type)
|
||||||
static var draw_lines: Dictionary = {}
|
static var draw_lines: Dictionary = {}
|
||||||
|
@ -70,3 +70,7 @@ func _draw() -> void:
|
||||||
|
|
||||||
if circle_type == CircleType.PLAYER_VIEW:
|
if circle_type == CircleType.PLAYER_VIEW:
|
||||||
draw_circle(center, radius, Color("green"), false, 2, true)
|
draw_circle(center, radius, Color("green"), false, 2, true)
|
||||||
|
elif circle_type == CircleType.GOAL_CONSIDERATION:
|
||||||
|
draw_circle(center, radius, Color("yellow"), false, 2, true)
|
||||||
|
elif circle_type == CircleType.GOAL:
|
||||||
|
draw_circle(center, radius, Color("red"), false, 2, true)
|
||||||
|
|
|
@ -43,7 +43,7 @@ func setup() -> void:
|
||||||
else:
|
else:
|
||||||
push_error("No boat leave location found on tilemap")
|
push_error("No boat leave location found on tilemap")
|
||||||
|
|
||||||
print("CampManager: camp=", camp, " campfire=", campfire)
|
print("CampManager: camp=", camp, " campfire=", campfire, " boat_build_location=", boat_build_location, " boat_leave_location=", boat_leave_location)
|
||||||
|
|
||||||
tilemap_interactive.set_cell(campfire, tilemap_types.OBJECT_I_FIREPIT_OFF)
|
tilemap_interactive.set_cell(campfire, tilemap_types.OBJECT_I_FIREPIT_OFF)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue