diff --git a/src/Boss/Boss_template.tscn b/src/Boss/Boss_template.tscn index 308ca14..3593d05 100644 --- a/src/Boss/Boss_template.tscn +++ b/src/Boss/Boss_template.tscn @@ -31,14 +31,17 @@ hframes = 60 [node name="Hitbox" parent="." instance=ExtResource( 2 )] collision_layer = 0 +collision_mask = 65 [node name="CollisionShape2D" parent="Hitbox" index="0"] position = Vector2( 0, -15 ) shape = SubResource( 1 ) -[node name="Hurtbox" parent="." instance=ExtResource( 1 )] +[node name="Hurtbox" parent="." groups=[ +"HittableByPlayer", +] instance=ExtResource( 1 )] collision_layer = 4 -collision_mask = 0 +collision_mask = 128 [node name="CollisionShape2D" parent="Hurtbox" index="0"] position = Vector2( 0, -15 ) diff --git a/src/Boss/Minion.gd b/src/Boss/Minion.gd new file mode 100644 index 0000000..25a6cb8 --- /dev/null +++ b/src/Boss/Minion.gd @@ -0,0 +1,66 @@ +extends Minion + +var velocity := Vector2.ZERO + +# This is how you export variables with ranges to the editor window +export(int, 0, 500) var ACCELERATION := 450 +# Reference for the current player + +onready var player_stats := $Stats +onready var debug_label := $DebugLabel + +var damage_per_second := 0.0 +var totaldamage := 0.0 + +var rollvector = Vector2.ZERO + +func _debug_update(): + debug_label.text = str(player_stats.health) + "/" + str(player_stats.max_health) + " HP\n" + +func _ready(): + grid = get_tree().current_scene.get_node("Grid") + +# IMPORTANT: If you are using move_and_slide don't multiply by delta +# Godots physics system does that internally +# In move_and_collide(...) you have to multiply by delta. +func move(): + move_and_slide(velocity) + +func _physics_process(delta): + totaldamage += damage_per_second * delta + player_stats.speed += 10 * delta + while (totaldamage > 1): + totaldamage -= 1 + player_stats.health -= 1 + while (totaldamage <- 1): + totaldamage += 1 + player_stats.health += 1 + _debug_update() + + run(Vector2.ZERO, delta) + makeMove(delta) + move() + + +func _on_Stats_no_health(): + queue_free() + + +func _on_Hurtbox_area_entered(area): + player_stats.health -= area.damage + damage_per_second += area.damage + + +func _on_Hurtbox_area_exited(area): + damage_per_second -= area.damage + +# API Interface for ai_hero +func run(direction, delta): + direction = direction.normalized() + rollvector = direction + velocity = velocity.move_toward(player_stats.speed * rollvector, ACCELERATION * delta) + + if direction == Vector2.ZERO: + pass + else: + pass diff --git a/src/Boss/Minion.tscn b/src/Boss/Minion.tscn new file mode 100644 index 0000000..746afdc --- /dev/null +++ b/src/Boss/Minion.tscn @@ -0,0 +1,73 @@ +[gd_scene load_steps=10 format=2] + +[ext_resource path="res://Overlap/HurtHit_Box/Hurtbox.tscn" type="PackedScene" id=1] +[ext_resource path="res://Overlap/HurtHit_Box/Hitbox.tscn" type="PackedScene" id=2] +[ext_resource path="res://Overlap/Kind.tscn" type="PackedScene" id=3] +[ext_resource path="res://Overlap/Stats/Stats.tscn" type="PackedScene" id=4] +[ext_resource path="res://testSprites/white_minion_dog.png" type="Texture" id=5] +[ext_resource path="res://Boss/Minion.gd" type="Script" id=6] + +[sub_resource type="CircleShape2D" id=1] +radius = 6.0 + +[sub_resource type="CapsuleShape2D" id=2] +radius = 11.0 +height = 1.0 + +[sub_resource type="CapsuleShape2D" id=3] +radius = 11.0 +height = 1.0 + +[node name="Minion" type="KinematicBody2D"] +script = ExtResource( 6 ) +ACCELERATION = 500 + +[node name="Kind" parent="." instance=ExtResource( 3 )] +kind = 3 + +[node name="Sprite" type="Sprite" parent="."] +position = Vector2( 0, -10.2123 ) +texture = ExtResource( 5 ) +hframes = 60 + +[node name="Body" type="CollisionShape2D" parent="."] +shape = SubResource( 1 ) + +[node name="Hitbox" parent="." instance=ExtResource( 2 )] +collision_layer = 0 +collision_mask = 65 + +[node name="CollisionShape2D" parent="Hitbox" index="0"] +position = Vector2( 0.110184, -4.81305 ) +shape = SubResource( 2 ) + +[node name="Hurtbox" parent="." groups=[ +"HittableByPlayer", +] instance=ExtResource( 1 )] +collision_layer = 8 +collision_mask = 128 + +[node name="CollisionShape2D" parent="Hurtbox" index="0"] +position = Vector2( 0.110184, -4.81305 ) +shape = SubResource( 3 ) + +[node name="DebugLabel" type="Label" parent="."] +margin_left = -50.8637 +margin_top = -41.3944 +margin_right = 51.1363 +margin_bottom = -27.3944 +text = "the white dog" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Stats" parent="." instance=ExtResource( 4 )] +max_health = 2 +max_speed = 80.0 +[connection signal="area_entered" from="Hurtbox" to="." method="_on_Hurtbox_area_entered"] +[connection signal="area_exited" from="Hurtbox" to="." method="_on_Hurtbox_area_exited"] +[connection signal="no_health" from="Stats" to="." method="_on_Stats_no_health"] + +[editable path="Hitbox"] + +[editable path="Hurtbox"] diff --git a/src/Maps/Grid.gd b/src/Maps/Grid.gd index e8c2371..3c96341 100644 --- a/src/Maps/Grid.gd +++ b/src/Maps/Grid.gd @@ -7,7 +7,7 @@ var prio_grid : Array = [] var used_grid : Array = [] var time_passed := 0.0 var offset -export(float, 0, 42.0) var refresh_rate = 1 +export(float, 0, 42.0) var refresh_rate = 0.0 func _draw_object_grid(): @@ -38,6 +38,7 @@ func _reset_grids(): func _ready(): + var walls = get_tree().current_scene.get_node("FloorTileMap") offset = walls.global_position #todo put in grid_lul @@ -64,6 +65,9 @@ func reset_history(): func countTargets(table): + for i in range(table.size()): + table[i]=0 + for x in range(14): for y in range(7): for i in prio_grid[x][y]: @@ -99,6 +103,8 @@ func get_nearest(position, kind): for i in prio_grid[x][y]: if(i == kind): list.append([x, y]) + if list.size() == 0: + return[-1,-1] var dist = [] for field in list: var tmp = sqrt(pow(position[0] - field[0], 2) + pow(position[1] - field[1], 2)) @@ -112,9 +118,9 @@ func get_nearest(position, kind): func _update_grid(): _reset_grids() - var world = get_tree().current_scene.get_child(2) + var world = get_tree().current_scene.get_node("../YSort") for node in world.get_children(): - var node_kind = node.get_child(0) + var node_kind = node.get_node("Kind") var grid_corrds = _pixel_to_grid_coords(node.global_position) if (_is_in_grid(grid_corrds)): if(node_kind.general != Kind.FIELD and node_kind.general != Kind.WALL): diff --git a/src/Objects/Barrel/Barrel.gd b/src/Objects/Barrel/Barrel.gd index 9dad71c..0bd2e38 100644 --- a/src/Objects/Barrel/Barrel.gd +++ b/src/Objects/Barrel/Barrel.gd @@ -1,15 +1,19 @@ extends StaticBody2D -var GreenDrop = 0.5 -var BlueDrop = 0.4 -var RedDrop = 0.2 +export(int,1,10) var health = 1 +var GreenDrop = 0.4 +var BlueDrop = 0.5 +var RedDrop = 0.8 var Heart = 0.2 func offset_vec(): - var offset = 20 + var offset = 16 return Vector2((randf()-0.5)*offset, (randf()-0.5)*offset) func _on_Hurtbox_area_entered(area): + health -= area.damage + if(health>0): + return queue_free() var GreenRubies = load("res://Objects/Rubies/Green.tscn") var BlueRubies = load("res://Objects/Rubies/Blue.tscn") @@ -17,7 +21,7 @@ func _on_Hurtbox_area_entered(area): var Hearts = load("res://Objects/Heart/Heart.tscn") #index of ysort - var world = get_tree().current_scene.get_child(2) + var world = get_tree().current_scene.get_node("YSort") if(randf()=spawnRate): - # elapsedTime-=spawnRate - # var Minion = load("") - # var world = get_tree().current_scene.get_child(2) - # #TODO minions - # var minion = Minion.instance() - # world.add_child(minion) - # minion.global_position = global_position + if(elapsedTime>=spawnRate): + elapsedTime-=spawnRate + var world = get_tree().current_scene.get_child(2) + var minion = Minion.instance() + world.add_child(minion) + minion.global_position = global_position+offset_vec() func _on_Hurtbox_area_entered(area): lifePoints -= area.damage - if(lifePoints<0): + if(lifePoints<=0): queue_free() pass diff --git a/src/Objects/Torch/Torch.tscn b/src/Objects/Torch/Torch.tscn index 72dcad8..f6d5e0f 100644 --- a/src/Objects/Torch/Torch.tscn +++ b/src/Objects/Torch/Torch.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://Overlap/HurtHit_Box/Hurtbox.tscn" type="PackedScene" id=1] [ext_resource path="res://testSprites/fackel.png" type="Texture" id=2] @@ -13,19 +13,22 @@ height = 12.0 [node name="Torch" type="Node2D"] script = ExtResource( 3 ) -[node name="FireEffect" parent="." instance=ExtResource( 4 )] -position = Vector2( 1.88936, -12.4698 ) [node name="Kind" parent="." instance=ExtResource( 5 )] general = 4 kind = 2 +[node name="FireEffect" parent="." instance=ExtResource( 4 )] +position = Vector2( 1.88936, -12.4698 ) + [node name="Sprite" type="Sprite" parent="."] position = Vector2( 0, -8 ) texture = ExtResource( 2 ) -[node name="Hurtbox" parent="." instance=ExtResource( 1 )] +[node name="Hurtbox" parent="." groups=[ +"HittableByPlayer", +] instance=ExtResource( 1 )] collision_layer = 8 -collision_mask = 0 +collision_mask = 128 script = null [node name="CollisionShape2D" parent="Hurtbox" index="0"] diff --git a/src/Overlap/AI/AI_Hero.gd b/src/Overlap/AI/AI_Hero.gd index 0f53e77..e298d71 100644 --- a/src/Overlap/AI/AI_Hero.gd +++ b/src/Overlap/AI/AI_Hero.gd @@ -7,15 +7,10 @@ const Grid = preload("res://Maps/Grid.gd") var grid - -enum{ - LENGTH, - WAY -} - enum{ STEP, ROLL, + ATTAC, NOTHING } @@ -30,18 +25,17 @@ var ai_movement_state = NOTHING var numbers = [0,0,0,0,0,0,0,0,0,0] var prios = [7,0,6,5,4,3,2,1,1,4] -var totalPrioTurn = 0 -var executesTurn = false -var abortProb = 0.01 - var targetFieldCur = [0,0] var targetFieldUsed = false -var actionField = [0,0] +var actionKind = Grid.Kind.TERMINAL_SYMBOL var actionFieldUsed = false -var threadTime = 0.4 +var areaRefList = [] + +var threadTime = 0.6 var threadDelta = 0.0 + #calculates the sum of all present prios func calcTotalPrio(): var sum = 0 @@ -76,9 +70,9 @@ func calcPrioTable(): #14+7 0.999 #updates heart and bonfire prio func adjustPrio(currentHealth, maxHealth): - var prioVal = 40.0 - (float(currentHealth)/float(maxHealth))*40.0 - var bonfire = prioVal - var hearts = prioVal - 1 + var prioVal = 10.0 - (float(currentHealth)/float(maxHealth))*10.0 + var bonfire = prioVal + 1 + var hearts = prioVal if(hearts < 0): hearts = 0 prios[Grid.Kind.BONFIRE]=bonfire @@ -103,16 +97,16 @@ func getCost(field): for i in grid.object_grid[field.x][field.y]: match i: Grid.Kind.DAMAGE: - cost += prios[Grid.Kind.BONFIRE] * 32 + cost += 100 Grid.Kind.SLOW: - cost += 1 + cost += 1 return cost #return an heurestic of distance # curr - current position # targ - a target position func h_fn(curr, target): - return sqrt(pow(target[0]-curr[0],2)+pow(target[0]-curr[0],2)) + return 0 # currCost - currentCost # target - position of the field to move to @@ -124,13 +118,13 @@ func adjacent(currentPosition, can_roll = true): var adj := [] #adj.append([STEP, Vector2(0,0)]) var p = currentPosition - var pot_adj_step = [[p[0]-1, p[1]-1], [p[0]-1, p[1]-0], [p[0]-1, p[1]+1], - [p[0]+0, p[1]-1], [p[0]+0, p[1]+1], - [p[0]+1, p[1]-1], [p[0]+1, p[1]+0], [p[0]+1, p[1]+1]] + var pot_adj_step = [[p[0]-1, p[1]-1], [p[0]-0, p[1]-1], [p[0]+1, p[1]-1], + [p[0]-1, p[1]-0], [p[0]+1, p[1]+0], + [p[0]-1, p[1]+1], [p[0]+0, p[1]+1], [p[0]+1, p[1]+1]] - var pot_adj_roll = [[p[0]-2, p[1]-2], [p[0]-2, p[1]-0], [p[0]-2, p[1]+2], - [p[0]+0, p[1]-2], [p[0]+0, p[1]+2], - [p[0]+2, p[1]-2], [p[0]+2, p[1]+0], [p[0]+2, p[1]+2]] + var pot_adj_roll = [[p[0]-0, p[1]-2], + [p[0]-2, p[1]-0],[p[0]+2, p[1]+0], + [p[0]+0, p[1]+2]] for i in range(pot_adj_step.size()): @@ -145,6 +139,8 @@ func adjacent(currentPosition, can_roll = true): continue if(grid.used_grid[next[0]][next[1]]): continue + if(grid._is_in_grid(Vector2(next[0], next[1])) ==false): + continue if(grid.object_grid[next[0]][next[1]][0]!=Grid.Kind.WALL): if(i==0): if(grid.object_grid[pot_adj_step[1][0]][pot_adj_step[1][1]][0]!=Grid.Kind.WALL && @@ -169,6 +165,7 @@ func adjacent(currentPosition, can_roll = true): adj.append([STEP, Vector2(next[0],next[1]),1.0]) + for i in range(pot_adj_roll.size()): var next = pot_adj_roll[i] if(next[0]<0): @@ -181,49 +178,21 @@ func adjacent(currentPosition, can_roll = true): continue if(grid.used_grid[next[0]][next[1]]): continue - if(grid.object_grid[next[0]][next[1]][0]!=Grid.Kind.WALL): - continue + if(grid._is_in_grid(Vector2(next[0], next[1])) == false): + continue if(grid.object_grid[next[0]][next[1]][0]!=Grid.Kind.WALL): if(i==0): - if(grid.object_grid[next[0]+0][next[1]+1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+1][next[1]+0][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+1][next[1]+1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+1][next[1]+2][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+2][next[1]+1][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.1]) - if(i==1): if(grid.object_grid[next[0]+0][next[1]+1][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.0]) - if(i==2): - if(grid.object_grid[next[0]-0][next[1]+1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-1][next[1]+0][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-1][next[1]+1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-1][next[1]+2][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-2][next[1]+1][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.1]) - if(i==3): + adj.append([ROLL, Vector2(next[0],next[1]),1.0]) + if(i==1): if(grid.object_grid[next[0]+1][next[1]+0][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.0]) - if(i==4): + adj.append([ROLL, Vector2(next[0],next[1]),1.0]) + if(i==2): if(grid.object_grid[next[0]-1][next[1]+0][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.0]) - if(i==5): - if(grid.object_grid[next[0]+0][next[1]-1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+1][next[1]-0][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+1][next[1]-1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+1][next[1]-2][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]+2][next[1]-1][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.1]) - if(i==6): + adj.append([ROLL, Vector2(next[0],next[1]),1.0]) + if(i==3): if(grid.object_grid[next[0]+0][next[1]-1][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.0]) - if(i==7): - if(grid.object_grid[next[0]-0][next[1]-1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-1][next[1]-0][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-1][next[1]-1][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-1][next[1]-2][0]!=Grid.Kind.WALL && - grid.object_grid[next[0]-2][next[1]-1][0]!=Grid.Kind.WALL): - adj.append([ROLL, Vector2(next[0],next[1]),2.1]) + adj.append([ROLL, Vector2(next[0],next[1]),1.0]) return adj @@ -247,6 +216,7 @@ func AStar(source, target): # Set flag grid.used_grid[node[2][0]][node[2][1]] = true var adj_list = adjacent(node[2]) + var current_field = node[2] for i in adj_list: var move_cost = i[2] @@ -260,67 +230,109 @@ func AStar(source, target): return [NOTHING, [0,0]] +func movement_calulcaotr(): + var currentPosition = grid._pixel_to_grid_coords(global_position) + + var enemyKind + + numbers = grid.countTargets(numbers) + if(actionKind == grid.Kind.TERMINAL_SYMBOL || numbers[actionKind]==0 || actionFieldUsed==false): + enemyKind = calcEnemyKind() + actionKind = enemyKind + actionFieldUsed = true + else: + enemyKind = actionKind + + if(enemyKind==Grid.Kind.TERMINAL_SYMBOL): + return + + var targetField = grid.get_nearest(currentPosition, enemyKind) + if(targetField==[-1,-1]): + return + + + var MoveAdvice = getMoveDescription(currentPosition, targetField) + grid.reset_history() + + return MoveAdvice -func makeMove(delta): +func is_hittable(): + var length = areaRefList.size() + if length == 0: + return null + return instance_from_id(areaRefList[0]).global_position + +func hit_or_miss(target, current, delta): + attac(Vector2(target[0]-current[0], target[1]-current[1]), delta*4) + +func movement_decider_ai(target, kindOfStep, delta): + var currentPosition = grid._pixel_to_grid_coords(global_position) + var currentPixel = global_position + var hitPixelTarget = is_hittable() - #if(actionFieldUsed==true): - # var random = randf() - # if(random < mindChangeProbability): - # ExecutionState = AI_MOVE - - if ExecutionState == AI_MOVE: - threadDelta = 0 - var currentPosition = grid._pixel_to_grid_coords(global_position) - var calcNew = false - var target - var MoveAdvice - - if(actionFieldUsed==false): - calcNew = true - - if(calcNew==true): - var enemyKind = calcEnemyKind() - if(enemyKind==Grid.Kind.TERMINAL_SYMBOL): - return - target = grid.get_nearest(currentPosition, enemyKind) - actionField = target - actionFieldUsed = true - MoveAdvice = getMoveDescription(currentPosition, target) - else: - MoveAdvice = getMoveDescription(currentPosition, actionField) - grid.reset_history() - - target = MoveAdvice[1] - if(MoveAdvice[0]==STEP): + if hitPixelTarget!=null: + hit_or_miss(hitPixelTarget, currentPixel, delta*4) + + else: + if(kindOfStep==STEP): run(Vector2(target[0]-currentPosition[0], target[1]-currentPosition[1]), delta*4) targetFieldCur = target targetFieldUsed = true ai_movement_state = STEP - elif(MoveAdvice[0]==ROLL): + elif(kindOfStep==ROLL): roll(Vector2(target[0]-currentPosition[0], target[1]-currentPosition[1]), delta*4) targetFieldCur = target targetFieldUsed = true - ExecutionState = EXECUTING + ExecutionState = EXECUTING + + + +func movement_execution(delta): + var currentPixel = global_position + var hitPixelTarget = is_hittable() + + if hitPixelTarget!=null: + hit_or_miss(hitPixelTarget, currentPixel, delta*4) + return + + if(targetFieldUsed): + var cur = grid._pixel_to_grid_coords(global_position) + var distance = sqrt(pow(cur[0]-targetFieldCur[0],2)+ pow(cur[1]-targetFieldCur[1],2)) + if(distance<0.1): + targetFieldUsed = false + ExecutionState = AI_MOVE + var actionField = grid.get_nearest(cur, actionKind) + if(targetFieldCur[0]==actionField[0]&&targetFieldCur[1]==actionField[1]): + actionFieldUsed = false + else: + var currentPosition = grid._pixel_to_grid_coords(global_position) + if(ai_movement_state==STEP): + run(Vector2(targetFieldCur[0]-currentPosition[0], targetFieldCur[1]-currentPosition[1]), delta*4) + elif(ai_movement_state==ROLL): + run(Vector2(targetFieldCur[0]-currentPosition[0], targetFieldCur[1]-currentPosition[1]), delta*4) + + +func reset_exeution_state(delta): + threadDelta = threadDelta + delta + if(threadDelta>threadTime): + ExecutionState = AI_MOVE + actionFieldUsed = false + + + +func makeMove(delta): + if ExecutionState == AI_MOVE: + threadDelta = 0 + var MoveAdvice = movement_calulcaotr() + if(MoveAdvice==null): + return + var target = MoveAdvice[1] + movement_decider_ai(target, MoveAdvice[0], delta) elif ExecutionState == EXECUTING: - if(targetFieldUsed): - var cur = grid._pixel_to_grid_coords(global_position) - var distance = sqrt(pow(cur[0]-targetFieldCur[0],2)+ pow(cur[1]-targetFieldCur[1],2)) - if(distance<0.4): - targetFieldUsed = false - ExecutionState = AI_MOVE - if(targetFieldCur[0]==actionField[0]&&targetFieldCur[1]==actionField[1]): - actionFieldUsed = false - else: - var currentPosition = grid._pixel_to_grid_coords(global_position) - if(ai_movement_state==STEP): - run(Vector2(targetFieldCur[0]-currentPosition[0], targetFieldCur[1]-currentPosition[1]), delta*4) - elif(ai_movement_state==ROLL): - run(Vector2(targetFieldCur[0]-currentPosition[0], targetFieldCur[1]-currentPosition[1]), delta*4) - threadDelta = threadDelta + delta - if(threadDelta>threadTime): - ExecutionState = AI_MOVE - actionFieldUsed = false + movement_execution(delta) + reset_exeution_state(delta) + # API Interface for ai_hero -> methods are handled in player.gd func attac(direction, delta): @@ -333,3 +345,5 @@ func roll(direction, delta): func run(direction, delta): pass + +#todo diff --git a/src/Overlap/AI/AI_Minion.gd b/src/Overlap/AI/AI_Minion.gd new file mode 100644 index 0000000..e2acc53 --- /dev/null +++ b/src/Overlap/AI/AI_Minion.gd @@ -0,0 +1,265 @@ +extends KinematicBody2D + +class_name Minion + +const PrioQueue = preload("prio_queue.gd") # Relative path +const Grid = preload("res://Maps/Grid.gd") + +var grid + +enum{ + STEP, + NOTHING +} + +enum{ + EXECUTING, + AI_MOVE +} + +var ExecutionState = AI_MOVE +var ai_movement_state = NOTHING + +var numbers = [0,0,0,0,0,0,0,0,0,0] +var prios = [0,6,0,0,0,0,0,0,4,0] + + +var targetFieldCur = [0,0] +var targetFieldUsed = false + +var actionKind = Grid.Kind.TERMINAL_SYMBOL +var actionFieldUsed = false + +var threadTime = 0.4 +var threadDelta = 0.0 + +#calculates the sum of all present prios +func calcTotalPrio(): + var sum = 0 + var i = Grid.Kind.BOSS + while i != Grid.Kind.TERMINAL_SYMBOL: + if(numbers[i]>0): + sum += prios[i] + i += 1 + return sum + +#calculates the relative porio +func calcRelPrio(index, sum) -> float: + if(sum==0): + return 0.0 + return float(prios[index])/float(sum) + +#calucaltes the prio table of all enemies[0,1) +func calcPrioTable(): + var table = [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0] + numbers = grid.countTargets(numbers) + var lower = 0.0 + var sum = calcTotalPrio() + + var i = 0; + while i != Grid.Kind.TERMINAL_SYMBOL: + if(numbers[i]!=0): + lower += calcRelPrio(i, sum) + table[i] = lower + i += 1 + + return table + +#14+7 0.999 +#updates heart and bonfire prio +func adjustPrio(currentHealth, maxHealth): + return + +#return the enemie which will be attacked +func calcEnemyKind(): + var table = calcPrioTable() + var number = randf() + var i = 0 + while i!=Grid.Kind.TERMINAL_SYMBOL and table[i] <= number: + i += 1 + return i + +#returns a move +func getMoveDescription(myPosition : Vector2, targetPositions): + return AStar(myPosition, targetPositions) + + +func getCost(field): + return 0 + +#return an heurestic of distance +# curr - current position +# targ - a target position +func h_fn(curr, target): + return sqrt(pow(target[0]-curr[0],2)+pow(target[0]-curr[0],2)) + +# currCost - currentCost +# target - position of the field to move to +func g_fn(currCost, target): + return currCost + getCost(target) + +# Returns the list of adjacent nodes +func adjacent(currentPosition, can_roll = false): + var adj := [] + #adj.append([STEP, Vector2(0,0)]) + var p = currentPosition + var pot_adj_step = [[p[0]-1, p[1]-1], [p[0]-1, p[1]-0], [p[0]-1, p[1]+1], + [p[0]+0, p[1]-1], [p[0]+0, p[1]+1], + [p[0]+1, p[1]-1], [p[0]+1, p[1]+0], [p[0]+1, p[1]+1]] + + + for i in range(pot_adj_step.size()): + var next = pot_adj_step[i] + if(next[0]<0): + continue + if(next[0]>13): + continue + if(next[1]<0): + continue + if(next[1]>6): + continue + if(grid.used_grid[next[0]][next[1]]): + continue + if(grid.object_grid[next[0]][next[1]][0]!=Grid.Kind.WALL): + if(i==0): + if(grid.object_grid[pot_adj_step[1][0]][pot_adj_step[1][1]][0]!=Grid.Kind.WALL && + grid.object_grid[pot_adj_step[3][0]][pot_adj_step[3][1]][0]!=Grid.Kind.WALL): + adj.append([STEP, Vector2(next[0],next[1]),1.1]) + continue + if(i==2): + if(grid.object_grid[pot_adj_step[1][0]][pot_adj_step[1][1]][0]!=Grid.Kind.WALL && + grid.object_grid[pot_adj_step[4][0]][pot_adj_step[4][1]][0]!=Grid.Kind.WALL): + adj.append([STEP, Vector2(next[0],next[1]),1.1]) + continue + if(i==5): + if(grid.object_grid[pot_adj_step[3][0]][pot_adj_step[3][1]][0]!=Grid.Kind.WALL && + grid.object_grid[pot_adj_step[6][0]][pot_adj_step[6][1]][0]!=Grid.Kind.WALL): + adj.append([STEP, Vector2(next[0],next[1]),1.1]) + continue + if(i==7): + if(grid.object_grid[pot_adj_step[4][0]][pot_adj_step[4][1]][0]!=Grid.Kind.WALL && + grid.object_grid[pot_adj_step[6][0]][pot_adj_step[6][1]][0]!=Grid.Kind.WALL): + adj.append([STEP, Vector2(next[0],next[1]),1.1]) + continue + + adj.append([STEP, Vector2(next[0],next[1]),1.0]) + + return adj + + +func AStar(source, target): + #swap rtarget and source, when target source istr reached, do inversxse step + # node layout [g+h(x), g(x), current, from, kind] + var tmp = source + source = target + target = tmp + + var Q = PrioQueue.new() + Q.insert([0,0, [source[0], source[1]], [source[0], source[1]], NOTHING] ) + while !Q.empty(): + var node = Q.delMin() + + # Check if reached + if(node[2][0] == target[0] and node[2][1] == target[1]): + return [node[4], node[3]] # 4 is kind | 3 is from + + # Set flag + grid.used_grid[node[2][0]][node[2][1]] = true + var adj_list = adjacent(node[2]) + for i in adj_list: + var move_cost = i[2] + + var g_val = g_fn(node[1]+move_cost, i[1]) + var h_val = h_fn(i[1], target) + + #[g+h(x), g(x), current, from, kind] + var new_node = [g_val+h_val, g_val,i[1], node[2], i[0]] + Q.insert(new_node) + + return [NOTHING, [0,0]] + + +func movement_calulcaotr(): + var currentPosition = grid._pixel_to_grid_coords(global_position) + + var enemyKind + if(actionFieldUsed==false): + enemyKind = calcEnemyKind() + actionKind = enemyKind + actionFieldUsed = true + else: + enemyKind = actionKind + + if(enemyKind==Grid.Kind.TERMINAL_SYMBOL): + return + + var targetField = grid.get_nearest(currentPosition, enemyKind) + if(targetField==[-1,-1]): + return + + + var MoveAdvice = getMoveDescription(currentPosition, targetField) + grid.reset_history() + + return MoveAdvice + + +func movement_decider_ai(target, kindOfStep, delta): + var currentPosition = grid._pixel_to_grid_coords(global_position) + var field_of_movement = target + var currentPixel = global_position + + if(kindOfStep==STEP): + run(Vector2(target[0]-currentPosition[0], target[1]-currentPosition[1]), delta*4) + targetFieldCur = target + targetFieldUsed = true + ai_movement_state = STEP + + ExecutionState = EXECUTING + + + +func movement_execution(delta): + if(targetFieldUsed): + var cur = grid._pixel_to_grid_coords(global_position) + var distance = sqrt(pow(cur[0]-targetFieldCur[0],2)+ pow(cur[1]-targetFieldCur[1],2)) + if(distance<0.1): + targetFieldUsed = false + ExecutionState = AI_MOVE + var actionField = grid.get_nearest(cur, actionKind) + if(targetFieldCur[0]==actionField[0]&&targetFieldCur[1]==actionField[1]): + actionFieldUsed = false + else: + var currentPosition = grid._pixel_to_grid_coords(global_position) + if(ai_movement_state==STEP): + run(Vector2(targetFieldCur[0]-currentPosition[0], targetFieldCur[1]-currentPosition[1]), delta*4) + + +func reset_exeution_state(delta): + threadDelta = threadDelta + delta + if(threadDelta>threadTime): + ExecutionState = AI_MOVE + actionFieldUsed = false + + + +func makeMove(delta): + if ExecutionState == AI_MOVE: + threadDelta = 0 + var MoveAdvice = movement_calulcaotr() + if(MoveAdvice==null): + return + var target = MoveAdvice[1] + movement_decider_ai(target, MoveAdvice[0], delta) + + elif ExecutionState == EXECUTING: + movement_execution(delta) + reset_exeution_state(delta) + + +# API Interface for ai_hero -> methods are handled in player.gd + +func run(direction, delta): + pass + +#todo diff --git a/src/Player/Player.gd b/src/Player/Player.gd index 176cbd7..2abd01c 100644 --- a/src/Player/Player.gd +++ b/src/Player/Player.gd @@ -4,7 +4,7 @@ class_name Player This is an example player controller script created by Paul """ var velocity := Vector2.ZERO -var rollvector := Vector2.ZERO +var rollvector := Vector2(-1,0) # This is how you export variables with ranges to the editor window export(bool) var debug := false @@ -77,7 +77,7 @@ func _physics_process(delta): elif movementState == moveState.IDLE: movement_idle() else: - movement_run(Vector2(0,0), delta) + movement_run(Vector2.ZERO, delta) makeMove(delta) move() $"Effects/HealEffect".emitting = heal_per_second > 0 @@ -148,8 +148,11 @@ func movement_hit(): func hit_finished(): + grid._update_grid() movementState = moveState.IDLE - ExecutionState = AI_MOVE + ai_movement_state = STEP + ExecutionState = EXECUTING + actionFieldUsed = false func movement_roll(): @@ -174,21 +177,23 @@ func roll_finished(): func _on_Hurtbox_area_entered(area): - if area.is_in_group("hitbox"): - player_stats.health -= area.damage - - if area.damage > 0: - damage_per_second += area.damage - else: - heal_per_second += abs(area.damage) + player_stats.health -= area.damage + + if area.damage > 0: + damage_per_second += area.damage + pass + else: + heal_per_second += abs(area.damage) + pass func _on_Hurtbox_area_exited(area): - if area.is_in_group("hitbox"): - if area.damage > 0: - damage_per_second -= area.damage - else: - heal_per_second -= abs(area.damage) + if area.damage > 0: + damage_per_second -= area.damage + pass + else: + heal_per_second -= abs(area.damage) + pass func _on_Stats_no_health(): @@ -209,4 +214,14 @@ func movement_run(direction, delta): func movement_idle(): movementState = moveState.IDLE velocity = Vector2.ZERO - animation_state.change_scene("idle") + animation_state.change_state("idle") + + +func _on_SwordRange_area_entered(area): + if(area.is_in_group("HittableByPlayer")): + areaRefList.push_back(area.get_instance_id()) + + +func _on_SwordRange_area_exited(area): + if(area.is_in_group("HittableByPlayer")): + areaRefList.erase(area.get_instance_id()) diff --git a/src/Player/Player.tscn b/src/Player/Player.tscn index 553af83..b35f873 100644 --- a/src/Player/Player.tscn +++ b/src/Player/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=63 format=2] +[gd_scene load_steps=64 format=2] [ext_resource path="res://Player/Player.gd" type="Script" id=1] [ext_resource path="res://Player/player.png" type="Texture" id=2] @@ -617,17 +617,23 @@ height = 0.2 [sub_resource type="CapsuleShape2D" id=48] radius = 4.03497 -height = 6.99104 +height = 9.42006 -[sub_resource type="DynamicFont" id=49] +[sub_resource type="CircleShape2D" id=51] +radius = 13.3924 + +[sub_resource type="DynamicFont" id=50] size = 12 font_data = ExtResource( 6 ) + [node name="Player" type="KinematicBody2D" groups=[ "hero", ]] collision_mask = 14 + script = ExtResource( 1 ) +ROLL_SPEED = 120 FRICTION = 270 [node name="Kind" parent="." instance=ExtResource( 7 )] @@ -693,7 +699,7 @@ position = Vector2( 1.90735e-06, 0.000833988 ) shape = SubResource( 47 ) [node name="Pivot" type="Position2D" parent="."] -position = Vector2( 0, -4.16248 ) +position = Vector2( 0, -4 ) rotation = 3.14159 __meta__ = { "_gizmo_extents_": 20.0 @@ -701,19 +707,31 @@ __meta__ = { [node name="SwordHitbox" parent="Pivot" instance=ExtResource( 4 )] collision_layer = 0 -collision_mask = 12 +collision_mask = 76 [node name="CollisionShape2D" parent="Pivot/SwordHitbox" index="0"] position = Vector2( 8.43416, 0.0698299 ) shape = SubResource( 48 ) disabled = true +[node name="SwordRange" parent="Pivot" instance=ExtResource( 4 )] +position = Vector2( 1.15451e-05, -4.16248 ) +rotation = -3.14159 +scale = Vector2( 0.909091, 0.909091 ) +collision_layer = 128 +collision_mask = 0 +damage = 0.0 + +[node name="CollisionShape2D" parent="Pivot/SwordRange" index="0"] +position = Vector2( 0, -4.56405 ) +shape = SubResource( 51 ) + [node name="DebugLabel" type="Label" parent="."] -margin_left = -8.01196 -margin_top = -21.2223 -margin_right = 8.98804 -margin_bottom = -9.22228 -custom_fonts/font = SubResource( 49 ) +margin_left = -8.12021 +margin_top = -21.9801 +margin_right = 12.8798 +margin_bottom = -9.98004 +custom_fonts/font = SubResource( 50 ) text = "Held" __meta__ = { "_edit_use_anchors_": false @@ -747,6 +765,8 @@ emitting = false [connection signal="area_entered" from="Hitbox" to="." method="_on_Hitbox_area_entered"] [connection signal="area_entered" from="Hurtbox" to="." method="_on_Hurtbox_area_entered"] [connection signal="area_exited" from="Hurtbox" to="." method="_on_Hurtbox_area_exited"] +[connection signal="area_entered" from="Pivot/SwordRange" to="." method="_on_SwordRange_area_entered"] +[connection signal="area_exited" from="Pivot/SwordRange" to="." method="_on_SwordRange_area_exited"] [connection signal="no_health" from="Stats" to="." method="_on_Stats_no_health"] [editable path="Hitbox"] @@ -754,3 +774,5 @@ emitting = false [editable path="Hurtbox"] [editable path="Pivot/SwordHitbox"] + +[editable path="Pivot/SwordRange"] diff --git a/src/World.tscn b/src/World.tscn index 15e1d5b..3ad40f5 100644 --- a/src/World.tscn +++ b/src/World.tscn @@ -1,3 +1,4 @@ + [gd_scene load_steps=13 format=2] [ext_resource path="res://Player/Player.tscn" type="PackedScene" id=1] @@ -6,18 +7,22 @@ [ext_resource path="res://testSprites/dark.png" type="Texture" id=4] [ext_resource path="res://Menus/DragNDrop/DragNDropUI.tscn" type="PackedScene" id=5] [ext_resource path="res://Menus/DialogueBox/DialogueBox.tscn" type="PackedScene" id=6] + [ext_resource path="res://Maps/Background/Background.tscn" type="PackedScene" id=7] [ext_resource path="res://Boss/SlimeBoss/SlimeBoss.tscn" type="PackedScene" id=8] [ext_resource path="res://Debug/BossStateDisplay.gd" type="Script" id=9] [ext_resource path="res://Objects/Bonfire/Bonfire.tscn" type="PackedScene" id=10] [ext_resource path="res://Fonts/Harmonic/Harmonic12.tres" type="DynamicFont" id=11] + [ext_resource path="res://Maps/Grid.tscn" type="PackedScene" id=18] +[sub_resource type="AnimationNodeStateMachinePlayback" id=1] + [node name="World" type="Node2D"] script = ExtResource( 2 ) [node name="WallSprite" type="Sprite" parent="."] -position = Vector2( 355.382, 175.62 ) +position = Vector2( 360, 176 ) texture = ExtResource( 4 ) region_enabled = true region_rect = Rect2( 0, 0, 1280, 720 ) @@ -33,6 +38,7 @@ cell_size = Vector2( 32, 32 ) collision_layer = 2 collision_mask = 0 format = 1 + tile_data = PoolIntArray( -1, -1610612689, 4, -65536, -1610612689, 196609, -65535, -1610612689, 196609, -65534, -1610612689, 196609, -65533, -1610612689, 196609, -65532, -1610612689, 196609, -65531, -1610612689, 196609, -65530, -1610612689, 196609, -65529, -1610612689, 196609, -65528, -1610612689, 196609, -65527, -1610612689, 196609, -65526, -1610612689, 196609, -65525, -1610612689, 196609, -65524, -1610612689, 196609, -65523, -1610612689, 196610, -65522, -1610612720, 131073, 65535, -1610612689, 65539, 14, -1610612689, 3, 131071, 47, 65539, 65550, -1610612689, 65539, 196607, 47, 65539, 131086, -1610612689, 65539, 262143, 47, 65539, 196622, -1610612689, 65539, 327679, 47, 65539, 262158, -1610612689, 65539, 393215, 47, 65539, 327694, -1610612689, 65539, 458751, -1610612689, 131076, 393216, -1610612689, 1, 393217, -1610612689, 1, 393218, -1610612689, 1, 393219, -1610612689, 1, 393220, -1610612689, 1, 393221, -1610612689, 1, 393222, -1610612689, 1, 393223, -1610612689, 1, 393224, -1610612689, 1, 393225, -1610612689, 1, 393226, -1610612689, 1, 393227, -1610612689, 1, 393228, -1610612689, 1, 393229, -1610612689, 1, 393230, -1610612689, 131079, 524287, -1610612689, 131072, 458752, 47, 131073, 458753, 47, 131073, 458754, 47, 131073, 458755, 47, 131073, 458756, 47, 131073, 458757, 47, 131073, 458758, 47, 131073, 458759, 47, 131073, 458760, 47, 131073, 458761, 47, 131073, 458762, 47, 131073, 458763, 47, 131073, 458764, 47, 131073, 458765, 47, 131073, 458766, -1610612689, 131074 ) __meta__ = { "_edit_group_": true, @@ -41,6 +47,7 @@ __meta__ = { [node name="YSort" type="YSort" parent="."] + [node name="Bonfire" parent="YSort" instance=ExtResource( 10 )] position = Vector2( 265.543, -16 ) @@ -62,50 +69,4 @@ position = Vector2( 104, 80 ) visible = false [node name="DragNDropUI" parent="CanvasLayer" instance=ExtResource( 5 )] -margin_top = -0.735092 -margin_bottom = -0.735107 -ObjectParent = NodePath("../../YSort") -[node name="DebugInterface" type="Control" parent="CanvasLayer"] -anchor_right = 1.0 -anchor_bottom = 1.0 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="BossStateDisplay" type="Panel" parent="CanvasLayer/DebugInterface"] -anchor_left = 1.0 -anchor_right = 1.0 -margin_left = -80.0 -margin_bottom = 60.0 -script = ExtResource( 9 ) - -[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/DebugInterface/BossStateDisplay"] -margin_right = 40.0 -margin_bottom = 40.0 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Title" type="Label" parent="CanvasLayer/DebugInterface/BossStateDisplay/VBoxContainer"] -margin_right = 40.0 -margin_bottom = 12.0 -custom_fonts/font = ExtResource( 11 ) -text = "Boss" -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Phase" type="Label" parent="CanvasLayer/DebugInterface/BossStateDisplay/VBoxContainer"] -margin_top = 16.0 -margin_right = 40.0 -margin_bottom = 28.0 -custom_fonts/font = ExtResource( 11 ) - -[node name="State" type="Label" parent="CanvasLayer/DebugInterface/BossStateDisplay/VBoxContainer"] -margin_top = 32.0 -margin_right = 40.0 -margin_bottom = 44.0 -custom_fonts/font = ExtResource( 11 ) -[connection signal="phase_changed" from="YSort/SlimeBoss" to="CanvasLayer/DebugInterface/BossStateDisplay" method="_on_SlimeBoss_phase_changed"] -[connection signal="state_changed" from="YSort/SlimeBoss" to="CanvasLayer/DebugInterface/BossStateDisplay" method="_on_SlimeBoss_state_changed"] diff --git a/src/project.godot b/src/project.godot index 4492c03..88cddfa 100644 --- a/src/project.godot +++ b/src/project.godot @@ -24,6 +24,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Overlap/AI/AI_Hero.gd" }, { +"base": "KinematicBody2D", +"class": "Minion", +"language": "GDScript", +"path": "res://Overlap/AI/AI_Minion.gd" +}, { "base": "Hero", "class": "Player", "language": "GDScript", @@ -43,6 +48,7 @@ _global_script_class_icons={ "Boss": "", "DialougeBox": "", "Hero": "", +"Minion": "", "Player": "", "TitleSceenButton": "", "TitleScreen": "" @@ -142,6 +148,8 @@ attack={ 2d_physics/layer_4="monster" 2d_physics/layer_5="trap" 2d_physics/layer_6="collectable" +2d_physics/layer_7="Bonfire" +2d_physics/layer_8="SwordRange" [rendering] diff --git a/src/testSprites/white_minion_dog.png b/src/testSprites/white_minion_dog.png new file mode 100644 index 0000000..5d01d9a Binary files /dev/null and b/src/testSprites/white_minion_dog.png differ diff --git a/src/testSprites/white_minion_dog.png.import b/src/testSprites/white_minion_dog.png.import new file mode 100644 index 0000000..2a2fd2a --- /dev/null +++ b/src/testSprites/white_minion_dog.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/white_minion_dog.png-4b59df758535e1f8bd50b861a164b220.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://testSprites/white_minion_dog.png" +dest_files=[ "res://.import/white_minion_dog.png-4b59df758535e1f8bd50b861a164b220.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=false +svg/scale=1.0