콘텐츠로 이동

함수와 이벤트 처리 - 코드 이해하기


코드 이해하기

이제 코드를 섹션별로 자세히 분석해봅시다!

1-6줄: 게임 초기화

from ursina import *
import os

app = Ursina(forced_aspect_ratio=.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 콜백을 설정할 수 있습니다.