From 3b23e7b50d8250d8873001c560a082542812b4cb Mon Sep 17 00:00:00 2001 From: OddlyTimbot Date: Mon, 30 Mar 2026 17:35:07 -0400 Subject: [PATCH] week 5 prep, multi-levels, coins, enemies, stats --- assets/graphics/enemies/slime_green.png | Bin 0 -> 908 bytes .../graphics/enemies/slime_green.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 | 1 + scenes/coin.tscn | 112 ++++ scenes/game.tscn | 98 ++-- scenes/level2.tscn | 499 ++++++++++++++++++ scenes/slime.tscn | 71 +++ scripts/coin.gd | 9 + scripts/coin.gd.uid | 1 + scripts/gameController.gd | 76 ++- scripts/scene_manager.gd | 58 +- scripts/slime.gd | 41 ++ scripts/slime.gd.uid | 1 + 16 files changed, 994 insertions(+), 57 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/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/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/pickups/coin.png b/assets/graphics/pickups/coin.png new file mode 100644 index 0000000000000000000000000000000000000000..01ae33d70b398db7f1f7bcafe883a0a469805201 GIT binary patch literal 500 zcmV^r!6hi!Wct>kSmw76A*+mkqIDVjdDL!Rb}5E?Td;C@2y9S zHih2xK(yTWh+gXdrTqK8Uwx^_$MoI4V|67Hn26^Qp-rJ*c_3P5d_*tx|6%^yEznE& zeE6^KHvJ|vI7934d=L#ytZIR)9hxaN1Jm8sZ6_j{Yx1#nTWt!D2<;1?{VNX?M*l~R zzukKP+i+D+FAlB;7qkOXfaGA?&h>EX&+$Oxqgs>{d4C#zhd05hUS`kO@{&+Bb`?-H zKXwYn7Ms9B!`F}PQh%-o65r;4=uy!A4;g>*6iCRL!wF!o{9{X0YM%Mf@U=DvM2}Kx zY#A;!e+4Y{Qh#m^NPMe5dkcj0f5`ZIy8@JYG2kpkh}LrU76{dHI?&Z}2LKX(>v1MX z4k6>OaQ_N1p97frj@jdSpELonJ&y=&3jN9h(K6#Bda3^x^WUBW>`ee7IfzLSUk<|l qVg27u071wNc?u+CjZ6R`YyJS*Ofbr5QwY-l0000 void: + if body is Player: + print("Player hit coin") + coinCollectedSignal.emit(body, self) diff --git a/scripts/coin.gd.uid b/scripts/coin.gd.uid new file mode 100644 index 0000000..5466873 --- /dev/null +++ b/scripts/coin.gd.uid @@ -0,0 +1 @@ +uid://b3dvuwq5c8l4h diff --git a/scripts/gameController.gd b/scripts/gameController.gd index 2819d70..93bb581 100644 --- a/scripts/gameController.gd +++ b/scripts/gameController.gd @@ -4,10 +4,20 @@ var crateTotal = 0 signal destroySignal(body) signal teleportSignal(body) signal levelChangeSignal(level) -var currentScene:String = "res://scenes/game.tscn" + +var coinsCollected = 0 var timer := Timer.new() -var timeAvailable := 10 + +#add new levels +var levels=["res://scenes/game.tscn","res://scenes/level2.tscn"] +var timers=[16,10] +var currentLevel = 0 +var timeAvailable = timers[currentLevel] + +var enemiesDict={} +var playerStartingHealth = 50 +var playerHealth = 50 # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -18,17 +28,37 @@ func _ready() -> void: timer.connect("timeout", secondCounter) timer.start() +# called by the scenemanager +func reset()->void: + # reset the time + timeAvailable = timers[currentLevel] + enemiesDict.clear() + playerHealth = playerStartingHealth + func secondCounter()->void: timeAvailable -=1 if timeAvailable <=0: print("YOU LOSE BABY!!") - levelChangeSignal.emit(currentScene) + levelChangeSignal.emit(levels[currentLevel]) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: pass - +func _on_coin_collected(body:Player, coin:Coin)-> void: + coinsCollected +=1 + destroySignal.emit(coin) + +#Any time coins are destroyed, game controller is informed how many left +func totalCoins(value)-> void: + print(value) + if value <=0: + print("You WON!!!") + currentLevel +=1 + if currentLevel >= levels.size(): + currentLevel = 0 + levelChangeSignal.emit(levels[currentLevel]) + func _on_trigger(body: Variant, effect, trigger) -> void: print("GC knows trigger...."+effect) if body is Crate: @@ -45,16 +75,50 @@ func _on_trigger(body: Variant, effect, trigger) -> void: print("GC knows about powerup") timeAvailable +=5 destroySignal.emit(trigger) - + +func _on_slime_damage(body, slime)->void: + # print("Slime attacked player for "+str(enemiesDict[slime]["damage"])) + playerHealth -= enemiesDict[slime]["damage"] + if playerHealth<=0: + print("PLAYER KILLED!") + #reload current level + levelChangeSignal.emit(levels[currentLevel]) + +func totalEnemies(value)->void: + print("Number of Enemies: "+str(value)) + +func addEnemyToLevel(slime:Slime)->void: + #random number up to 10 + var randDamage:int = randi()%10 + var enemyStat = { + "health":50, + "damage":randDamage + } + #store in the enemy Dictionary + enemiesDict[slime]=enemyStat +func removeEnemyFromLevel(slime)->void: + enemiesDict.erase(slime) + func crateUpdate(cratesAmount)->void: crateTotal = cratesAmount print("GC updated crates: "+str(crateTotal)) if crateTotal <=0: print("You WON!!!") - 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: + print("bullet hitting slime") + #damage the slime + enemiesDict[body]["health"] -= 10 + if enemiesDict[body]["health"] <=0: + removeEnemyFromLevel(body) + destroySignal.emit(body) + destroySignal.emit(bullet) diff --git a/scripts/scene_manager.gd b/scripts/scene_manager.gd index 69db837..0185b05 100644 --- a/scripts/scene_manager.gd +++ b/scripts/scene_manager.gd @@ -2,7 +2,8 @@ class_name SceneManager extends Node2D @onready var triggers: Node2D = $"../Triggers" @onready var crates: Node2D = $"../Crates" @onready var level: Node2D = $"../Level" -@onready var game: GameController = $".." +@onready var coins: Node2D = $"../Coins" +@onready var enemies: Node2D = $"../Enemies" var bullet = preload("res://scenes/bullet.tscn") var bulletArray:Array[Bullet] = [] @@ -10,6 +11,9 @@ var totalAllowedBullets:int = 7 # Called when the node enters the scene tree for the first time. func _ready() -> void: + # Reset all the stuff in the level + Gamecontroller.reset() + buildLevel() @@ -19,20 +23,50 @@ func _process(delta: float) -> void: func buildLevel()->void: print("building level") + updateCoins() updateCrates() updateTriggers() + updateEnemies() #wire up signals from GameController - 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 enemies: + var totalEnemies = 0 + for obj in enemies.get_children(): + if obj is Slime: + totalEnemies +=1 + if not obj.slimeDamageSignal.is_connected(Gamecontroller._on_slime_damage): + print("Hooking up slime") + obj.slimeDamageSignal.connect(Gamecontroller._on_slime_damage) + Gamecontroller.addEnemyToLevel(obj) + if not obj.tree_exited.is_connected(updateEnemies): + obj.tree_exited.connect(updateEnemies) + Gamecontroller.totalEnemies(totalEnemies) + +func updateCoins()->void: + if coins: + var totalCoins = 0 + for obj in coins.get_children(): + if obj is Coin: + totalCoins +=1 + print("coin found") + if not obj.coinCollectedSignal.is_connected(Gamecontroller._on_coin_collected): + obj.coinCollectedSignal.connect(Gamecontroller._on_coin_collected) + #Any time a coin is destroyed, let game controller know how many remain + if not obj.tree_exited.is_connected(updateCoins): + obj.tree_exited.connect(updateCoins) + 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 updateCrates()->void: #check that there is a crates node @@ -43,7 +77,7 @@ func updateCrates()->void: if not obj.tree_exited.is_connected(updateCrates): obj.tree_exited.connect(updateCrates) totalCrates +=1 - game.crateUpdate(totalCrates) + Gamecontroller.crateUpdate(totalCrates) func destroy(body)->void: if body is Bullet: @@ -71,9 +105,11 @@ 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) + #Gamecontroller.add_child(myBullet) + #Gamecontroller is pure code now, so switch to add_sibling + add_sibling(myBullet) else: myBullet = bulletArray.pop_back() diff --git a/scripts/slime.gd b/scripts/slime.gd new file mode 100644 index 0000000..6652c5a --- /dev/null +++ b/scripts/slime.gd @@ -0,0 +1,41 @@ +class_name Slime extends Area2D +@onready var right_cast: RayCast2D = $RightCast +@onready var left_cast: RayCast2D = $LeftCast +@onready var left_down_cast: RayCast2D = $LeftDownCast +@onready var right_down_cast: RayCast2D = $RightDownCast +@onready var slime_graphic: AnimatedSprite2D = $SlimeGraphic + +var speed:int = 100 +var direction = 1 + +signal slimeDamageSignal(body, slime) +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + #raycast detection + 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): + 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..fdf31ac --- /dev/null +++ b/scripts/slime.gd.uid @@ -0,0 +1 @@ +uid://c8o8u4tesokv5