Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- extends State
- # export variables
- export(int) var MAX_IDLE_MOVE_RADIUS := 3
- export(int) var MAX_MOVE_TIME_GAP_IN_SEC := 60
- # node references
- onready var parent_state_tree :StateTree = $'..'
- onready var debug_line :Line2D = $'../../DebugLine'
- onready var idle_debug_line :Line2D = $'../../IdleDebugLine'
- onready var wander_timer :Timer = $WanderTimer
- onready var wander_target :Position2D = $WanderTarget
- # member variables
- var rng :RandomNumberGenerator = RandomNumberGenerator.new()
- var npc :KinematicBody2D
- var nav_mesh :Navigation2D
- var current_tilemap :TileMap
- var last_move_timestamp :int
- var move_influence :float = 0.0
- var current_tile :Vector2
- var current_target :Vector2
- var is_moving :bool = false
- var path :PoolVector2Array
- var _player_temp :Player
- var _debug_path :PoolVector2Array
- var _debug_distance_to_target :float
- # constants
- const MAX_MOVE_INFLUENCE := 100.0
- const MIN_DISTANCE_TO_TARGET := 10.0
- const SPEED := 150.0
- func _on_enable() -> void:
- wander_timer.start()
- func _on_disable() -> void:
- wander_timer.stop()
- func _init() -> void:
- state_name = 'idle'
- last_move_timestamp = OS.get_unix_time()
- # Called when the node enters the scene tree for the first time.
- func _ready() -> void:
- npc = parent_state_tree.target_entity
- nav_mesh = Game.get_current_world().find_node('Navigation2D')
- current_tilemap = Game.get_current_world().find_node('BaseTileMap') as TileMap
- debug_line.set_as_toplevel(true)
- _player_temp = Game.get_player()
- current_tile = current_tilemap.world_to_map(npc.global_position)
- # print('npc position in tilemap space: ', str(current_tile))
- rng.randomize()
- print('tilemap cell_size: ', str(current_tilemap.cell_size))
- # Called every frame. 'delta' is the elapsed time since the previous frame.
- func _process(delta) -> void:
- if is_moving:
- move_to_target(delta)
- # Updates the NPC's move influence. This influences the random chance that an NPC
- # will want to move to a different spot while idling
- #
- # the move influence increases more and more the longer the NPC hasn't moved
- func update_move_influence() -> void:
- var current_timestamp := OS.get_unix_time()
- var influence_interpolator := float(current_timestamp - last_move_timestamp) / MAX_MOVE_INFLUENCE
- move_influence = lerp(0.0, MAX_MOVE_INFLUENCE, influence_interpolator)
- # Generates a random number between 0 and MAX_MOVE_INFLUENCE
- # if the number is >= 95% of MAX_MOVE_INFLUENCE's value then the NPC decides to move
- func decides_to_move() -> bool:
- var decision := rng.randf_range(0.0, MAX_MOVE_INFLUENCE) + move_influence
- if decision >= MAX_MOVE_INFLUENCE - (MAX_MOVE_INFLUENCE / 20.0):
- return true
- else:
- return false
- # Picks a random tile within the MAX_IDLE_MOVE_RADIUS to move to, and returns the
- # global(?) space Vector2 representing the center of the chosen tile to move to
- func get_random_move_target() -> void:
- var move_x := rng.randi_range(-MAX_IDLE_MOVE_RADIUS, MAX_IDLE_MOVE_RADIUS)
- var move_y := rng.randi_range(-MAX_IDLE_MOVE_RADIUS, MAX_IDLE_MOVE_RADIUS)
- var current_npc_tile = current_tilemap.world_to_map(npc.global_position)
- var target_pos := current_tilemap.map_to_world(Vector2(move_x, move_y) + current_npc_tile)
- wander_target.global_position = target_pos
- func get_path_to_target() -> PoolVector2Array:
- var nav_start := nav_mesh.to_local(npc.global_position)
- var ideal_nav_target := nav_mesh.to_local(wander_target.global_position)
- var nav_target := nav_mesh.get_closest_point(ideal_nav_target)
- print('nav target: ', str(nav_target))
- # debug_line.clear_points()
- # debug_line.add_point(nav_start)
- # debug_line.add_point(nav_target)
- # debug_line.add_point(nav_start)
- # debug_line.add_point(_player_temp.global_position)
- var _path = nav_mesh.get_simple_path(nav_start, nav_target)
- if _path.size() == 0:
- get_random_move_target()
- get_path_to_target()
- _debug_path = path
- var player_path = nav_mesh.get_simple_path(nav_start, _player_temp.global_position)
- debug_line.points = path
- return _path
- # Moves to the specified target position using a path created from the current
- # world's Navigation2D node
- func move_to_target(delta: float) -> void:
- if path.size() == 0:
- return
- var distance_to_next := npc.global_position.distance_to(path[1])
- var distance_to_target := npc.global_position.distance_to(path[path.size() - 1])
- _debug_distance_to_target = distance_to_target
- if path.size() < 2 or distance_to_next <= MIN_DISTANCE_TO_TARGET:
- print('path: ', str(path))
- # print('player path: ', str(player_path))
- last_move_timestamp = OS.get_unix_time()
- is_moving = false
- current_tile = current_tilemap.world_to_map(npc.global_position)
- return
- elif distance_to_target > MIN_DISTANCE_TO_TARGET:
- var move_direction := npc.global_position.direction_to(path[1])
- var move_velocity = move_direction * SPEED * delta
- var idle_movement := npc.move_and_collide(move_velocity)
- if idle_movement != null and idle_movement.remainder != Vector2.ZERO:
- var slide_vec = idle_movement.remainder.slide(idle_movement.normal)
- var _slide = npc.move_and_collide(slide_vec)
- elif distance_to_next < MIN_DISTANCE_TO_TARGET:
- path.remove(0)
- # temporary timer to debug values inside _process or functions run by _process
- func _on_Timer_timeout():
- # print('move influence: ', move_influence)
- print('path: ', path)
- print('npc global position: ', npc.global_position)
- print('distance to target: ', _debug_distance_to_target)
- pass
- func _on_WanderTimer_timeout():
- if not is_moving:
- update_move_influence()
- if decides_to_move():
- get_random_move_target()
- path = get_path_to_target()
- is_moving = true
Add Comment
Please, Sign In to add comment