함수와 이벤트 처리 - 코드 이해하기
코드 이해하기
이제 코드를 섹션별로 자세히 분석해봅시다!
1-6줄: 게임 초기화
설명:
- 1줄: Ursina 엔진의 모든 기능을 불러옵니다.
- 2줄:
os모듈을 불러옵니다 (환경변수 확인용). - 6줄:
Ursina(forced_aspect_ratio=.6)로 앱을 만듭니다.forced_aspect_ratio=.6은 화면 비율을 세로로 길게 만듭니다 (탄막 슈팅 게임에 적합).
13-18줄: 배경, 플레이어, 총알 렌더러 설정
bg = Entity(model='quad', scale=(30, 50), texture='grass', color=hsv(0,0,.2))
player = Entity(model=Circle(3), color=color.azure, speed=8, y=-.4, z=-1)
player.bullet_renderer = Entity(model=Mesh(mode='point', thickness=.2), texture='circle', color=color.yellow)
scene.fog_density = (10,50)
ec = EditorCamera(rotation_x=-20)
설명:
- 13줄: 배경을 만듭니다.
quad는 사각형 평면입니다. - 14줄: 플레이어를 만듭니다.
Circle(3): 3개의 꼭지점을 가진 원(삼각형)speed=8: 커스텀 속성을 추가합니다 (Entity는 자유롭게 속성 추가 가능!)
- 15줄: 핵심! 총알 렌더러를 만듭니다.
Mesh(mode='point'): 점들의 집합으로 그리는 메쉬thickness=.2: 점의 두께
- 17줄: 안개 효과를 설정합니다.
- 18줄: 카메라를 약간 위에서 바라보도록 설정합니다.
Mesh의 mode 옵션
'point': 각 정점을 점으로 그립니다 (총알에 적합)'line': 정점들을 선으로 연결합니다'triangle': 정점들을 삼각형으로 채웁니다
21-25줄: 발사 함수와 시퀀스
def shoot():
player.bullet_renderer.model.vertices.append(player.position)
shoot_cooldown = .1
shoot_sequence = Sequence(Func(shoot), Wait(shoot_cooldown), loop=True)
설명:
- 21-22줄:
shoot()함수를 정의합니다.player.bullet_renderer.model.vertices: 총알의 좌표들을 저장하는 리스트append(player.position): 현재 플레이어 위치를 리스트에 추가
- 24줄: 발사 간격을 0.1초로 설정합니다.
- 25줄: 핵심! 시퀀스를 만듭니다.
Func(shoot): shoot 함수를 실행Wait(shoot_cooldown): 0.1초 대기loop=True: 무한 반복
28-50줄: 메인 업데이트 함수
def update():
move_direction = Vec2(held_keys['d']-held_keys['a'], held_keys['w']-held_keys['s']).normalized()
player.position += move_direction * player.speed * time.dt
bg.texture_offset += Vec2(0, time.dt)
설명:
- 29줄: 이동 방향을 계산합니다.
held_keys['d']-held_keys['a']: D가 눌리면 1, A가 눌리면 -1.normalized(): 대각선 이동이 더 빠르지 않도록 정규화
- 30줄: 플레이어를 이동시킵니다.
player.speed * time.dt: 속도 × 시간 = 이동 거리
- 31줄: 배경 텍스처를 스크롤하여 움직이는 효과를 줍니다.
for i, bullet in enumerate(player.bullet_renderer.model.vertices):
player.bullet_renderer.model.vertices[i] += Vec3(0, time.dt * 10, 0)
for enemy in enemies:
if distance_2d(bullet, enemy) < .5:
enemy.hp -= 1
enemy.blink(color.white)
if enemy.hp <= 0:
enemies.remove(enemy)
destroy(enemy)
player.bullet_renderer.model.vertices.remove(bullet)
설명:
- 33-34줄: 모든 총알을 위로 이동시킵니다.
- 35-43줄: 각 총알과 적의 충돌을 검사합니다.
distance_2d(): 2D 거리 계산 함수enemy.blink(): 적이 맞으면 흰색으로 깜빡임destroy(): 객체를 완전히 제거
if len(player.bullet_renderer.model.vertices):
player.bullet_renderer.model.vertices = player.bullet_renderer.model.vertices[-100:]
player.bullet_renderer.model.generate()
설명:
- 47-48줄: 총알이 너무 많아지면 최근 100개만 유지합니다.
- 50줄: 필수!
generate()를 호출해야 화면에 변경사항이 반영됩니다.
53-57줄: 입력 처리
def input(key):
if key == 'space':
shoot_sequence.start()
if key == 'space up':
shoot_sequence.paused = True
설명:
- 54-55줄: 스페이스바를 누르면 발사 시퀀스를 시작합니다.
- 56-57줄: 스페이스바를 떼면 시퀀스를 일시정지합니다.
'space up': 키를 뗐을 때의 이벤트
62-73줄: 적 설정 및 업데이트
enemies = []
enemy = Entity(model=Circle(3), rotation_z=180, position=(0, 16), color=color.red, z=-1, speed=3, hp=5)
enemies.append(enemy)
def enemy_update():
for e in enemies:
e.position += e.up * enemy.speed * time.dt
enemy_handler = Entity(update=enemy_update)
설명:
- 62-64줄: 적 리스트를 만들고 적을 추가합니다.
rotation_z=180: 아래를 향하도록 회전hp=5: 체력 속성 추가
- 66-68줄: 적을 이동시키는 함수입니다.
e.up: 적의 위쪽 방향 (rotation_z=180이므로 아래로 이동)
- 72줄: 팁!
Entity(update=함수)로 update 콜백을 설정할 수 있습니다.