본문 바로가기

Programming/파이썬

나도코딩 활용편2 GUI 프로그래밍 ft.백업의 중요성

https://www.youtube.com/watch?v=Dkx8Pl6QKW0&list=LL&index=7

베이직(가운데 있는 공 피해 움직이기)


import pygame

pygame.init() #초기화 (필수!)

#화면 크기 설정
screenwidth = 480 #가로크기
screenheight = 640 #세로크기
screen = pygame.display.set_mode((screenwidth, screenheight))

#화면 타이틀 설정
pygame.display.set_caption("game") #게임 이름

#FPS
clock = pygame.time.Clock()

#배경 이미지 불러오기
background = pygame.image.load("C:/Users/User/Desktop/python workspace/pygame_basic/background.png")

#캐릭터(스프라이트) 불러오기
character = pygame.image.load("C:/Users/User/Desktop/python workspace/pygame_basic/character.png")
charactersize = character.get_rect().size #이미지 크기 구해옴
characterwidth = charactersize[0]
characterheight = charactersize[1]
characterxpos = (screenwidth / 2) - (characterwidth/2) #화면 가로 중앙
characterypos = screenheight-characterheight #화면 세로 크기 가장 아래

#이동할 좌표
tox = 0
toy = 0

#이동속도
characterspeed = 0.6

#적 enemy 캐릭터
enemy = pygame.image.load("C:/Users/User/Desktop/python workspace/pygame_basic/enemy.png")
enemysize = enemy.get_rect().size #이미지 크기 구해옴
enemywidth = enemysize[0]
enemyheight = enemysize[1]
enemyxpos = (screenwidth / 2) - (enemywidth/2) #화면 가로 중앙
enemyypos = (screenheight / 2) - (enemyheight/2)

#폰트 정의
gamefont = pygame.font.Font(None, 40) #폰트 객체 생성 (폰트, 크기)

#총시간
totaltime = 10

#시작시간 정보
startticks = pygame.time.get_ticks() #현재 tick 받아옴

#이벤트 루프
running = True #게임이 진행중인가
while running:
    dt = clock.tick(60) #게임화면의 초당 프레임 수 설정
 
    #캐릭터가 1초 동안 100만큼 이동해야 함
    #10 fps : 1초 동안 10번 동작 => 1번에 10만큼 이동함 10*10
    #20 fps : 1초 동안 20번 동작 => 1번에 5만큼 이동함 5*20

    print("fps: " + str(clock.get_fps()))

    for event in pygame.event.get(): #어떤 이벤트가 발생했는가
        if event.type == pygame.QUIT: #창이 닫히는 이벤트가 발생했는가
            running = False #게임 진행중 아님
   
        if event.type == pygame.KEYDOWN: #키가 눌러졌는지 확인
            if event.key == pygame.K_LEFT:
                tox -= characterspeed
            elif event.key == pygame.K_RIGHT:
                tox += characterspeed
            elif event.key == pygame.K_UP:
                toy -= characterspeed
            elif event.key == pygame.K_DOWN:
                toy += characterspeed

        if event.type == pygame.KEYUP: #방향키 떼면 멈춤
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                tox = 0
            elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                toy = 0

    characterxpos += tox * dt
    characterypos += toy * dt

    #가로 경계값 처리
    if characterxpos < 0:
        characterxpos = 0
    elif characterxpos > screenwidth-characterwidth:
        characterxpos = screenwidth-characterwidth

    #세로 경계값 처리
    if characterypos < 0:
        characterypos = 0
    elif characterypos > screenheight-characterheight:
        characterypos = screenheight-characterheight    

    #충돌 처리를 위한 rect 정보 업데이트
    characterrect= character.get_rect() #사각형 정보 불러오기
    characterrect.left = characterxpos
    characterrect.top = characterypos
    enemyrect= enemy.get_rect()
    enemyrect.left = enemyxpos
    enemyrect.top = enemyypos
   
    #충돌 체크
    if characterrect.colliderect(enemyrect): #사각형 충돌 확인
        print("충돌!")
        running = False


    screen.blit(background, (0,0)) #배경 그리기
    # screen.fill((0,0,255))도 배경 채우기 가능
   
    screen.blit(character, (characterxpos, characterypos))
    screen.blit(enemy, (enemyxpos, enemyypos))

    #타이머 집어넣기
    #경과 시간 집어넣기
    elapsedtime= (pygame.time.get_ticks()-startticks) / 1000 #경과시간(ms)을 1000으로 나누어 초단위 표시

    timer = gamefont.render(str(int(totaltime-elapsedtime)), True, (255,255,255)) #10,9,8.. 본격 구현
    screen.blit(timer, (10,10))

    #만약 시간 0이하이면 게임 종료
    if totaltime - elapsedtime <= 0:
        print("타임아웃")
        running = False

    #잠시대기
    pygame.time.delay(2000) #2초 정도 대기 (ms)

    pygame.display.update() #게임화면 다시 그리기 (계속 호출하기)

#pygame 종료
pygame.quit()

 

 

 

프로젝트(똥피하기게임)


#1 모든 공을 없애면 게임 종료 (성공)
#2 캐릭터가 공에 닿으면 게임 종료 (실패)
#3 시간 제한 99초 초과 시 게임 종료 (실패)



import os
import pygame
#############################################################
 
pygame.init()

#화면 크기 설정
screenwidth = 640 #가로크기
screenheight = 480 #세로크기
screen = pygame.display.set_mode((screenwidth, screenheight))

#화면 타이틀 설정
pygame.display.set_caption("hello") #게임 이름

#FPS
clock = pygame.time.Clock()
#################################################################

#1. 사용자 게임 초기화 (배경 화면, 게임 이미지, 좌표, 속도, 폰트 등)
currentpath = os.path.dirname(__file__) #현재 파일 위치 반환
imagepath = os.path.join(currentpath, "images") #이미지 폴더 위치 반환

#배경 만들기
background = pygame.image.load(os.path.join(imagepath, "background.png"))

#스테이지 만들기
stage = pygame.image.load(os.path.join(imagepath, "stage.png"))
stagesize = stage.get_rect().size
stageheight = stagesize[1] #스테이지 높이 위에 캐릭터 두기 위해 사용

#캐릭터 만들기
character = pygame.image.load(os.path.join(imagepath, "character.png"))
charactersize = character.get_rect().size
characterwidth = charactersize[0]
characterheight = charactersize[1]
characterxpos = screenwidth/2 - characterwidth/2
characterypos = screenheight - stageheight - characterheight

#캐릭터 이동방향
charactertox = 0

#캐릭터 이동속도
characterspeed = 5

#무기 만들기
weapon = pygame.image.load(os.path.join(imagepath, "weapon.png"))
weaponsize = weapon.get_rect().size
weaponwidth = weaponsize[0]

#무기는 한번에 여러발 발사 가능
weapons = []

#무기 이동 속도
weaponspeed = 10

#공 만들기 (4개 크기 따로 처리)
ballimages = [
    pygame.image.load(os.path.join(imagepath, "ball1.png")),
    pygame.image.load(os.path.join(imagepath, "ball2.png")),
    pygame.image.load(os.path.join(imagepath, "ball3.png")),
    pygame.image.load(os.path.join(imagepath, "ball4.png"))]

#공 크기에 따른 최초 스피드
ballspeedy = [-18,-15, -12, -9]  왜 마이너스였지

#공들
balls = []

#최초 발생하는 큰 공 추가
balls.append({
    "posx" : 50, #공의 x 좌표
    "posy" : 50,  #공의 y 좌표
    "imgidx" : 0, #공의 이미지 인덱스
    "tox" : 3, #x축 이동방향, -3이면 왼쪽 3이면 오른쪽 이동
    "toy" : -6, #y축 이동방향,
    "initspdy" : ballspeedy[0]}) #y 최초 속도

