From 1cb3d6c4264e5780fe7f627bd41e1d11793a5272 Mon Sep 17 00:00:00 2001 From: OddlyTimbot Date: Mon, 27 Jul 2026 21:12:26 -0400 Subject: [PATCH] enemies and lots stuff --- assets/enemies/slime/slime_purple.png | Bin 0 -> 1030 bytes assets/enemies/slime/slime_purple.png.import | 40 ++++++ assets/player/dead/Player Death 64x64.png | Bin 0 -> 1584 bytes .../player/dead/Player Death 64x64.png.import | 40 ++++++ assets/player/hurt/Player Hurt 48x48.png | Bin 0 -> 1448 bytes .../player/hurt/Player Hurt 48x48.png.import | 40 ++++++ project.godot | 4 + scenes/bullet.tscn | 1 + scenes/game.tscn | 13 +- scenes/player.tscn | 118 +++++++++++++++++- scenes/slime.tscn | 74 +++++++++++ scripts/bullet.gd | 2 +- scripts/game.gd | 55 +++++++- scripts/player.gd | 31 +++-- scripts/rscs/characterstats.gd | 9 ++ scripts/rscs/characterstats.gd.uid | 1 + scripts/rscs/playerStats.tres | 10 ++ scripts/rscs/slimeStats.tres | 11 ++ scripts/scene_manager.gd | 39 ++++-- scripts/slime.gd | 31 +++++ scripts/slime.gd.uid | 1 + 21 files changed, 490 insertions(+), 30 deletions(-) create mode 100644 assets/enemies/slime/slime_purple.png create mode 100644 assets/enemies/slime/slime_purple.png.import create mode 100644 assets/player/dead/Player Death 64x64.png create mode 100644 assets/player/dead/Player Death 64x64.png.import create mode 100644 assets/player/hurt/Player Hurt 48x48.png create mode 100644 assets/player/hurt/Player Hurt 48x48.png.import create mode 100644 scenes/slime.tscn create mode 100644 scripts/rscs/characterstats.gd create mode 100644 scripts/rscs/characterstats.gd.uid create mode 100644 scripts/rscs/playerStats.tres create mode 100644 scripts/rscs/slimeStats.tres create mode 100644 scripts/slime.gd create mode 100644 scripts/slime.gd.uid diff --git a/assets/enemies/slime/slime_purple.png b/assets/enemies/slime/slime_purple.png new file mode 100644 index 0000000000000000000000000000000000000000..76f564e1d18d3f4b59c032ee8233ebf4665af431 GIT binary patch literal 1030 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 void: func _on_body_entered(body: Node2D) -> void: - if body is Crate: + if body.is_in_group("shootable"): bulletHitSignal.emit(body,self) diff --git a/scripts/game.gd b/scripts/game.gd index b5000e8..3947151 100644 --- a/scripts/game.gd +++ b/scripts/game.gd @@ -2,14 +2,33 @@ class_name GameController extends Node2D signal destroySignal(body) signal fanTriggerSignal(body, fanDirection) signal teleportTriggerSignal(body) +signal playerHurtSignal(playerHealth, maxHealth) +signal playerDeadSignal + var numberOfCrates = 2 var timeAvailable = 50 var totalCoinsCollected = 0 var timer = Timer.new() + +var currentPlayerHealth = 100 +var startingHealth = 100 + +var enemiesDict={} + +var enemy:CharacterStats +var player:CharacterStats + +func reset()->void: + print("GC reset") + currentPlayerHealth=player.startingHealth + # Called when the node enters the scene tree for the first time. func _ready() -> void: get_window().grab_focus() + enemy = load("res://scripts/rscs/slimeStats.tres") + player = load("res://scripts/rscs/playerStats.tres") + add_child(timer) timer.wait_time = 1 timer.one_shot = false @@ -21,7 +40,7 @@ func countdown()->void: timeAvailable-=1 if timeAvailable<=0 and numberOfCrates>0: print("LOOOOOSAH") - get_tree().reload_current_scene() + playerDeadSignal.emit() # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: @@ -51,15 +70,45 @@ func coinCollected(body,coin)->void: totalCoinsCollected +=1 print("GC knows coin collected") destroySignal.emit(coin) + func coinTotal(totalAmount)->void: print("GC knows total coins "+str(totalAmount)) func bulletDamage(body, _bullet)->void: if body.is_in_group("shootable"): - destroySignal.emit(body) - destroySignal.emit(_bullet) + if body is Crate: + destroySignal.emit(body) + destroySignal.emit(_bullet) + if body is Slime: + enemiesDict[body]["health"] -= player.rangeDamage + if enemiesDict[body]["health"]<=0: + enemiesDict.erase(body) + destroySignal.emit(body) + destroySignal.emit(_bullet) func rocketDamage(body, rocket)->void: if body.is_in_group("shootable"): print("Rocket strikes target!") destroySignal.emit(body) + +func totalEnemies(numberOfEnemies)->void: + print("GC knows this many badguy: "+str(numberOfEnemies)) +func slimeAttack(body,slime)->void: + print("GC knows slime attack "+str(enemiesDict[slime]["damage"])) + currentPlayerHealth -= enemiesDict[slime]["damage"] + if currentPlayerHealth>0: + #damage + print("player damaged") + playerHurtSignal.emit(currentPlayerHealth, startingHealth) + else: + #ded + print("player ded") + playerDeadSignal.emit() +func levelChange()->void: + get_tree().reload_current_scene() +func addEnemyToLevel(slime)->void: + var stats = { + "health": enemy.startingHealth, + "damage": enemy.meleeDamage + } + enemiesDict[slime]=stats diff --git a/scripts/player.gd b/scripts/player.gd index 28e5195..4ed8479 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -2,6 +2,7 @@ class_name Player extends CharacterBody2D signal pushSignal(body, direction) signal shootSignal(markerPosition, speed) signal fireSignal(markerPosition, direction, speed) +signal deathAnimationCompleteSignal @onready var right_cast: RayCast2D = $RightCast @onready var left_cast: RayCast2D = $LeftCast @onready var right_spawn: Marker2D = $RightSpawn @@ -19,18 +20,24 @@ const JUMP_VELOCITY = -400.0 enum FaceDirection {RIGHT,LEFT} var facing:FaceDirection = FaceDirection.RIGHT -enum PlayerStates {IDLE,RUNNING,JUMPING,FALLING,CHARGING,SHOVING} +enum PlayerStates {IDLE,RUNNING,JUMPING,FALLING,CHARGING,SHOVING,HURT,DEAD} var current_player_state:PlayerStates = PlayerStates.IDLE var upJump:bool = false func _physics_process(delta: float) -> void: - handle_input() + if current_player_state != PlayerStates.DEAD: + handle_input() handle_movement(delta) handle_states() handle_animation() move_and_slide() handle_collisions() - + +func hurt(playerHealth,maxHealth)->void: + current_player_state = PlayerStates.HURT +func kill()->void: + current_player_state = PlayerStates.DEAD + func handle_input()->void: # Handle jump. if Input.is_action_just_pressed("ui_accept") and is_on_floor(): @@ -39,7 +46,7 @@ func handle_input()->void: upJump = true # Handle shove. if Input.is_action_just_pressed("shove"): - print("I want to shove") + if pushRightEnabled and facing==FaceDirection.RIGHT: current_player_state= PlayerStates.CHARGING pushTimer = Time.get_ticks_msec() @@ -60,7 +67,7 @@ func handle_input()->void: current_player_state = PlayerStates.SHOVING #Handle Shoot Bullet if Input.is_action_just_pressed("shoot"): - print("Ima shoot a bullet") + #marker postion, speed match facing: FaceDirection.RIGHT: @@ -69,7 +76,7 @@ func handle_input()->void: shootSignal.emit(left_spawn.global_transform, -800) #Handle fire rocket if Input.is_action_just_pressed("fire"): - print("Ima fire rocket") + match facing: FaceDirection.RIGHT: fireSignal.emit(right_spawn.global_transform,Vector2(1,0), 800) @@ -95,7 +102,7 @@ func handle_movement(delta)->void: velocity += get_gravity() * delta func handle_collisions()->void: if right_cast.is_colliding(): - print("Right raycast collision") + var collider = right_cast.get_collider() if collider is Node: pushRightEnabled = true @@ -104,7 +111,7 @@ func handle_collisions()->void: pushRightEnabled = false if left_cast.is_colliding(): - print("Left raycast collision") + var collider = left_cast.get_collider() if collider is Node: pushLeftEnabled = true @@ -148,6 +155,10 @@ func handle_animation()->void: player_graphic.play("charging") PlayerStates.SHOVING: player_graphic.play("shoving") + PlayerStates.HURT: + player_graphic.play("hurt") + PlayerStates.DEAD: + player_graphic.play("dying") func _on_animation_finished() -> void: @@ -156,3 +167,7 @@ func _on_animation_finished() -> void: upJump = false PlayerStates.SHOVING: current_player_state = PlayerStates.IDLE + PlayerStates.HURT: + current_player_state = PlayerStates.IDLE + PlayerStates.DEAD: + deathAnimationCompleteSignal.emit() diff --git a/scripts/rscs/characterstats.gd b/scripts/rscs/characterstats.gd new file mode 100644 index 0000000..02696e6 --- /dev/null +++ b/scripts/rscs/characterstats.gd @@ -0,0 +1,9 @@ +class_name CharacterStats extends Resource + +@export var currentHealth := 100 +@export var maxHealth := 150 +@export var startingHealth:int = 100 + +#damage +@export var meleeDamage:int = 20 +@export var rangeDamage:int = 15 diff --git a/scripts/rscs/characterstats.gd.uid b/scripts/rscs/characterstats.gd.uid new file mode 100644 index 0000000..d92af08 --- /dev/null +++ b/scripts/rscs/characterstats.gd.uid @@ -0,0 +1 @@ +uid://cye1467wwip7u diff --git a/scripts/rscs/playerStats.tres b/scripts/rscs/playerStats.tres new file mode 100644 index 0000000..7559b20 --- /dev/null +++ b/scripts/rscs/playerStats.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="CharacterStats" format=3 uid="uid://dt55hoe718r1x"] + +[ext_resource type="Script" uid="uid://cye1467wwip7u" path="res://scripts/rscs/characterstats.gd" id="1_sqkfu"] + +[resource] +script = ExtResource("1_sqkfu") +maxHealth = 200 +meleeDamage = 30 +rangeDamage = 20 +metadata/_custom_type_script = "uid://cye1467wwip7u" diff --git a/scripts/rscs/slimeStats.tres b/scripts/rscs/slimeStats.tres new file mode 100644 index 0000000..8ff5dcd --- /dev/null +++ b/scripts/rscs/slimeStats.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="CharacterStats" format=3 uid="uid://c0ghdtxe11f0"] + +[ext_resource type="Script" uid="uid://cye1467wwip7u" path="res://scripts/rscs/characterstats.gd" id="1_ppipo"] + +[resource] +script = ExtResource("1_ppipo") +currentHealth = 60 +maxHealth = 80 +startingHealth = 60 +rangeDamage = 0 +metadata/_custom_type_script = "uid://cye1467wwip7u" diff --git a/scripts/scene_manager.gd b/scripts/scene_manager.gd index 4dc3f75..4babeb3 100644 --- a/scripts/scene_manager.gd +++ b/scripts/scene_manager.gd @@ -1,9 +1,10 @@ extends Node2D -@onready var game: GameController = $".." + @onready var crates: Node2D = $"../Crates" @onready var player: Player = $"../Player" @onready var coin: Coin = $"../Coins/Coin" @onready var coins: Node2D = $"../Coins" +@onready var enemies: Node2D = $"../Enemies" var bullet = preload("res://scenes/bullet.tscn") var rocket = preload("res://scenes/rocket.tscn") @@ -15,18 +16,22 @@ var totalAllowedRockets:int = 3 # Called when the node enters the scene tree for the first time. func _ready() -> void: + Gamecontroller.reset() #signals from the view player.pushSignal.connect(pushTarget) player.shootSignal.connect(makeBullet) player.fireSignal.connect(makeRocket) + player.deathAnimationCompleteSignal.connect(Gamecontroller.levelChange) #signals from the GameController - game.destroySignal.connect(destroy) - game.fanTriggerSignal.connect(pushTarget) - game.teleportTriggerSignal.connect(teleportTarget) + Gamecontroller.destroySignal.connect(destroy) + Gamecontroller.fanTriggerSignal.connect(pushTarget) + Gamecontroller.teleportTriggerSignal.connect(teleportTarget) + Gamecontroller.playerHurtSignal.connect(player.hurt) + Gamecontroller.playerDeadSignal.connect(player.kill) #signals from pickups - coin.coinCollectedSignal.connect(game.coinCollected) + coin.coinCollectedSignal.connect(Gamecontroller.coinCollected) buildLevel() @@ -38,6 +43,7 @@ func buildLevel()->void: #tell GC how many crates... updateCrates() updateCoins() + updateEnemies() func updateCrates()->void: var totalCrates = 0 @@ -48,15 +54,28 @@ func updateCrates()->void: obj.tree_exited.connect(updateCrates) totalCrates +=1 - game.crateTotal(totalCrates) + Gamecontroller.crateTotal(totalCrates) func updateCoins()->void: var totalCoins = 0 if coins: for obj in coins.get_children(): if obj is Coin: + if not obj.tree_exited.is_connected(updateCoins): + obj.tree_exited.connect(updateCoins) + if not obj.coinCollectedSignal.is_connected(Gamecontroller.coinCollected): + obj.coinCollectedSignal.connect(Gamecontroller.coinCollected) totalCoins +=1 - game.coinTotal(totalCoins) + Gamecontroller.coinTotal(totalCoins) +func updateEnemies()->void: + var totalEnemies = 0 + if enemies: + for obj in enemies.get_children(): + if obj is Slime: + Gamecontroller.addEnemyToLevel(obj) + obj.slimeDamageSignal.connect(Gamecontroller.slimeAttack) + totalEnemies +=1 + Gamecontroller.totalEnemies(totalEnemies) func pushTarget(body,pushDirection)->void: if body is RigidBody2D: @@ -91,8 +110,8 @@ func bulletFactory()->Bullet: #make a new bullet myBullet = bullet.instantiate() add_sibling(myBullet) - if not myBullet.bulletHitSignal.is_connected(game.bulletDamage): - myBullet.bulletHitSignal.connect(game.bulletDamage) + if not myBullet.bulletHitSignal.is_connected(Gamecontroller.bulletDamage): + myBullet.bulletHitSignal.connect(Gamecontroller.bulletDamage) else: myBullet = bulletArray.pop_back() @@ -119,6 +138,6 @@ func makeRocket(spawnPosition, direction, speed)->void: print("make a rocket") var myRocket:Rocket = rocketFactory() myRocket.splodeSignal.connect(destroy) - myRocket.impactSignal.connect(game.rocketDamage) + myRocket.impactSignal.connect(Gamecontroller.rocketDamage) myRocket.transform = spawnPosition pushTarget(myRocket,direction*speed) diff --git a/scripts/slime.gd b/scripts/slime.gd new file mode 100644 index 0000000..b73bf46 --- /dev/null +++ b/scripts/slime.gd @@ -0,0 +1,31 @@ +class_name Slime extends Area2D +@onready var right_cast: RayCast2D = $RightCast +@onready var right_down_cast: RayCast2D = $RightDownCast +@onready var left_down_cast: RayCast2D = $LeftDownCast +@onready var left_cast: RayCast2D = $LeftCast +@onready var slime_graphic: AnimatedSprite2D = $SlimeGraphic + +signal slimeDamageSignal(body,slime) + +@export var speed:int = 100 +var direction = 1 + +func _process(delta: float) -> void: + if not right_down_cast.is_colliding(): + direction =-1 + slime_graphic.flip_h = true + if not left_down_cast.is_colliding(): + direction = 1 + slime_graphic.flip_h = false + if right_cast.is_colliding() && not right_cast.get_collider() is Player: + direction = -1 + slime_graphic.flip_h = true + if left_cast.is_colliding() && not left_cast.get_collider() is Player: + direction = 1 + slime_graphic.flip_h = false + position.x += direction*speed*delta + + +func _on_body_entered(body: Node2D) -> void: + if body is Player: + slimeDamageSignal.emit(body,self) diff --git a/scripts/slime.gd.uid b/scripts/slime.gd.uid new file mode 100644 index 0000000..4c69c7b --- /dev/null +++ b/scripts/slime.gd.uid @@ -0,0 +1 @@ +uid://d215jspbbgtq6