햇빛 시스템 구현
Godot로 Plants vs. Zombies 클론을 만들고 있다. 오늘은 햇빛 시스템을 구현했다.
목표
- 하늘에서 햇빛이 주기적으로 떨어짐
- 클릭하면 수집되고 카운터에 반영
- 나중에 Sunflower 연동까지 확장 가능한 구조
구조 설계
Sun (Area2D) ← sun.gd
├── AnimatedSprite2D
└── CollisionShape2D
SunManager (Node) ← Autoload 등록
Main
├── SunTimer
└── Label (햇빛 카운터)
SunManager는 Autoload로 등록해서 어디서든 접근 가능하게 했다.
햇빛 카운터처럼 게임 전체에서 공유하는 데이터는 Autoload가 적합하다.
Sun 씬
스프라이트는 Retro Diffusion으로 뽑은 64×64 픽셀아트 스프라이트시트 (4×4, 16프레임)를 사용했다. AnimatedSprite2D에 SpriteFrames 리소스로 등록하고 loop 설정.
충돌 모양은 CircleShape2D, 반지름 28 정도로 잡았다.
# sun.gd
extends Area2D
signal sun_collected
var fall_speed = 50.0
var target_y = 0.0
var is_falling = true
func _ready():
$AnimatedSprite2D.play("idle")
func _process(delta):
if is_falling:
position.y += fall_speed * delta
if position.y >= target_y:
position.y = target_y
is_falling = false
func _on_input_event(_viewport, event, _shape_idx):
if event is InputEventMouseButton and event.pressed:
get_viewport().set_input_as_handled()
emit_signal("sun_collected")
queue_free()
_on_input_event는 Area2D의 시그널을 에디터에서 직접 연결해서 사용했다.
클릭하면 sun_collected 시그널을 발생시키고 자기 자신을 삭제한다.
SunManager
# sun_manager.gd
extends Node
signal sun_changed(new_amount)
var sun_count = 50
func add_sun(amount):
sun_count += amount
emit_signal("sun_changed", sun_count)
func spend_sun(amount):
if sun_count >= amount:
sun_count -= amount
emit_signal("sun_changed", sun_count)
return true
return false
sun_changed 시그널로 UI에 알린다. UI는 이 시그널을 구독해서 Label을 업데이트하는 방식.
Main - 타이머로 Sun 생성
# main.gd
extends Node
@onready var debug_label = $Label
@onready var sun_timer = $SunTimer
var SunScene = preload("res://scenes/sun.tscn")
func _ready() -> void:
SunManager.sun_changed.connect(_on_sun_changed)
debug_label.text = "Sun: %d" % SunManager.sun_count
sun_timer.timeout.connect(_on_sun_timer_timeout)
func _on_sun_changed(new_amount):
debug_label.text = "Sun: %d" % new_amount
func _on_sun_timer_timeout():
var sun = SunScene.instantiate()
sun.position = Vector2(randf_range(100, 820), -32)
sun.target_y = randf_range(200, 580)
sun.sun_collected.connect(SunManager.add_sun.bind(25))
add_child(sun)
SunTimer는 Wait Time 5초, Autostart 켜둔 상태. 나중에 시작 씬 만들면 Autostart 끄고 코드로 제어할 예정.
sun.position.y = -32는 스프라이트 크기 절반 기준으로 화면 위쪽 바깥에서 시작하게 한 것.
시행착오 - ColorRect가 클릭을 먹고 있었다
클릭해도 Sun이 아무 반응이 없었다. 원인을 찾는 데 시간이 좀 걸렸다.
의심한 것들:
_on_input_event연결 문제input_event시그널 미연결- game_board.gd의
_input이 클릭을 가로채는 것 _inputvs_unhandled_input차이
실제 원인은 배경으로 깔아둔 ColorRect였다.
ColorRect의 Mouse Filter 기본값이 Stop이라 모든 마우스 입력을 ColorRect가 먼저 먹어버리고 있었다.
Ignore로 바꾸니까 바로 해결됐다.
| Mouse Filter | 동작 |
|---|---|
| Stop | 클릭을 여기서 멈춤 (기본값) |
| Pass | 처리하고 아래로도 전달 |
| Ignore | 무시하고 아래로 전달 |
UI 노드 쪽은 항상 Mouse Filter 확인하는 습관을 들여야겠다.
다음
- Sunflower가 주기적으로 Sun 생성
- 식물 선택 UI
- 좀비 기본 이동