#사라질 무기, 공 정보 저장
weapontoremove = -1
balltoremove = -1

#Font 정의
gamefont = pygame.font.Font(None, 40)
 
totaltime = 100
startticks = pygame.time.get_ticks() #시작시간 정의

#게임 종료 메시지
# Time over(시간 초과 실패)
# Mission Complete(성공)
# Game over(캐릭터 공 충돌, 실패)
gameresult = "Game Over"

running = True
while running:
    dt = clock.tick(30)
 
    #2. 이벤트 처리(키보드, 마우스 등)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                charactertox -= characterspeed
            elif event.key == pygame.K_RIGHT:
                charactertox += characterspeed
            elif event.key == pygame.K_SPACE: #무기 발사
                weaponxpos = characterxpos + characterwidth/2 - weaponwidth/2
                weaponypos = characterypos
                weapons.append([weaponxpos, weaponypos])
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                charactertox = 0


    #3. 게임 캐릭터 위치 정의
    characterxpos += charactertox

    if characterxpos < 0:
        characterxpos = 0
    if characterxpos > screenwidth - characterwidth:
        characterxpos = screenwidth - characterwidth

    #무기 위치 조정
    #100,200 ->y만 180, 160, 140....
    weapons =[ [w[0],w[1]-weaponspeed] for w in weaponsfor in 문이 반복도 포함이었나..

    #천장에 닿은 무기 없애기
    weapons =[ [w[0],w[1]-weaponspeed] for w in weapons if w[1] > 0]

    #공 위치 정의
    for ballidx, ballval in enumerate(balls):
        ballposx = ballval["posx"]
        ballposy = ballval["posy"]
        ballimgidx = ballval["imgidx"]

        ballsize = ballimages[ballimgidx].get_rect().size
        ballwidth = ballsize[0]
        ballheight = ballsize[1]
        #가로벽 부딪혔을 때 공 튕겨나오는 효과
        if ballposx <= 0 or ballposx > screenwidth - ballwidth:
            ballval["tox"] = ballval["tox"] * -1
        #세로벽 부딪혔을 때 공 튕겨나오는 효과
        if ballposy >= screenheight - stageheight - ballheight:
            ballval["toy"] = ballval["initspdy"]
        else: ballval["toy"] += 0.5 #그외 모든 경우 속도값 증가(속도값 마이너스기 때문에 느려짐)

        ballval["posx"] += ballval["tox"]
        ballval["posy"] += ballval["toy"]

    #4. 충돌 처리
 
    #캐릭터 rect 정보 업데이트
    characterrect = character.get_rect()
    characterrect.left = characterxpos
    characterrect.top = characterypos

    for ballidx, ballval in enumerate(balls):
        ballposx = ballval["posx"]
        ballposy = ballval["posy"]
        ballimgidx = ballval["imgidx"]

        #공 rect 정보 업데이트
        ballrect = ballimages[ballimgidx].get_rect()
        ballrect.left = ballposx
        ballrect.top = ballposy
       
        #공과 캐릭터 충돌 처리
        if characterrect.colliderect(ballrect):
            running = False
            break

        #공과 무기들 충돌 처리
        for weaponidx, weaponval in enumerate(weapons):
            weaponposx = weaponval[0]
            weaponposy = weaponval[1]

            #무기 rect 정보 업데이트
            weaponrect = weapon.get_rect()
            weaponrect.left = weaponposx
            weaponrect.top = weaponposy

            #충돌 체크
            if weaponrect.colliderect(ballrect):
                weapontoremove = weaponidx #해당 무기 없애기 위한 값 설정
                balltoremove = ballidx

                #가장 작은 크기 공이 아니라면 다음 단계의 공으로 나눠주기
                if ballimgidx < 3:

                    #현재 공 크기 정보 불러오기
                    ballwidth = ballrect.size[0]
                    ballheight = ballrect.size[1]

                    #나눠진 공 정보
                    smallballrect = ballimages[ballimgidx + 1].get_rect()
                    smallballwidth = smallballrect.size[0]
                    smallballheight = smallballrect.size[1]

                    #왼쪽으로 튕겨나가는 작은 공
                    balls.append({
                        "posx" : ballposx + ballwidth/2 - smallballwidth/2 , #공의 x 좌표
                        "posy" : ballposy + ballheight/2 - smallballheight/2 ,  #공의 y 좌표
                        "imgidx" : ballimgidx + 1, #공의 이미지 인덱스
                        "tox" : -3, #x축 이동방향, -3이면 왼쪽 3이면 오른쪽 이동
                        "toy" : -6, #y축 이동방향,
                        "initspdy" : ballspeedy[ballimgidx + 1]}) #y 최초 속도

                    #오른쪽으로 튕겨나가는 작은 공
                    balls.append({
                        "posx" : ballposx + ballwidth/2 - smallballwidth/2 , #공의 x 좌표
                        "posy" : ballposy + ballheight/2 - smallballheight/2 ,  #공의 y 좌표
                        "imgidx" : ballimgidx + 1, #공의 이미지 인덱스
                        "tox" : 3, #x축 이동방향, -3이면 왼쪽 3이면 오른쪽 이동
                        "toy" : -6, #y축 이동방향,
                        "initspdy" : ballspeedy[ballimgidx + 1]}) #y 최초 속도      

                break
        else: #계속 게임 진행
            continue #안쪽 for문 조건 맞지 않으면 continue, 바깥 for 문 계속 수행
        break #안쪽 for문에서 break를 만나면 여기로 진입 가능, 2중 for문을 한번에 탈출

    #충돌된 공 or 무기 없애기
    if balltoremove > -1 :
        del balls[balltoremove]
        balltoremove = -1
    if weapontoremove > -1 :
        del weapons[weapontoremove]
        weapontoremove = -1

    #모든 공 없앤 경우 게임 종료 (성공)
    if len(balls) == 0 :
        gameresult = "Mission Complete"
        running=False

    #5. 화면에 그리기
    screen.blit(background,(0,0))
    for weaponxpos, weaponypos in weapons:
        screen.blit(weapon,(weaponxpos,weaponypos))

    for idx, val in enumerate(balls):
        ballposx = val["posx"]
        ballposy = val["posy"]
        ballimgidx = val["imgidx"]
        screen.blit(ballimages[ballimgidx], (ballposx, ballposy))

    screen.blit(stage, (0,screenheight-stageheight))
    screen.blit(character,(characterxpos,characterypos))

    #경과시간 계산
    elapsedtime = (pygame.time.get_ticks() - startticks)/1000 #ms -> s
    timer = gamefont.render("Time:{}".format(int(totaltime -elapsedtime)), True, (255,255,255))
    screen.blit(timer, (10,10))

    #시간초과했다면
    if totaltime - elapsedtime <= 0:
        gameresult = "Time Over"
        running = False

    pygame.display.update() #게임화면 다시 그리기 (계속 호출하기)

    #게임오버 메시지
msg = gamefont.render(gameresult, True, (255,255,0))
msgrect = msg.get_rect(center=(int(screenwidth/2), int(screenheight/2)))
screen.blit(msg, msgrect)
pygame.display.update()

#2초 대기
pygame.time.delay(2000)

pygame.quit()

 

 

집중력이 낮아서 활용편 하나도 몇일을 보고 또 복습한 듯 하다. 하루에 다섯시간은 할애해서 2~3일만에 강의 수강, 복습, 2차 복습까지 하는 게 목표다. 헷갈리는 부분은 표시하고 다시 공부해봐야겠다.

'Programming > 파이썬' 카테고리의 다른 글

나도코딩 활용편1  (0) 2022.02.04