From 84efe0ff37ce8432ba54d5ed2b1fd3f45897b862 Mon Sep 17 00:00:00 2001 From: Jdevadas Date: Mon, 30 Mar 2026 21:01:43 -0400 Subject: [PATCH] add enemies, autoload, multilevels, coins --- assets/graphics/enemies/slime_green.png | Bin 0 -> 908 bytes .../graphics/enemies/slime_green.png.import | 40 ++ .../environment/terrain/mushroom2.png | Bin 0 -> 2147 bytes .../environment/terrain/mushroom2.png.import | 40 ++ assets/graphics/pickups/coin.png | Bin 0 -> 500 bytes assets/graphics/pickups/coin.png.import | 40 ++ project.godot | 4 + scenes/bullet.tscn | 6 +- scenes/coin.tscn | 114 ++++ scenes/game.tscn | 49 +- scenes/level2.tscn | 498 ++++++++++++++++++ scenes/level3.tscn | 498 ++++++++++++++++++ scenes/player.tscn | 1 + scenes/slime.tscn | 78 +++ scripts/bullet.gd | 4 + scripts/coin.gd | 12 + scripts/coin.gd.uid | 1 + scripts/gameController.gd | 64 ++- scripts/scene_manager.gd | 63 ++- scripts/slime.gd | 34 ++ scripts/slime.gd.uid | 1 + 21 files changed, 1508 insertions(+), 39 deletions(-) create mode 100644 assets/graphics/enemies/slime_green.png create mode 100644 assets/graphics/enemies/slime_green.png.import create mode 100644 assets/graphics/environment/terrain/mushroom2.png create mode 100644 assets/graphics/environment/terrain/mushroom2.png.import create mode 100644 assets/graphics/pickups/coin.png create mode 100644 assets/graphics/pickups/coin.png.import create mode 100644 scenes/coin.tscn create mode 100644 scenes/level2.tscn create mode 100644 scenes/level3.tscn create mode 100644 scenes/slime.tscn create mode 100644 scripts/coin.gd create mode 100644 scripts/coin.gd.uid create mode 100644 scripts/slime.gd create mode 100644 scripts/slime.gd.uid diff --git a/assets/graphics/enemies/slime_green.png b/assets/graphics/enemies/slime_green.png new file mode 100644 index 0000000000000000000000000000000000000000..a21cb6fa253a2142be9bdad248238299dce6e695 GIT binary patch literal 908 zcmeAS@N?(olHy`uVBq!ia0vp^2|(<@!3HEb(?2AGr~;43Vg?3oVGw3ym^DX&fq~i1 z)5S5QV$Rz+)_J!b1lrmiqe6M+oJ(NX&NN4Phv|b`z4{NYP5+>JWrs--17qeTsRD5g z!(g=zZP^CRNrf+-+NH@KR$Td0s&mngVw3+xu0?EXcCBM}?K8i`C}Wk?V1NhZ=gNnL znwH6IezGFZ!~9a6?RHUyhPV4>Uu{?_FnfW>zS{qPKK*<4uVTZ$ce_63>1Q2~5psEW zx_|#J@#X97|9=sRdr@7gG^K>%S{q!=tk;zc{umA757CW^gF~?Y* zzL@Q4_FeSScBuyG05^_0b=8H-_E|RV`0{(oCG+JLF?=tr`x)+BFt>laYl`#E_4#US z^)8yV;ydQc)Lt=IzWv`O|NWa{=kBflzObA3)w^Aa^ZVqko^^cn|Ic5O3*}M*OaJxH zkT2-?mBRcbPJn+~%B^6jY(87p9(Mo#>Q7(h~rm&XFcnS2%Pu(#j4I<=R1EbeZ((y;O5o?wIy5Q|G$2J-k$H; z`tsE}e}z7FZ&xe&&T>;Ie$t&EuHB#RoL~6BudegQ(e6(xj^8Zaa&Il$W#4ySE~~5m zTfmt7%O>)U?6I5hEH)mc^Zy7i2AYE5_cS8+Pd zEL*XBwVBru|99M6hFkZ|y>aAN9DmO}@fM%8>yNRi-8VbG`yY1_&*gmzOfw=rUyaF+ zc6a>UWOJqT@=>+Yz0nhwE57CCn(*tmRI)?YzOxPXujg|0Ui|Qj8JN8oJYD@<);T3K F0RY5^vzq__ literal 0 HcmV?d00001 diff --git a/assets/graphics/enemies/slime_green.png.import b/assets/graphics/enemies/slime_green.png.import new file mode 100644 index 0000000..8160b80 --- /dev/null +++ b/assets/graphics/enemies/slime_green.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c00c0x1qv83o1" +path="res://.godot/imported/slime_green.png-5261ffd1254c816fe62b35227a9aa11d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/enemies/slime_green.png" +dest_files=["res://.godot/imported/slime_green.png-5261ffd1254c816fe62b35227a9aa11d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/graphics/environment/terrain/mushroom2.png b/assets/graphics/environment/terrain/mushroom2.png new file mode 100644 index 0000000000000000000000000000000000000000..ffaf96eb5cba58746296ab6e2e7a33a4e210670e GIT binary patch literal 2147 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 void: func _on_body_entered(body: Node2D) -> void: bulletDamageSignal.emit(body,self) + + +func _on_area_entered(area: Area2D) -> void: + bulletDamageSignal.emit(area,self) diff --git a/scripts/coin.gd b/scripts/coin.gd new file mode 100644 index 0000000..806174e --- /dev/null +++ b/scripts/coin.gd @@ -0,0 +1,12 @@ +class_name Coin extends Area2D + +signal coinCollectedSignal(body, coin) + + + +func _on_body_entered(body: Node2D) -> void: + if body is Player: + coinCollectedSignal.emit(body,self) + + + diff --git a/scripts/coin.gd.uid b/scripts/coin.gd.uid new file mode 100644 index 0000000..0962263 --- /dev/null +++ b/scripts/coin.gd.uid @@ -0,0 +1 @@ +uid://bojml668gpamd diff --git a/scripts/gameController.gd b/scripts/gameController.gd index 3d542e4..32825f1 100644 --- a/scripts/gameController.gd +++ b/scripts/gameController.gd @@ -8,6 +8,18 @@ var currentScene:String="res://scenes/game.tscn" var timer := Timer.new() var timeAvailable := 10 +var levels=["res://scenes/game.tscn","res://scenes/level2.tscn","res://scenes/level3.tscn"] +var timers =[15, 10, 8] +var currentLevel=0 +var coinsCollected=0 + +var playerHealth=100 +var playerStartingHealth =100 + +var enemiesDict={} + + + # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -17,12 +29,16 @@ func _ready() -> void: timer.one_shot=false timer.connect("timeout", secondCounter) timer.start() + +func reset() -> void: + timeAvailable =timers[currentLevel] + playerHealth=playerStartingHealth func secondCounter()-> void: timeAvailable -=1 if timeAvailable <=0: print("YOU LOSE!!") - levelChangeSignal.emit(currentScene) + levelChangeSignal.emit(levels[currentLevel]) @@ -59,19 +75,53 @@ func crateUpdate(cratesAmount) ->void: print("GC updated crates: " +str(crateTotal)) if crateTotal <=0: print("you win") - levelChangeSignal.emit(currentScene) + currentLevel +=1 + if currentLevel >= levels.size(): + currentLevel=0 + levelChangeSignal.emit(levels[currentLevel]) func bulletDamage(body:Node2D,bullet:Bullet) -> void: if body is Crate: # destroy Crate destroySignal.emit(body) destroySignal.emit(bullet) + if body is Slime: + enemiesDict[body]["health"] -=10 + if enemiesDict[body]["health"] <=0: + destroySignal.emit(body) + destroySignal.emit(bullet) - - - - - + +func _on_coin_collected(body:Node2D, coin:Coin) -> void: + print("GC knows coin collected") + coinsCollected +=1 + destroySignal.emit(coin) + + +func totalCoins(value) -> void: + print("GC knows coin remaining " + str(value)) + if value <=0: + # no coins left in level + levelChangeSignal.emit(levels[currentLevel]) + +func _on_slime_damage(body:Node2D, slime:Slime) -> void: + playerHealth -=enemiesDict[slime]["damage"] + print("GC knows damage "+str(enemiesDict[slime]["damage"])) + print("GC knows slime damage to player "+ str(playerHealth)) + if playerHealth <=0: + print("You are dead") + levelChangeSignal.emit(levels[currentLevel]) + + +func addEnemyToLevel(slime:Slime)-> void: + var randDamage:int=randi()%10 + var enemyStat ={ + "health": 50, + "damage": randDamage + } + + #put it in dictionary + enemiesDict[slime]=enemyStat diff --git a/scripts/scene_manager.gd b/scripts/scene_manager.gd index d2588a0..d5e9d19 100644 --- a/scripts/scene_manager.gd +++ b/scripts/scene_manager.gd @@ -2,7 +2,9 @@ class_name SceneManager extends Node2D @onready var triggers: Node2D = $"../Triggers" @onready var level: Node2D = $"../Level" @onready var crates: Node2D = $"../Crates" -@onready var game: GameController = $".." +@onready var coins: Node2D = $"../Coins" +@onready var slimes: Node2D = $"../Slimes" + # has the recepies var bullet = preload("res://scenes/bullet.tscn") var bulletArray:Array[Bullet] = [] @@ -11,6 +13,9 @@ var totalAllowedBullets:int=7 # Called when the node enters the scene tree for the first time. func _ready() -> void: + # resets the timer + # player health + Gamecontroller.reset() buildLevel() @@ -23,18 +28,51 @@ func buildLevel() -> void: print("building level") updatesCrates() updateTriggers() + updateCoins() + updateEnemies() #wire up signals from gamecontrollerd - game.destroySignal.connect(destroy) - game.teleportSignal.connect(teleport) - game.levelChangeSignal.connect(loadLevel) + Gamecontroller.destroySignal.connect(destroy) + Gamecontroller.teleportSignal.connect(teleport) + Gamecontroller.levelChangeSignal.connect(loadLevel) + +func updateEnemies() -> void: + if slimes: + var totalSlimes =0 + for obj in slimes.get_children(): + if obj is Slime: + totalSlimes +=1 + Gamecontroller.addEnemyToLevel(obj) + #hook up to game controller + if not obj.slimeDamageSignal.is_connected(Gamecontroller._on_slime_damage): + obj.slimeDamageSignal.connect(Gamecontroller._on_slime_damage) + + +func updateCoins() -> void: + if coins: + var totalCoins=0 + for obj in coins.get_children(): + if obj is Coin: + totalCoins +=1 + # hook up coin to gamecontrollerd + if not obj.coinCollectedSignal.is_connected(Gamecontroller._on_coin_collected): + obj.coinCollectedSignal.connect(Gamecontroller._on_coin_collected) + # any time coin destroyed update game controller + if not obj.tree_exited.is_connected(updateCoins): + obj.tree_exited.connect(updateCoins) + + # tell game controller! + Gamecontroller.totalCoins(totalCoins) + + + func updateTriggers()->void: if triggers: for obj in triggers.get_children(): if obj is Trigger: - if not obj.AreaTrigger.is_connected(game._on_trigger): - obj.AreaTrigger.connect(game._on_trigger) + if not obj.AreaTrigger.is_connected(Gamecontroller._on_trigger): + obj.AreaTrigger.connect(Gamecontroller._on_trigger) func updatesCrates() -> void: @@ -47,7 +85,7 @@ func updatesCrates() -> void: obj.tree_exited.connect(updatesCrates) totalCrates+=1 print("Total crates: "+str(totalCrates)) - game.crateUpdate(totalCrates) + Gamecontroller.crateUpdate(totalCrates) func destroy(body)->void: @@ -79,10 +117,9 @@ func bulletFactory()-> Bullet: # how many bullets have been made? if bulletArray.size() <=totalAllowedBullets: myBullet=bullet.instantiate() - if not myBullet.bulletDamageSignal.is_connected(game.bulletDamage): - myBullet.bulletDamageSignal.connect(game.bulletDamage) - - game.add_child(myBullet) + if not myBullet.bulletDamageSignal.is_connected(Gamecontroller.bulletDamage): + myBullet.bulletDamageSignal.connect(Gamecontroller.bulletDamage) + add_sibling(myBullet) else: myBullet=bulletArray.pop_back() bulletArray.push_front(myBullet) @@ -97,7 +134,3 @@ func makebullet(targetPosition,speed) -> void: myBullet.setSpeed(speed) myBullet.set_process(true) - - - - diff --git a/scripts/slime.gd b/scripts/slime.gd new file mode 100644 index 0000000..2745b5a --- /dev/null +++ b/scripts/slime.gd @@ -0,0 +1,34 @@ +class_name Slime extends Area2D +@onready var right_cast: RayCast2D = $RightCast +@onready var left_cast: RayCast2D = $LeftCast +@onready var right_down_cast: RayCast2D = $RightDownCast +@onready var left_down_cast: RayCast2D = $LeftDownCast +@onready var slime_graphic: AnimatedSprite2D = $SlimeGraphic + + + +var speed:int=100 +var direction =1 +signal slimeDamageSignal(body,slime) + +#animation code +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=true + 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..7488ff5 --- /dev/null +++ b/scripts/slime.gd.uid @@ -0,0 +1 @@ +uid://8iya0pgh6sfe