Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- extends Node2D
- #INITIATING
- #variable declaraction
- #ready function (first timer call)
- #CORE LOGIC
- #timer timeout
- #get direction & state
- #on tween completed
- #STATE ACTIONS
- #attack
- #move
- #damaged
- #KNIGHT ONLY ACTIONS
- #stunned
- #PATHFINDING
- #get path
- #get cost
- #get distance
- #get lower score & distance
- #path translate
- #------------------------------------ INITIATING ------------------------------------
- export (PackedScene) var Sword
- export (PackedScene) var Shield
- export (PackedScene) var Arrow
- export (PackedScene) var Fireball
- export (PackedScene) var Bones
- onready var Core = get_node("/root/Game")
- onready var map = get_node("/root/Game/TileMap")
- onready var spr = get_node("Sprite")
- onready var step = get_node("Timer")
- onready var tween = get_node("Tween")
- var player
- var mapArray = []
- var s = []
- var type
- var health
- var points
- #knight only variables
- var defending = false
- var stunned = false
- func _ready(): #to be merged with the current _ready()
- s = dir.sides
- #beginning here: this part is probably unecessary
- for y in range(29):
- for x in range(39):
- var point = Vector2(x * 16, y * 16)
- var tileIndex = map.get_cellv(map.world_to_map(point))
- if tileIndex == 2 or tileIndex == 7:
- mapArray.append(point)
- #ending here: this part is probably unecessary
- player = get_tree().get_nodes_in_group("Player")[0]
- self.add_to_group("Enemies")
- type = rn._rn(0, 2) #this will decide the type of enemy {knight, archer, mage}
- if type == 0: #knight
- spr.set_region_rect(Rect2(Vector2(48, 48), Vector2(16, 16)))
- health = 4
- step.wait_time = 1.5
- points = 10
- self.add_to_group("Knight")
- elif type == 1: #archer
- spr.set_region_rect(Rect2(Vector2(32, 48), Vector2(16, 16)))
- health = 2
- step.wait_time = 2
- points = 8
- self.add_to_group("Archer")
- elif type == 2: #mage
- spr.set_region_rect(Rect2(Vector2(16, 48), Vector2(16, 16)))
- health = 1
- step.wait_time = 2.2
- points = 12
- self.add_to_group("Mage")
- step.start()
- #------------------------------------ CORE LOGIC ------------------------------------
- func _on_Timer_timeout(): #when the timer is up
- var state = get_directionAndState()
- if state[1] == "combat":
- if not defending and type == 0:
- _defend()
- else:
- _attack(state[0])
- elif state[1] == "move":
- _move(state[0])
- func get_directionAndState(): #checks either if enemy is within range or not
- var state = "move"
- var target
- var objective = player.position
- for side in dir.sides:
- if objective == (position + side) and type == 0: #Knight: if objective(player) is in one of the four sides
- target = side
- state = "combat"
- if (get_distance(position, objective) <= 8 and type == 1) or (get_distance(position, objective) <= 4 and type == 2): #Archer or Mage: if objective(player) is within range
- target = objective
- state = "combat"
- if state == "move":
- target = _get_path(objective)[1] #[0]to get only the first step of the returned array
- return [target, state]
- func _on_Tween_tween_completed(object, key):
- if type == 0: #knight
- step.wait_time = 2.2
- elif type == 1: #archer
- step.wait_time = 1.6
- elif type == 2: #mage
- step.wait_time = 1.8
- step.set_paused(false)
- step.start()
- #------------------------------------ STATE ACTIONS ------------------------------------
- func _attack(point):
- if type == 0: #knight
- defending = false
- spr.set_region_rect(Rect2(Vector2(48, 48), Vector2(16, 16)))
- if player.defending:
- _stunned()
- step.start()
- #play sword on shield
- return
- else:
- var attack = Sword.instance()
- attack.position = (point + Vector2(0, -16))
- get_parent().add_child(attack)
- AP._play("res://Audio/SFX-sword-attack.wav")
- player._beAttacked(type)
- step.wait_time = 0.3
- step.start()
- return
- elif type == 1: #archer
- var attack = Arrow.instance()
- attack.position = position
- attack.target = (point + Vector2(8, 8))
- get_parent().add_child(attack)
- AP._play("res://Audio/SFX-bow-attack.wav")
- elif type == 2: #mage
- var attack = Fireball.instance()
- attack.position = position
- attack.target = (point + Vector2(8, 8))
- get_parent().add_child(attack)
- step.start()
- func _move(point):
- if type == 0 and defending:
- defending = false
- spr.set_region_rect(Rect2(Vector2(48, 48), Vector2(16, 16)))
- position = point
- step.start()
- func _damaged():
- if defending:
- #have to play sword in shield sound
- var shield = Shield.instance()
- shield.position = (position + Vector2(0, -16))
- get_parent().add_child(shield)
- player.stunned = true
- player.tween.interpolate_property(player, "modulate", Color(0, 0, 1, 1), Color(1, 1, 1, 1), 1.2, Tween.TRANS_LINEAR, Tween.EASE_OUT)
- player.tween.start()
- player.tic.wait_time = 1.2
- player.tic.start()
- print("Shield")
- else:
- step.set_paused(true)
- health -= 1
- if health <= 0:
- Core._scoreUpdate(points)
- var bones = Bones.instance()
- bones.position = position
- bones.add_to_group("Bones")
- if rn._rn(1, 2) == 1:
- bones.set_region_rect(Rect2(Vector2(32, 32), Vector2(16, 16)))
- get_parent().add_child(bones)
- queue_free()
- tween.interpolate_property(self, "modulate", Color(1, 0, 0, 1), Color(1, 1, 1, 1), 0.2, Tween.TRANS_LINEAR, Tween.EASE_OUT)
- tween.start()
- if type == 0:
- _defend()
- #--- KNIGHT ONLY ACTIONS ---
- func _defend():
- defending = true
- spr.set_region_rect(Rect2(Vector2(48, 64), Vector2(16, 16)))
- step.start()
- func _stunned():
- #have to play sword in shield sound
- step.wait_time = 2
- stunned = true
- tween.interpolate_property(self, "modulate", Color(0, 0, 1, 1), Color(1, 1, 1, 1), 2.0, Tween.TRANS_LINEAR, Tween.EASE_OUT)
- tween.start()
- #------------------------------------ PATHFINDING ------------------------------------
- func _get_path(objective):
- #this logic takes into account that start will always be the actual position of the character
- var openList = [{'coord': position, 'score': 0, 'distance': 0, 'parent': position}]
- var closedList = []
- while not openList.empty():
- if openList.empty():
- break
- var idx = get_lowestScoreAndDistance(openList)
- var current = openList[idx]
- #if current is the objective
- if current.coord == objective:
- closedList.append(current)
- return _pathInverter(closedList, position, objective) #I need to take this list through the "inverter"
- closedList.append(openList[idx])
- openList.remove(idx)
- for child in get_sides(current.coord):
- #start of list checking
- var closedHasIt = false
- for idx in closedList: #check closedList's indexes
- if idx.coord == child:
- closedHasIt = true
- break
- if closedHasIt == true: #if any index of closedList has it's "coord" value equals to child
- continue
- var openHasIt = false
- for idx in openList: #check openList's indexes
- if idx.coord == child:
- openHasIt = true
- break
- if openHasIt == true: #if any index of openList has it's "coord" value equals to child
- continue
- #end of list checking
- #beginning of: This block of text checks if there is another knight in the same position as the one being checked
- var knightHasIt = false
- for knight in get_tree().get_nodes_in_group("Knight"):
- if child == knight.position:
- knightHasIt = true
- if knightHasIt:
- continue
- #Ending of: This block of text checks if there is another knight in the same position as the one being checked
- var score = (get_cost(child) +get_distance(position, child) + get_distance(child, objective))
- for i in openList:
- if i.coord == child:
- openList.erase(i)
- var distance = get_distance(child, objective)
- var parent = current.coord
- openList.append({'coord': child, 'score': score, 'distance': distance, 'parent': parent})
- print("no path")
- return [position, position]
- func get_cost(node): #gets the cost of the node based on it's tile type (index)
- var tileIndex = map.get_cellv(node)
- var cost = 0
- if tileIndex == 2 or tileIndex == 7:
- cost = 0
- else:
- cost = 999
- return cost
- func get_distance(a, b): #gets the distance in tiles from "a" to "b"
- a = map.world_to_map(a)
- b = map.world_to_map(b)
- return int(abs(a.x - b.x) + abs(a.y - b.y))
- func get_lowestScoreAndDistance(list): #gets the index of the lowest distance among the lowest score duplicates
- var idx = 0
- var duplicates = []
- for i in range(list.size() - 1): #gets the lowest score
- if list[i].score < list[idx].score:
- idx = i
- for i in range(list.size() - 1): #gets all the lowest score duplicates into an array
- if list[i].score == list[idx].score:
- duplicates.append(i)
- for i in duplicates: #checks each duplicate for the lowest distance value and set it as the right idx
- if list[i].distance < list[idx].distance:
- idx = i
- return idx
- func get_sides(node): #gets the four sides of a node always in the contrary order
- var sides = []
- for side in s:
- for tile in mapArray:
- if tile == node + side:
- sides.append(tile)
- s.invert() #this is important as to eliminate favoritism for routes with rectangular shapes.
- return sides
- func _pathInverter(list, start, goal): #takes the result of pathfinding and translates it to a route that is understandable for the character.
- var pathList = []
- var current = goal
- pathList.append(goal)
- while not pathList.has(start): #beginning from the goal
- for i in list: #for each index in the list(closedList)
- if current == start:
- break
- if i.coord == current: #check if it matches with the "actual node" coordinate value
- current = i.parent #turn the parent into the node currently being checked(step 3 "actual node")
- pathList.append(current) #append current to the pathList
- break
- pathList.invert()
- return pathList #as the pathList is drawn backwards it has to be inverted
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement