앱 개발/pygame

[pygame] 08. 피격 판정

내만 2022. 9. 29. 21:57
728x90
반응형

728x90
반응형

 

 

 

 

🙆‍♂️ 피격 판정 객체


삽입한 이미지들 끼리 만난다면 특별한 이벤트를 진행하는 방향으로 설정합니다.

 

총알과 적군이 충돌하면 적군이 사라지도록

적군과 본체가 충돌하면 게임이 끝나도록 등이 있는데

 

우선 총알과 적군이 충돌하면 적군이 사라지도록 하고 적군의 HP를 늘려서 특정 값 이상 맞아야 사라지도록 해보겠습니다.

 

충돌의 범위는 이렇습니다.

b.x의 범위는 a.x-b.oX < b.x < a.x+a.oX

b.y의 범위는 a.y-b.oY < b.y < a.y+a.oY

입니다.

 

한국어로 풀어쓰면 A의 좌표 - B의 좌표 < b.x, b.y < A의 반대편 좌표(저기 빨간 동그라미 부분) 입니다.

 

🙆‍♂️ 적군, 총알 충돌 판정


#충돌 탐지 함수
"""
충돌 탐지 함수
서로 다른 이미지들이 충돌하면 True값을 반환하는 함수입니다.

ex) a=colDetec(hero,enemy1)
>>>print(a)
>>>True
"""
def colDetec(vic,perp):
    if vic.x-perp.oX < perp.x and perp.x < vic.x+vic.oX:
        if vic.y-perp.oY < perp.y and perp.y < vic.y+vic.oY:
            return True
        else:
            return False
    else:
        return False
    #총알과 적군 충돌 시 충알과 적군 del
    cd_del_enemList=[]
    cd_del_bulList=[]
    for i,enem in enumerate(enemList):
        for j,bul in enumerate(bulList):
            if colDetec(enem,bul):
                cd_del_enemList.append(i)
                cd_del_bulList.append(j)
    cd_del_enemList=list(set(cd_del_enemList))
    cd_del_bulList=list(set(cd_del_bulList))
    
    for i in cd_del_enemList:
        del enemList[i]
    for i in cd_del_bulList:
        del bulList[i]

 

잘 됐는데 근데 에러가 났습니다.

이게 찾아보니까 set() 함수를 통해서 중복을 제거할 때 인덱스가 낮은 것부터 다시 정렬이 되어서 낮은 인덱스를 삭제해서 for문을 돌릴 때 에러가 나는 그런 모양이라고 하네요! 그래서 reverse함수를 통해서 거꾸로 돌려줘야 큰 index부터 제거가 되어서 for문에 영향이 안간다고 하네요.

 

    #총알과 적군 충돌 시 충알과 적군 del
    cd_del_enemList=[]
    cd_del_bulList=[]
    for i,enem in enumerate(enemList):
        for j,bul in enumerate(bulList):
            if colDetec(enem,bul):
                cd_del_enemList.append(i)
                cd_del_bulList.append(j)
    cd_del_enemList=list(set(cd_del_enemList))
    cd_del_bulList=list(set(cd_del_bulList))
    cd_del_enemList.reverse()
    cd_del_bulList.reverse()
    
    for i in cd_del_enemList:
        del enemList[i]
    for i in cd_del_bulList:
        del bulList[i]

 

🙆‍♂️ 적군, 본체 충돌 판정


#XB가 1이 아니라면 while문 종료
while XB == 1:
	.
    	.
    
    for i,enem in enumerate(enemList):
        if colDetec(hero,enem):
            XB=0

적군과 본체 충돌 코드는 위와 같은데 XB라는 값은 while문을 돌리기 위한 값인데

XB가 1이 아니게 되면 while문을 종료하고 게임이 종료됩니다.

 

🙆‍♂️ 적군 HP 설정


우선은 이렇게 설정을 했고 이제 총알 하나 당 적군이 없어지는 것이 아닌

여러 번 맞아야 없어지도록 설정하겠습니다.

 

#클래스 생성
class createObj:
    #생성자
    def __init__(self):
        .
        .
        self.kill = 0
        
        
        
    .
    .
    .
    
    """
    적군과 총알이 충돌하면 일어나는 이벤트를 정의한 구간입니다.
    deathNum의 값을 통해서 적군의 HP를 설정할 수 있습니다.
    """
    deathNum=2
    cd_del_enemList=[]
    cd_del_bulList=[]
    for i,enem in enumerate(enemList):
        for j,bul in enumerate(bulList):
            if colDetec(enem,bul):
                enem.kill+=1
                cd_del_bulList.append(j)
                if enem.kill==deathNum:
                    cd_del_enemList.append(i)
                    enem.kill=0

class를 정의하는 생성자의 kill이라는 변수를 추가하여서

colDetec 함수를 돌렸을 때 충돌 판정이 난다면 객체.kill 값이 1씩 올라가게 하여

설정해둔 deathNum 과 같아지면 삭제 리스트로 올겨 적군이 죽은 것 처럼 하고 kill값을 0으로 초기화 하면 됩니다!

 

🙆‍♂️ 본체 HP 설정


 

