RoNS 님의 블로그

[Pygame(파이게임)] 가시 함정 생성 본문

Pygame

[Pygame(파이게임)] 가시 함정 생성

namu999 2025. 8. 30. 13:36
반응형

이번 글에서는 이전 글의 마지막에 이야기했듯이 맵을 게임 실행 전에 완성(로딩)을 하도록 만들고,

드디어 플레이어를 방해할 수 있는 첫번째 요소로 가시 함정을 추가 할 것이다.


이전 글에서는 평면 상태의 땅만 게임창에 보이게 하여서, 조금 심심해 보이기도 했었다.

같은 높이의 땅이더라도,

왼쪽의 땅이 한칸 더 낮다면, 땅의 왼쪽 모서리가 둥글게, 

오른쪽의 땅이 한칸 더 낮다면, 땅의 오른쪽 모서리가 둥글게~

만들어주기 위하여

"왼쪽 모서리가 둥근 땅",  "오른쪽 모서리가 둥근 땅" 그리고 원래의 "평면 땅"을 세가지 타입으로 나누어, 각각 다른 확률로 나타나게 하면 된다. ( [Pygame(파이게임)] 게임 맵 랜덤 생성 에서 확률적으로 맵을 생성하는 것은 설명했다.)

new_P = np.array([
#-5               #-4              #-3               #-2               #-1                 #0               #1               #2               #3               #4

#깊이 -5 #최대 깊이(점프 거리 고려) 다음 생성은 무조건 깊이 0 땅
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      1.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      1.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      1.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 -4 #한칸 아래 or 땅
[0.7, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.3, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.7, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.3, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.7, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.3, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 -3 #한칸 아래 or 땅
[0.0, 0.0, 0.0,   0.7, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.3, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.7, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.3, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.7, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.3, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 -2 #한칸 아래 or 땅
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.8, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.1, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.8, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.1, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.8, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.1, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 -1 #한칸 아래 or 땅
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.8, 0.0, 0.0,    0.0, 0.0, 0.0,      0.1, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.8, 0.0, 0.0,    0.0, 0.0, 0.0,      0.1, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.8, 0.0, 0.0,    0.0, 0.0, 0.0,      0.1, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
    

#깊이 0
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.5, 0.2,   0.2, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.5, 0.2,   0.2, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    1.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 1 
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.5, 0.2,   0.2, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.5, 0.2,   0.2, 0.0, 0.0,   0.1, 0.0, 0.0,   0.0, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.5, 0.0, 0.0,      0.0, 0.3, 0.2,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 2
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.5, 0.2,   0.2, 0.0, 0.0,   0.1, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.5, 0.2,   0.2, 0.0, 0.0,   0.1, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.3, 0.0, 0.0,      0.0, 0.1, 0.1,   0.0, 0.3, 0.2,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 3
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.5, 0.3,   0.2, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.5, 0.3,   0.2, 0.0, 0.0,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.2, 0.0, 0.0,      0.0, 0.1, 0.0,   0.0, 0.1, 0.1,   0.0, 0.3, 0.2,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,],
#깊이 4
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.7, 0.3,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.0, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.7, 0.3,],
[0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,    0.0, 0.0, 0.0,    0.1, 0.0, 0.0,      0.0, 0.0, 0.0,   0.0, 0.1, 0.1,   0.0, 0.1, 0.1,   0.0, 0.3, 0.2,   0.0, 0.0, 0.0,],
])

땅을 세가지의 타입으로 만드니, 게임에서 맵의 깊이를 10가지로 밖에 나누지 않았음에도, 행렬의 크기가 어마무시하다..

코드를 통해, 맵이 적절하게 나올지를 우선 파이썬의 scatter함수로 그렸다.

5 이하는 화면상에서는 보이지 않는 낭떠러지이고,

파란색은 왼쪽으로 둥근 땅, 주황색은 평면, 초록색은 오른쪽으로 둥근 땅이다. 적절하게 잘 계산 된 것 같다!

 

그 다음은 이제 "가시 함정"이다.

가시는 넘파이의 랜덤 확률(30%)로 나타나게 하고, 위 맵에서 왼쪽으로 둥근 땅 일 때, 오른쪽으로 둥근 땅 일 때는 삭제하였다.

(맵을 미리 만들기 때문에, 가시 함정도 맵의 총 길이 만큼 나타날 곳을 미리 모두 계산해 두었다.)

또, 캐릭터가 가시 함정을 밟으면 데미지/게임오버가 되어야 한다.

pygame에서는 colliderect 함수를 통해, 그린 그림의 영역과 닿았는지를 확인 할 수 있는 기능이 있지만,

현재는 가시의 그림을 배경 그림과 한번에 그려서 렉을 줄이는게 우선 목표이기 때문에 다른 방법을 이용한다.

가시 또한 맵처럼 그래프로 그려서 플레이어가 이 그래프의 위치에 닿게 된다면!

게임오버가 되도록 한다.

파란 선이 맵, 주황색 선이 가시에 대한 그래프이다. 플레이어는 파란 선 위로 이동하다가, 주황선에 몸이 닿게 되면 게임오버가 된다.

아래는 현재까지의 과정과 맵을 미리 만드는 과정의 전체 코드이다.

np.random.seed(seed_v)

## 가시함정의 위치 랜덤으로 만들기
is_spike = np.random.random(map_length)
is_spike[is_spike>0.7] = 1 # 30% 확률로 생성
is_spike[is_spike!=1] = 0 # 나머지 70%는 빈 땅 
is_spike[m_type==0] = 0 # 모서리가 둥근땅이면 삭제1
is_spike[m_type==2] = 0  # 모서리가 둥근땅이면 삭제2
is_spike[0:5] = [0,0,0,0,0] #시작지점은 가시 삭제

## (물리적인) 가시함정 위치 계산하기
m_spike = (m_ground-30) * np.repeat(is_spike,50)
m_spike[m_spike==0] = 800
for i in list(range(0,2*5))+list(range(7*5,10*5)):
    m_spike[np.array(np.where(is_spike))*50 + i] = 800

## 모든 맵에 대한 지형지물, 가시, 배경 조립하기 (map_length길이만큼)
map_v=[]
for i in range(map_length):
    
    # 가시 있으면
    if is_spike[i]:
        sp = np.hstack([sky_block, spike_block])
    # 돌,풀 등 지형지물 있으면 
    elif is_backgorund_block[i]:
        sp = background_blocks[is_backgorund_block[i]]
    # 아무것도 없음
    else:
        sp = np.hstack([sky_block,sky_block])      
    
    #아래 블록~위 블록 조립하기
    map_v.append(np.hstack((
        np.hstack([sky_block for i in range(17-m_deep[i]-2)]), 
        sp,
        map_RGB[m_type[i],0], map_RGB[m_type[i],1], map_RGB[m_type[i],2], 
        np.hstack([map_RGB[1,2] for i in range(m_deep[i])]) )))

#왼쪽 블록~ 오른쪽 블록 조립하기        
long_map = np.vstack(map_v)

 

(만들어둔 맵, 가시, 지형지물을 합치는 코드에서 np.hstack과 np.vstack이 아주 중요하게 쓰였다.)

아래는 플레이 화면이다.

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

저번 글에서 말한 멈추는 렉이 사라지고, 모두 직각이던 맵이 조금은 부드러워졌다.

또, 가시 역시 잘 작동한다

반응형