【Python語言學習】小人躲子彈-小遊戲學習

2020-10-14 19:00:33

Python小遊戲

​ 在python整個語言系統學完以後,我得知了Pygame這個擴充套件,發現相當的好用,所以在個人興趣下寫了小遊戲(還沒徹底寫完)作為學習.

遊戲整體設計

​ 視窗大小:1200×600

​ 遊戲基本內容:使用一個類似馬里奧的小人,進行類似飛機大戰形式的躲子彈遊戲:

​ 大致py檔案分類:

​ box類:類似馬里奧箱子那種,可以站立

​ bullet類:boss發射的子彈

​ hinder類:障礙物類,從螢幕的左右兩邊發射火球,擊中後主角死亡

​ part類:主人公類

​ road類:地面類,(emmmmmm本來可以不要這個,不知道咋的就加上了)

​ boss類:就是boss類

​ game_function:儲存遊戲的主要判定函數等等

​ main_cycle:遊戲主函數部分

​ setting類:儲存遊戲的設定等等

程式碼塊

main_cycle.py:

from time import sleep
import pygame
from settings import Settings
from part import Part
from BOSS import BOSS
from road import Road
from box import Box
import game_function as gf
from pygame.sprite import Group
import datetime
def run():
    pygame.init()
    game_setting=Settings()
    screen = pygame.display.set_mode((game_setting.screen_width, game_setting.screen_height))
    pygame.display.set_caption("茄理奧")
    box = Box(game_setting, screen)
    road = Road(game_setting, screen)
    boss = BOSS(screen,game_setting)
    part = Part(game_setting, screen,box,road)
    hinders=Group()
    hinder1s = Group()
    bullets = Group()
    # dt = datetime.datetime.now()
    gf.create_fleet(game_setting, screen, hinders)
    gf.create_fleet1(game_setting, screen, hinder1s)
    gf.create_bullet(game_setting,screen,bullets,boss)
    # gf.create_bullet(game_setting,screen,bullets,boss)
    while True:
        # 監聽
            gf.check_events(part)
            part.update()
            boss.update()
            hinders.update()
            hinder1s.update()
            bullets.update()
            for hinder in hinders.copy():
                if hinder.rect.bottom >550 or hinder.rect.top<0 or hinder.rect.left<0 or hinder.rect.right>1200:
                    hinders.remove(hinder)
                if len(hinders)<1:
                    hinders.remove(hinder)
                    gf.create_fleet(game_setting, screen, hinders)
            for hinder1 in hinder1s.copy():
                if hinder1.rect.bottom > 550 or hinder1.rect.top < 0 or hinder1.rect.left < 0 or hinder1.rect.right > 1500:
                    hinder1s.remove(hinder1)
                if len(hinder1s) < 1:
                    hinder1s.remove(hinder1)
                    gf.create_fleet1(game_setting, screen, hinder1s)
            for bullet in bullets.copy():
                if bullet.rect.bottom > 550 or bullet.rect.top < 0 or bullet.rect.left < 0 or bullet.rect.right > 1200:
                    bullets.remove(bullet)
                if len(bullets) < 5:
                    bullets.remove(bullet)
                    gf.create_bullet(game_setting, screen, bullets,boss)
            gf.update_screen(game_setting, screen, part,hinders,boss,bullets,road,box,hinder1s)
run()

settings.py:

#因為後面程式碼越寫越亂,本來好多東西應該放在設定類裡面,請大家別學習這種行為
import pygame
class Settings(object):
    """儲存遊戲中所有的設定類"""
    def __init__(self):
        """初始化遊戲設定"""
        #螢幕設定
        self.screen_width = 1200
        self.screen_height =600
        self.bg_img =pygame.image.load("image/backgroud.jpg")
        self.img1 = pygame.transform.scale(self.bg_img, (1200, 553))
        self.a = 1
        self.part_speed_factor = 3
        self.time = 5
        self.boss_speed_factor = 1.5

game_function.py:

import pygame,sys,random
from hinder import Hinder
from hinder1 import Hinder1
from bullet import  BULLET
def check_keydown_events(event,part):
    if event.key == pygame.K_RIGHT:
        part.moving_right = True
        part.direction = True
    if event.key == pygame.K_LEFT:
        part.moving_left = True
        part.direction = False
    if event.key == pygame.K_UP:
        part.isjump = True