#클래스 생성
class createObj:
    #생성자
    def __init__(self):
        .
        .
        .
        self.passing = False
    
    
    
    .
    .
    .
    
    """
    본체와 적군이 충돌할 때 일어나는 이벤트를 정의한 구간입니다.
    lifeNum 변수를 통해서 본체의 HP를 설정할 수 있습니다.
    """
    lifeNum=5
    for i,enem in enumerate(enemList):
        if enem.passing == False:
            if colDetec(hero,enem):
                hero.kill += 1
                print(hero.kill)
                enem.passing = True
                if hero.kill == 5:
                    XB=0

아까 설정했던 kill 변수도 사용하는데 kill 변수만 사용해서 하면 한 번 부딪친 적군과 무한으로 부딪치기 때문에 lifeNum을 설정하기 어려웠는데 한 번 부딪친 적군은 passing True로 바꿔줘서 다시 안 부딪치도록 설정했습니다!

 

지금까지 하면 게임 같은 모습은 나옵니다!

이제 본체 HP를 이미지화 하고 피격 효과음 등을 하고 적군에서 나오는 총알 등 구현해야 할 것이 많습니다!!

 

지금까지 코드입니다.

"""
현재까지 만들어진 이미지 객체들
hero : 본체
bullet : 총알
enemy1 : 적군1
===============================
bulList : 총알 저장 리스트
enemList: 적군 저장 리스트
"""


import pygame
import random

# 1. 게임 초기화
pygame.init()


# 2. 게임 창 옵션 설정

#크기 설정
size = [800,1000]                         
screen = pygame.display.set_mode(size)

 #제목 설정
title = "Korea 1942"                    
pygame.display.set_caption(title)        



# 3. 게임 내 필요한 설정

#시계 만들기
clock = pygame.time.Clock()              

#배경 색 지정
gray = (80,80,80)                        
color = gray

#클래스 생성
class createObj:
    #생성자
    def __init__(self):
        self.x = 0
        self.y = 0
        self.move = 0
        self.kill = 0
        self.passing = False
    #캐릭터 입력
    def insertImg(self, addr):
        if addr[-3:] == 'png':
            self.obj = pygame.image.load(addr).convert_alpha()
        else:
            self.obj = pygame.image.load(addr)
        #캐릭터 x길이, y길이 받아오기
        self.oX, self.oY = self.obj.get_size()
        
    #사진 사이즈 설정
    def setSize(self, oX, oY):
        self.obj = pygame.transform.scale(self.obj, (oX, oY))
        #캐릭터 x길이, y길이 받아오기
        self.oX, self.oY = self.obj.get_size()
    
    #blit
    def show(self):
        screen.blit(self.obj, (self.x, self.y))

        
        
#충돌 탐지 함수
"""
충돌 탐지 함수
서로 다른 이미지들이 충돌하면 True값을 반환하는 함수입니다.

ex) a=colDetec(hero,enemy1)
>>>print(a)
>>>True
"""
def colDetec(vic,perp):
    if vic.x-perp.oX+5 < perp.x and perp.x < vic.x+vic.oX-5:
        if vic.y-perp.oY+5 < perp.y and perp.y < vic.y+vic.oY-5:
            return True
        else:
            return False
    else:
        return False

    
    
        
hero = createObj()
#캐릭터 경로 설정
hero.insertImg(r'image\blackEagle.png')
#캐릭터 크기 설정
hero.setSize(40,70)
#캐릭터 위치 설정
hero.x = round(size[0]/2 - hero.oX/2)
hero.y = size[1] - 50 - hero.oY
hero.move = 10


# 4. 메인 이벤트
# 변수 설정
#버튼 누르면 XB값이 0이되어 종료
XB = 1
k=0

###초기화 설정###
#이동 값(bool) 초기화
leftMove=False
rightMove=False
topMove = False
bottomMove = False
#슈팅 여부
shot = False

#총알 리스트
bulList=[]
#적군 리스트
enemList=[]


