From a93515f6213e535fcf2d563cd7971adaafca7ec8 Mon Sep 17 00:00:00 2001 From: OddlyTimbot Date: Mon, 26 May 2025 20:57:03 -0400 Subject: [PATCH] custom resources, player damage, bad guy damage, animations, ui --- .../player/death/Player Death 64x64.png | Bin 0 -> 1584 bytes .../death/Player Death 64x64.png.import | 34 ++++++ .../player/hurt/Player Hurt 48x48.png | Bin 0 -> 1448 bytes .../player/hurt/Player Hurt 48x48.png.import | 34 ++++++ scenes/bullet.tscn | 1 + scenes/game.tscn | 11 +- scenes/player.tscn | 114 +++++++++++++++++- scenes/slime.tscn | 38 +++++- scenes/ui.tscn | 46 +++++++ scripts/bullet.gd | 7 +- scripts/gamecontroller.gd | 68 ++++++++--- scripts/player.gd | 19 ++- scripts/res/characterstats.gd | 8 ++ scripts/res/characterstats.gd.uid | 1 + scripts/res/playerstats.tres | 12 ++ scripts/res/slimestats.tres | 12 ++ scripts/scene_manager.gd | 8 +- scripts/slime.gd | 23 +++- scripts/ui.gd | 17 +++ scripts/ui.gd.uid | 1 + 20 files changed, 418 insertions(+), 36 deletions(-) create mode 100644 assets/graphics/player/death/Player Death 64x64.png create mode 100644 assets/graphics/player/death/Player Death 64x64.png.import create mode 100644 assets/graphics/player/hurt/Player Hurt 48x48.png create mode 100644 assets/graphics/player/hurt/Player Hurt 48x48.png.import create mode 100644 scenes/ui.tscn create mode 100644 scripts/res/characterstats.gd create mode 100644 scripts/res/characterstats.gd.uid create mode 100644 scripts/res/playerstats.tres create mode 100644 scripts/res/slimestats.tres create mode 100644 scripts/ui.gd create mode 100644 scripts/ui.gd.uid diff --git a/assets/graphics/player/death/Player Death 64x64.png b/assets/graphics/player/death/Player Death 64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6a1ae0514b237d754893f563c87ba5f95dc109 GIT binary patch literal 1584 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 void: func _on_body_entered(body: Node2D) -> void: if not body is Player: - print("Bullet hit") bulletHit.emit(body, self) + + +func _on_area_entered(area: Area2D) -> void: + if area is Slime: + print("bullet hitting enemy") + bulletHit.emit(area, self) diff --git a/scripts/gamecontroller.gd b/scripts/gamecontroller.gd index a6ab37c..bf23272 100644 --- a/scripts/gamecontroller.gd +++ b/scripts/gamecontroller.gd @@ -6,18 +6,29 @@ var timer = Timer.new() var coinsCollectedTotal := 0 var levels = ["res://scenes/game.tscn","res://scenes/level2.tscn","res://scenes/level3.tscn"] -var timers = [10, 15, 25] +var timers = [50, 15, 25] var currentLevel = 0 var playerHealth = 100 +var player:CharacterStats +var slime:CharacterStats + +var enemiesDict = {} + signal levelCompleteSignal(level) signal destroySignal(body) -signal playerDamage +signal playerDamage(health, maxhealth) signal playerDeath +signal countDown(timeRemaining) +signal coinUpdate(totalCoins) +signal enemyHurt(enemy) # Called when the node enters the scene tree for the first time. func _ready() -> void: + #load custom resource for player and slime + player = load("res://scripts/res/playerstats.tres") + slime = load("res://scripts/res/slimestats.tres") add_child(timer) timer.wait_time = 1 timer.one_shot = false @@ -26,6 +37,8 @@ func _ready() -> void: func secondCounter(): timeLimit -=1 + countDown.emit(timeLimit) + if timeLimit <= 0: #loser!!!! levelCompleteSignal.emit(levels[currentLevel]) @@ -41,39 +54,60 @@ func _process(delta: float) -> void: func _on_trigger_fired(effect: Variant, body: Variant) -> void: - print("Game controller knows :: "+effect) + if effect=="destroy": if body is Crate: - print("Crates Remaining " + str(totalCrates) ) + destroySignal.emit(body) func _on_coin_collected(body, coin): coinsCollectedTotal += 1 + coinUpdate.emit(coinsCollectedTotal) destroySignal.emit(coin) - print("GC knows coin collected") + func _on_player_damage(body, enemy): if enemy is Slime: - print("slime attack!!!") - playerHealth -= 10 + + playerHealth -= enemiesDict[enemy]["damage"] - if playerHealth >0: - print("Player damaged") - playerDamage.emit() - else: - print("Player dead") - playerDeath.emit() + if playerHealth >0: + + playerDamage.emit(playerHealth, player.max_health) + else: + + playerDeath.emit() + +func addEnemyToLevel(enemy): + var randHealth:int = randi() % 20 + var randDamage:int = randi() % 10 + print("randoms "+str(randHealth)+" "+str(randDamage)) + var enemyStat = { + "health": slime.health + randHealth, + "damage": slime.meleeDamage + randDamage + } + enemiesDict[enemy] = enemyStat func numberOfCrates(value): totalCrates = value - print("Total crates at GC: "+str(totalCrates) ) + func bulletDamage(body, bullet): - print("Game controller knows about bullet hit") + + if body is Slime: + enemiesDict[body]["health"] -= player.rangeDamage + #send custom signal + enemyHurt.emit(body) + + if enemiesDict[body]["health"] <= 0: + destroySignal.emit(body) + enemiesDict.erase(body) + func reset(): timeLimit = timers[currentLevel] - playerHealth = 100 + playerHealth = player.starting_health func death(): - print("player death animation complete") + + levelCompleteSignal.emit(levels[currentLevel]) diff --git a/scripts/player.gd b/scripts/player.gd index 62c49ab..f97a6f1 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -18,7 +18,7 @@ const JUMP_VELOCITY = -400.0 @export var acceleration = 15 @export var hard_gravity = 5 -enum State{IDLE, RUN, JUMP, FALLING, MELEE} +enum State{IDLE, RUN, JUMP, FALLING, MELEE, HURT, DEATH} var current_state = State.IDLE enum FaceDirection{LEFT, RIGHT} @@ -31,15 +31,18 @@ var upJump:bool = false signal deathComplete -func _player_damage(): +func _player_damage(_currentHealth, _maxHealth): print("Player taking damage!") + current_state = State.HURT + func _player_death(): print("Player dead!!") + current_state = State.DEATH func _physics_process(delta: float) -> void: - - handle_input() + if current_state != State.HURT and current_state != State.DEATH: + handle_input() update_movement(delta) update_states() update_animation() @@ -136,6 +139,10 @@ func update_animation()->void: player_graphic.play("fall") State.MELEE: player_graphic.play("melee") + State.HURT: + player_graphic.play("hurt") + State.DEATH: + player_graphic.play("death") func handle_collisions()->void: for i in get_slide_collision_count(): @@ -166,3 +173,7 @@ func _on_animation_finished() -> void: upJump = false State.MELEE: current_state = State.IDLE + State.HURT: + current_state = State.IDLE + State.DEATH: + deathComplete.emit() diff --git a/scripts/res/characterstats.gd b/scripts/res/characterstats.gd new file mode 100644 index 0000000..ec435f1 --- /dev/null +++ b/scripts/res/characterstats.gd @@ -0,0 +1,8 @@ +class_name CharacterStats extends Resource + +@export var max_health:int = 100 +@export var starting_health:int = 100 +@export var health:int = 100 + +@export var meleeDamage:int = 10 +@export var rangeDamage:int = 0 diff --git a/scripts/res/characterstats.gd.uid b/scripts/res/characterstats.gd.uid new file mode 100644 index 0000000..d753b92 --- /dev/null +++ b/scripts/res/characterstats.gd.uid @@ -0,0 +1 @@ +uid://da5ofgqbqvfv4 diff --git a/scripts/res/playerstats.tres b/scripts/res/playerstats.tres new file mode 100644 index 0000000..1d5301f --- /dev/null +++ b/scripts/res/playerstats.tres @@ -0,0 +1,12 @@ +[gd_resource type="Resource" script_class="CharacterStats" load_steps=2 format=3 uid="uid://d0evd4qs7p8vx"] + +[ext_resource type="Script" uid="uid://da5ofgqbqvfv4" path="res://scripts/res/characterstats.gd" id="1_4nldt"] + +[resource] +script = ExtResource("1_4nldt") +max_health = 100 +starting_health = 100 +health = 100 +meleeDamage = 10 +rangeDamage = 20 +metadata/_custom_type_script = "uid://da5ofgqbqvfv4" diff --git a/scripts/res/slimestats.tres b/scripts/res/slimestats.tres new file mode 100644 index 0000000..b255650 --- /dev/null +++ b/scripts/res/slimestats.tres @@ -0,0 +1,12 @@ +[gd_resource type="Resource" script_class="CharacterStats" load_steps=2 format=3 uid="uid://cofkrecvkxrlq"] + +[ext_resource type="Script" uid="uid://da5ofgqbqvfv4" path="res://scripts/res/characterstats.gd" id="1_fftob"] + +[resource] +script = ExtResource("1_fftob") +max_health = 50 +starting_health = 50 +health = 50 +meleeDamage = 30 +rangeDamage = 0 +metadata/_custom_type_script = "uid://da5ofgqbqvfv4" diff --git a/scripts/scene_manager.gd b/scripts/scene_manager.gd index 6580bc5..f77bef0 100644 --- a/scripts/scene_manager.gd +++ b/scripts/scene_manager.gd @@ -6,6 +6,7 @@ extends Node @onready var coins: Node2D = $"../coins" @onready var enemies: Node2D = $"../enemies" @onready var player: Player = $"../CharacterBody2D" +@onready var ui: Control = $"../CanvasLayer/ui" var bullet = preload("res://scenes/bullet.tscn") var bulletArray=[] @@ -32,12 +33,17 @@ func buildLevel()->void: for obj in enemies.get_children(): if obj is Slime: obj.playerDamageSignal.connect(Gamecontroller._on_player_damage) + Gamecontroller.enemyHurt.connect(obj.damage) + Gamecontroller.addEnemyToLevel(obj) #Wire up signals Gamecontroller.levelCompleteSignal.connect(loadLevel) Gamecontroller.destroySignal.connect(destroy) Gamecontroller.playerDamage.connect(player._player_damage) + Gamecontroller.playerDamage.connect(ui.healthUpdate) + Gamecontroller.coinUpdate.connect(ui.coinsUpdate) Gamecontroller.playerDeath.connect(player._player_death) + Gamecontroller.countDown.connect(ui.timerUpdate) #player connection player.deathComplete.connect(Gamecontroller.death) @@ -66,7 +72,7 @@ func bulletFactory(): return mybullet func makeBullet(position, speed): - print("Scene manager makes a bullet") + var mybullet = bulletFactory() mybullet.setSpeed(speed) mybullet.transform = position diff --git a/scripts/slime.gd b/scripts/slime.gd index b477401..4ed8d92 100644 --- a/scripts/slime.gd +++ b/scripts/slime.gd @@ -10,15 +10,28 @@ var speed = 100 var direction = 1 func _process(delta: float) -> void: - if not right_down_cast.is_colliding() or right_side_cast.is_colliding(): + if not right_down_cast.is_colliding(): direction = -1 sprite.flip_h = true - if not left_down_cast.is_colliding() or left_side_cast.is_colliding(): + if right_side_cast.is_colliding(): + if not right_side_cast.get_collider() is Player: + direction = -1 + sprite.flip_h = true + + if not left_down_cast.is_colliding(): direction = 1 sprite.flip_h = false - + if left_side_cast.is_colliding(): + if not left_side_cast.get_collider() is Player: + direction = 1 + sprite.flip_h = false + position.x += direction * speed * delta func _on_body_entered(body: Node2D) -> void: - print("Slime Contact") - playerDamageSignal.emit(body, self) + if body is Player: + playerDamageSignal.emit(body, self) + +func damage(body)->void: + if body == self: + sprite.play("hurt") diff --git a/scripts/ui.gd b/scripts/ui.gd new file mode 100644 index 0000000..38f1686 --- /dev/null +++ b/scripts/ui.gd @@ -0,0 +1,17 @@ +extends Control + +@onready var health: Label = $VBoxContainer/HBoxContainer/MarginContainer/health +@onready var timer: Label = $VBoxContainer/HBoxContainer/MarginContainer2/timer +@onready var coins: Label = $VBoxContainer/HBoxContainer/MarginContainer3/coins + +func _ready() -> void: + health.text = "Health 100" + +func healthUpdate(currentHealth, maxHealth): + health.text = "Health"+str(currentHealth) + +func coinsUpdate(amt) -> void: + coins.text = "Coins "+str(amt) + +func timerUpdate(timeRemaining)-> void: + timer.text = str(timeRemaining) diff --git a/scripts/ui.gd.uid b/scripts/ui.gd.uid new file mode 100644 index 0000000..9dc0649 --- /dev/null +++ b/scripts/ui.gd.uid @@ -0,0 +1 @@ +uid://daslx4en4rji1