def check_keyup_events(event,part):
    if event.key == pygame.K_RIGHT:
        part.moving_right = False
    if event.key == pygame.K_LEFT:
        part.moving_left = False
def check_events(part):
    """響應按鍵和滑鼠事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event,part)
        elif event.type ==pygame.KEYUP:
            check_keyup_events(event,part)
def update_screen(game_setting,screen,part,hinders,boss,bullets,road,box,hinder1s):
    """更新螢幕上的影象"""
    #每次呼叫時都回圈繪製螢幕
    screen.blit(game_setting.img1,(0,0))     #在遊戲視窗上顯示背景圖片,背景圖片比遊戲視窗大,否則視窗周邊將用黑邊填充
    # screen.fill(255,0,0)
    part.blitme()
    hinders.draw(screen)
    boss.blitim()
    road.blitme()
    box.blitme()
    hinder1s.draw(screen)
    bullets.draw(screen)
    for hinder in hinders:
         part.part_hinder_collide(hinder)
    for hinder1 in hinders:
        part.part_hinder_collide(hinder1)

    # part.Ispeng()
    for bullet in bullets:
        part.part_bullet_collide(bullet)


    #繪製螢幕課件(測試)
    pygame.display.flip()
def create_fleet(game_setting, screen,hinders):
    for hinder_number in range(1):
        hinder=Hinder(game_setting, screen)
        hinder.x=0
        hinder.y =random.randint(0,500)
        hinder.rect.x=hinder.x
        hinders.add(hinder)

def create_fleet1(game_setting, screen,hinder1s):
    for hinder1_number in range(1):
        hinder1=Hinder1(game_setting, screen)
        hinder1.x=1180
        hinder1.y =random.randint(0,500)
        hinder1.rect.x=hinder1.x
        hinder1s.add(hinder1)

def create_bullet(game_setting,screen,bullets,boss):
    for bullet_number in range(10):
        bullet = BULLET(game_setting,screen)
        bullet.x = boss.rect.centerx
        bullet.y = boss.rect.bottom
        bullet.rect.x = bullet.x
        bullets.add(bullet)

part.py:

from time import sleep

import pygame

class Part():
    def __init__(self, game_setting, screen,box,road):
        """設定角色的初始化位置"""
        self.road=road
        self.box = box
        self.screen = screen
        self.game_setting = game_setting
        # 載入角色影象,並獲得他的外解矩形位置
        self.image = pygame.image.load("image/part_0.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        # 將新繪製的角色放在螢幕底部中間
        self.rect.centerx = self.screen_rect.centerx-200
        self.rect.centery = self.screen_rect.bottom-100
        # 在屬性中儲存小數值
        self.center = float(self.rect.centerx)
        self.center2 = float(self.rect.centery)
        # # 移動標誌
        self.moving_right = False
        self.moving_left = False
        self.moving_top = False
        self.moving_bottom = False
        self.isjump=False
        self.direction=True#角色圖片的朝向
        self.ispeng=False
        self.isdie=False

    def jump(self):
        if self.game_setting.time >= -5 and not(self.isdie):
            a = self.game_setting.a  # 前半段減速上跳
            if self.game_setting.time < 0:
                a = -self.game_setting.a  # 後半段加速下落
            self.center2 -= 0.5 * a * (self.game_setting.time ** 2)  # 勻加速直線運動的位移公式
            if self.center2 < 60:
                self.center2 = 60  # 防止跳出邊界
            if self.center2 > self.road.rect.top - 110:
                self.center2 = self.road.rect.top - 110  # 防止跳出邊界
            self.game_setting.time -= 0.1
        else:
            a = self.game_setting.a
            self.isjump = False
            self.game_setting.time = 5
    def update(self):
        """根據移動標誌調整角色的位置"""
        # 更新角色的center值,不是rect
        if not(self.isjump) and not(self.isdie) :
            if not (self.ispeng):
                if self.moving_right and self.rect.right < self.screen_rect.right:
                    self.center += self.game_setting.part_speed_factor
                if self.moving_left and self.rect.left > 0:
                    self.center -= self.game_setting.part_speed_factor
                if self.center2 != self.road.rect.top-50:
                    self.center2 = self.road.rect.top-50
            else:
                if self.moving_right and self.rect.right < self.screen_rect.right:
                    self.center += self.game_setting.part_speed_factor
                if self.moving_left and self.rect.left > 0:
                    self.center -= self.game_setting.part_speed_factor
        if not(self.isjump) and self.isdie:
            if not (self.ispeng):
                if self.center2 != self.road.rect.top:
                    self.center2 = self.road.rect.top
        if self.isjump:
            if self.moving_right and self.rect.right < self.screen_rect.right:
                self.center += self.game_setting.part_speed_factor
            if self.moving_left and self.rect.left > 0:
                self.center -= self.game_setting.part_speed_factor
            self.jump()

        # 根據self.center 更新 rect
        self.rect.centerx = self.center
        self.rect.centery = self.center2
        if self.isjump==True and not(self.isdie):
            self.image = pygame.image.load("image/part_1.png")
        if self.isjump==False and not(self.isdie):
            self.image = pygame.image.load("image/part_0.png")
        if self.isjump==False and self.moving_left==True and not(self.isdie):
            self.image = pygame.image.load("image/part_4.png")
        if self.isjump==False and self.moving_right==True and not(self.isdie):
            self.image = pygame.image.load("image/part_4.png")
        if self.isjump==False and self.moving_right==False and self.moving_left==False and not(self.isdie):
            self.image = pygame.image.load("image/part_0.png")
        if self.isdie:
            self.image = pygame.image.load("image/part_die.png")
    def blitme(self):
        """在指定位置繪製角色"""
        img1 = pygame.transform.flip(self.image, True, False)
        if self.direction==False:
            self.screen.blit(img1, self.rect)
        else:
            self.screen.blit(self.image, self.rect)

    def part_hinder_collide(self, hinders):
        if pygame.Rect.colliderect(pygame.Rect(self.rect.x+35, self.rect.y, 50, 80), pygame.Rect(hinders.rect.x+122, hinders.rect.y+88, 60, 60)):
            self.isdie = True

    def part_bullet_collide(self, bullets):
        if pygame.Rect.colliderect(pygame.Rect(self.rect.x+35, self.rect.y, 50, 80), pygame.Rect(bullets.rect.x, bullets.rect.y, 22, 22)):
            self.isdie = True

road.py:

import pygame
class Road():
    def __init__(self, game_setting, screen):
        """設定角色的初始化位置"""
        self.screen = screen
        self.game_setting = game_setting
        # 載入角色影象,並獲得他的外解矩形位置
        self.image = pygame.image.load("image/road.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        self.rect.centery = 710
        self.img1 = pygame.transform.scale(self.image, (1200, 47))
        # 在屬性中儲存小數值
        self.center1 = float(self.rect.centerx)
        self.center2 = float(self.rect.centery)
    def blitme(self):
        """在指定位置繪製角色"""
        self.screen.blit(self.img1, self.rect)

box.py :

#箱子還沒範例化出來,後續會寫
import pygame
class Box():
    def __init__(self, game_setting, screen):
        """設定角色的初始化位置"""
        self.screen = screen
        self.game_setting = game_setting
        # 載入角色影象,並獲得他的外解矩形位置
        self.image = pygame.image.load("image/box.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        # 將新繪製的角色放在螢幕底部中間
        self.rect.centerx = self.screen_rect.centerx + 200
        self.rect.centery = 470
        self.img1=pygame.transform.scale(self.image,(200,40))

boss.py:

import pygame

#boss類
class BOSS():
    def __init__(self, screen, game_setting):
        # 初始化BOSS並設定初始位置
        self.screen = screen
        self.game_setting = game_setting
        # 載入BOSS影象
        self.image = pygame.image.load("image/boss.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        # 讓BOSS出生在螢幕頂側
        self.rect.centerx = self.screen_rect.centerx
        self.rect.top = self.screen_rect.top
        # 在boss屬性中儲存小數值
        self.center = float(self.rect.centerx)
        # 移動標誌
        self.moving_right = True

    def update(self):
        if self.moving_right:
            if self.center < self.screen_rect.right:
                self.center += self.game_setting.boss_speed_factor
            else:
                self.center -= self.game_setting.boss_speed_factor
                self.moving_right = False
        else:
            if self.center > self.screen_rect.left:
                self.center -= self.game_setting.boss_speed_factor
                self.moving_right = False
            else:
                self.center += self.game_setting.boss_speed_factor
                self.moving_right = True
        # # # 根據self.center跟新rect
        self.rect.centerx = self.center
    # 指定位置繪製BOSS
    def blitim(self):
        img1 = pygame.transform.flip(self.image, True, False)
        if self.moving_right==False:
            self.screen.blit(img1, self.rect)
        else:
            self.screen.blit(self.image, self.rect)

bullet.py:

import pygame,random
from pygame.sprite import Sprite

class BULLET(Sprite):
    def __init__(self,game_setting,screen):
        #初始化子彈位置
        super(BULLET, self).__init__()
        self.screen = screen
        self.game_setting = game_setting
        #載入子彈影象,
        self.image = pygame.image.load("image/bullet.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        #讓子彈出生在boss圖下
        # self.rect.x = self.boss.rect.centerx
        # self.rect.y = self.boss.rect.bottom

        # 在屬性中儲存小數值
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height

        # 在屬性中儲存小數值
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        # 設定子彈速度
        self.speed_factor_Y = random.randint(-5, 5)
        self.speed_factor_X = random.randint(-3,3)

    def update(self):
        self.x += self.speed_factor_X
        self.y += self.speed_factor_Y
        self.rect.y = self.y
        self.rect.x = self.x
    # def blitme(self):
    #     """在指定位置繪製角色"""
    #     self.screen.blit(self.image, self.rect)

hinder.py:

import pygame,random
from pygame.sprite import Sprite

class Hinder(Sprite):
    def __init__(self, game_setting, screen):
        """設定角色的初始化位置"""
        super(Hinder,self).__init__()
        self.screen = screen
        self.game_setting = game_setting
        # 載入角色影象,並獲得他的外解矩形位置
        self.image = pygame.image.load("image/hinder.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        # 將新繪製的角色放在螢幕底部中間
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height

        # 在屬性中儲存小數值
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        #設定子彈速度
        self.speed_factor_Y = random.randint(1,2)
        self.speed_factor_X = random.randint(2,4)
    def update(self):
        self.x += self.speed_factor_X
        self.y +=self.speed_factor_Y
        self.rect.y=self.y
        self.rect.x=self.x
    # def blitme(self):
    #     """在指定位置繪製角色"""
    #     self.screen.blit(self.image, self.rect)

​ ps:為了省事,我直接寫了個hinder1類,實際上直接用hinder在範例化一個就可以了,但是把生成位置寫死了,改起來很簡單,但是我有點懶:所以

hinder1.py:

import pygame,random
from pygame.sprite import Sprite

class Hinder1(Sprite):
    def __init__(self, game_setting, screen):
        """設定角色的初始化位置"""
        super(Hinder1,self).__init__()
        self.screen = screen
        self.game_setting = game_setting
        # 載入角色影象,並獲得他的外解矩形位置
        self.image = pygame.image.load("image/hinder1.png")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        # 將新繪製的角色放在螢幕底部中間
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height

        # 在屬性中儲存小數值
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        #設定子彈速度
        self.speed_factor_Y = random.randint(1,2)
        self.speed_factor_X = random.randint(-4,-2)
    def update(self):
        self.x += self.speed_factor_X
        self.y +=self.speed_factor_Y
        self.rect.y=self.y
        self.rect.x=self.x
    # def blitme(self):
    #     """在指定位置繪製角色"""
    #     self.screen.blit(self.image, self.rect)

​ 程式碼完成的很草率,有很多地方還能優化,死亡畫面和計分都沒加

後續完成: 功能(boss血量,主人公血量,死亡畫面,等)

​ 函數(程式碼整合優化,主人公攻擊boss,計分,等)

#程式碼完成:
@by本人
	main_cycle,game_function,part,settings,部分整合
@by Siranyu
	boss,bullet,部分整合	
@by 小zhang
	hinder,hinder1,road,box