#XB가 1이 아니라면 while문 종료
while XB == 1:
    
    # 4-1. FPS 설정
    
    #FPS 설정 초당 반응 수
    clock.tick(60)                       


    # 4-2. 각종 입력 감지
    
    #입력 감지
    
    for event in pygame.event.get():
        #입력이 들어오면 종료
        if event.type == pygame.QUIT:
            XB=0
        
        #wasd or 방향키 입력 or 슈팅 입력(space bar or k) 감지
        #KeyDown되면 활성화
        if event.type == pygame.KEYDOWN:
            if event.key == 97 or event.key == 1073741904:
                leftMove = True
            if event.key == 100 or event.key == 1073741903:
                rightMove = True
            if event.key == 115 or event.key == 1073741905:
                bottomMove = True
            if event.key == 119 or event.key == 1073741906:
                topMove = True
            if event.key == 32 or event.key == 107:
                shot = True
                k=0
        #KeyUp 되면 비활성화
        elif event.type == pygame.KEYUP:
            if event.key == 97 or event.key == 1073741904:
                leftMove = False
            if event.key == 100 or event.key == 1073741903:
                rightMove = False
            if event.key == 115 or event.key == 1073741905:
                bottomMove = False
            if event.key == 119 or event.key == 1073741906:
                 topMove = False
            if event.key == 32 or event.key == 107:
                shot = False 
    
    
    
    # 4.3 입력과 시간에 따른 변화
    
    #해당 키가 눌리면 이동
    #좌측 이동
    if leftMove == True:
        hero.x -= hero.move
        #화면에 벗어나지 않도록
        if hero.x <= 0:
            hero.x = 0
    #우측 이동
    if rightMove == True:
        hero.x += hero.move
        #화면에 벗어나지 않도록
        if hero.x >=size[0]-hero.oX:
            hero.x = size[0]-hero.oX
    #위로 이동
    if topMove == True:
        hero.y -= hero.move
        #화면에 벗어나지 않도록
        if hero.y <= 0 :
            hero.y = 0
    #아래로 이동
    if bottomMove == True:
        hero.y += hero.move
        #화면에 벗어나지 않도록
        if hero.y >= size[1]-hero.oY:
            hero.y = size[1]-hero.oY
    
    
    
    #총알 쏠 때
    """
    총알 쏠 때 
    bul_num의 변수 값의 k % n 중 n값이
    작아질 수록 총알 수 많아짐
    """
    bul_num = k%7
    if shot == True and bul_num == 0:
        bullet = createObj()
        bullet.insertImg(r'image\bullet.png')
        bullet.setSize(30,50)
        bullet.x = round(hero.x + hero.oX/2 - bullet.oX/2)
        bullet.y = hero.y - bullet.oY - 10
        bullet.move = 20
        bulList.append(bullet)
    k+=1
    
    #총알이 화면을 벗어나면 제거
    del_bulList=[]
    for i,v in enumerate(bulList):
        v.y -= v.move
        if v.y <= -v.oY:
            del_bulList.append(i)
    for i in del_bulList:
        del bulList[i]
        
    
    """
    랜덤 적기 생성
    enem_num_index의 값은 0~1사이 값입니다.
    1로 설정하면 적군이 하나도 나오지 않고
    1에 가까워질수록 적군이 나오는 빈도수가 줄어듭니다.
    """
    enem_num_index = 0.97
    if random.random() > enem_num_index:
        enemy1 = createObj()
        enemy1.insertImg(r'image\enemy1.png')
        enemy1.setSize(50,80)
        enemy1.x = random.randrange(size[0]-enemy1.oX)#-round(hero.oX/2)
        enemy1.y = 15
        enemy1.move = 2
        enemList.append(enemy1)
    
    #적기가 화면을 벗어나면 제거
    del_enemList=[]
    for i,v in enumerate(enemList):
        v.y += v.move
        if v.y > size[1]+v.oY:
            del_enemList.append(i)
    for i in del_enemList:
        del enemList[i]
    
    #총알과 적군 충돌 시 충알과 적군 del
    """
    적군과 총알이 충돌하면 일어나는 이벤트를 정의한 구간입니다.
    deathNum의 값을 통해서 적군의 HP를 설정할 수 있습니다.
    """
    deathNum=2
    cd_del_enemList=[]
    cd_del_bulList=[]
    for i,enem in enumerate(enemList):
        for j,bul in enumerate(bulList):
            if colDetec(enem,bul):
                enem.kill+=1
                cd_del_bulList.append(j)
                if enem.kill==deathNum:
                    cd_del_enemList.append(i)
                    enem.kill=0
                
    cd_del_enemList=list(set(cd_del_enemList))
    cd_del_bulList=list(set(cd_del_bulList))
    cd_del_enemList.reverse()
    cd_del_bulList.reverse()
    
    for i in cd_del_enemList:
        del enemList[i]
    for i in cd_del_bulList:
        del bulList[i]
    
    """
    본체와 적군이 충돌할 때 일어나는 이벤트를 정의한 구간입니다.
    lifeNum 변수를 통해서 본체의 HP를 설정할 수 있습니다.
    """
    lifeNum=5
    for i,enem in enumerate(enemList):
        if enem.passing == False:
            if colDetec(hero,enem):
                hero.kill += 1
                print(hero.kill)
                enem.passing = True
                if hero.kill == 5:
                    XB=0
    
            
    
    # 4-4 그리기
    
    #화면 색 채우기
    screen.fill(color)
    
    #캐릭터 띄우기
    hero.show()
    
    #총알 띄우기
    for v in bulList:
        v.show()
    
    #적기 띄우기
    for v in enemList:
        v.show()
    

    # 4-5 업데이트
    
    #screen 상태 업데이트
    pygame.display.flip()                
    
    
    

# 5 게임 종료 
pygame.quit()
728x90
반응형

'앱 개발 > pygame' 카테고리의 다른 글

[pygame] 10. 깃허브에 올리기  (0) 2022.11.27
[pygame] 09. 텍스트 사용  (0) 2022.11.09
[pygame] 07. 적 생성  (0) 2022.09.27
[pygame] 06. 총알 쏘기  (1) 2022.09.22
[pygame] 05. 캐릭터 움직이기  (0) 2022.09.22