Python练手项目(1)Pygame制作游戏

背景部分


创建Pygame窗口以及响应用户输入

# invasion.py

import sys
import pygame

def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()
    screen = pygame.display.set_mode((1200, 700))
    pygame.display.set_caption("Thunder")

    # 开始游戏的主循环
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()

        # 让最近绘制的屏幕可见
        pygame.display.flip()


run_game()
  1. 首先我们导入模块pygamesys。sys用于退出游戏
  2. 游戏以函数run_game()开头。
  3. pygame.init()用于初始化游戏背景。
  4. pygame.display.set_mode()用于创建一个名为screen的显示窗口。实参(1200,700)是一个元组,指定游戏窗口的尺寸。
  5. 对象screen是一个surface。在Pygame中,surface是屏幕的一部分,用于显示游戏元素(比如外星人、飞船),游戏中每个元素都是一个surface。激活游戏的动画循环后,每经过一次循环都将重新绘制这个surface。
  6. 为访问Pygame侦听到的时间,我们使用方法pygame.event.get()。所有的键盘和鼠标事件都将促使for循环运行。比如玩家点击窗口的关闭按钮时,将检测到pygame.QUIT事件,我们就调用sys.exit()来退出游戏。
  7. pygame.display.flip()命令Pygame让最近绘制的屏幕可见。它在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕。

绘制背景色

# 在while循环中加入如下语句:
    screen.fill((230,230,230))

Pygame中,颜色是以RGB值表示的。

创建设置类

#settings.py

class Settings():
    """存储游戏所有设置的类"""

    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕设置
        self.screen_width = 1200
        self.screen_length = 700
        self.bg_color = (230, 230, 230)

将所有游戏的设置存储在这个类中, 则invasion.py可修改:

import sys
import pygame

from settings import Settings


def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()
    sett = Settings()
    screen = pygame.display.set_mode(
        (sett.screen_length, sett.screen_width)
    )
    pygame.display.set_caption("Thunder")

    # 开始游戏的主循环
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()

        screen.fill(sett.bg_color)

        # 让最近绘制的屏幕可见
        pygame.display.flip()


run_game()


飞船部分


添加飞船图像

就选用书配套的素材吧

创建Ship类

import pygame


class Ship():

    def __init__(self, screen):
        self.screen = screen

        self.image = pygame.image.load("ship.bmp")
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        
    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)

在屏幕上绘制飞船

在invasion.py中创建飞船对象,并调用其方法blitme():

import sys
import pygame

from settings import Settings
from ship import Ship


def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()
    sett = Settings()
    screen = pygame.display.set_mode(
        (sett.screen_width, sett.screen_length)
    )
    pygame.display.set_caption("Thunder")
    ship = Ship(screen)


    # 开始游戏的主循环
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()

        screen.fill(sett.bg_color)
        ship.blitme()

        # 让最近绘制的屏幕可见
        pygame.display.flip()

run_game()

运行后结果:
在这里插入图片描述

重构:game_function模块


函数check_events()

我们把管理事件的代码移到一个名为check_events()的函数里,以简化run_game()

#game_function.py

import sys
import pygame


def check_events():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

函数update_screen()

为进一步简化run_game(),将更新屏幕的代码移到一个名为update_screen()的函数里,并将函数定义放在game_function中

def update_screen(sett, screen, ship):
    screen.fill(sett.bg_color)
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()




飞船移动部分


响应按键

每当用户按键时,都在Pygame里注册一个事件。事件都是通过方法pygame.event.get()获取的,因此在函数check_events()中,我们需要制定检查哪些类型的事件。
每次按键都被注册一个KEYDOWN事件。检测到该事件后,我们需要检查是否按下了特定的键,执行特定的操作。比如按下右键后,要让飞船向右移动。

def check_events(ship):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                ship.rect.centerx += 1       

我们在参数列表里加入了ship,因为需要能够访问到飞船内部的属性。

允许不断移动

玩家按住→键是希望飞船不停移动,直到松开为止。
我们可以让游戏检测pygame.KEYUP事件,然后结合KEYUP和KEYDOWN事件实现持续移动。

# ship.py
        def __init__(self, screen):
        ...
        self.right_move = False
	
	def update(self):
        if self.right_move:
            self.rect.centerx += 1

在飞船的类内初始化时多添了一个属性移动标志变量right_move
多添了一个方法update(),用于检查该标志变量,实现飞船属性更新:这个变量为True时,飞船就会向右移动。
而这个标志变量会因KEYDOWN变为True,因KEYUP变为False,以此来实现持续移动

同时,要在invasion.py的while循环里调用update()方法:

# invasion.py   
    while True:
        gf.check_events(ship)
        ship.update()
        gf.update_screen(sett, screen, ship)

左右移动

只需照着向右移动就能做出向左移动

调整飞行速度

每次执行while循环,飞船最多移动1像素。但可以在settings模块里加入属性ship_speed,用于控制飞船的速度。

# settings.py
class Settings():
    """存储游戏所有设置的类"""

    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕设置
        self.screen_width = 1200
        self.screen_length = 700
        self.bg_color = (230, 230, 230)
        self.ship_speed = 0.7

同时在ship.py中修改:

class Ship():

    def __init__(self, sett, screen):
        ...
        self.center = float(self.rect.centerx)
        ...
        
    	...

    def update(self):
        if self.right_move:
            self.center += sett.ship_speed
        if self.left_move:
            self.center -= sett.ship_speed

        self.rect.centerx = self.center
  • 在__init__()的形参中加入了setting类的sett,让飞船的方法update()可以获取其速度设置。
  • rect只存储整数,所以我们新建一个属性center,用flota()rect.centerx转化成小数存储到center中。更新center之后,再根据它来更新控制飞船位置的rect.centerx(虽然centerx只存储self.center的整数部分,但对于显示飞船而言问题不大。)

限制飞船活动范围

为了防止飞船飞出屏幕外,我们在飞船位置变更前添加if语句判断飞船是否将飞出框外。

# ship.py
    def update(self):
        if self.right_move and self.rect.right < self.screen_rect.right:
            self.center += self.sett.ship_speed
        if self.left_move and self.rect.left > 0:
            self.center -= self.sett.ship_speed

如果rect的左/右边缘没有触及屏幕左/右边缘,才可以移动。

重构check_event()

# game_function.py
def check_keydown(event, ship):
    if event.key == pygame.K_RIGHT:
        ship.right_move = True
    elif event.key == pygame.K_LEFT:
        ship.left_move = True


def check_keyup(event, ship):
    if event.key == pygame.K_RIGHT:
        ship.right_move = False
    elif event.key == pygame.K_LEFT:
        ship.left_move = False


def check_events(ship):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown(event, ship)

        elif event.type == pygame.KEYUP:
            check_keyup(event, ship)


子弹部分

添加子弹设置

在setting.py中添加新类Bullet所需的值:

    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕设置
        ...
        # 子弹设置
        self.bullet_speed = 1
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = (60, 60, 60)

创建Bullet类

# bullet.py
import pygame
from pygame.sprite import Sprite


class Bullet(Sprite):
    """一个对飞船的子弹管理的类"""

    def __init__(self, sett, screen, ship):
        """在飞船处创建一个子弹对象"""
    	super(Bullet, self).__init__()
    	self.screen = screen

    	self.rect = pygame.Rect(0, 0, sett.bullet_width, sett.bullet_height)
    	self.rect.centerx = ship.rect.centerx
    	self.rect.top = ship.rect.top

    	self.y = float(self.rect.y)

    	self.color = sett.bullet_color
    	self.speed_factor = sett.bullet_speed

子弹并非基于图像,因此我们必须使用pygame.Rect()类从空白开始创建一个矩形。创建这个类的实例时,必须提供矩形左上角的x坐标和y坐标,还有宽度和高度。我们先在(0,0)处创建一个矩形,并在接下来放在正确的位置,这个位置取决于飞船的位置。

接下来编写update()draw_bullet方法

    def update(self):
        """向上移动子弹"""
        
    	self.y -= self.speed
    	self.rect.y = self.y
     
    def draw_bullet(self):
        pygame.draw.rect(self.screen, self.color, self.rect)

将子弹存到编组中

在玩家每次按下空格时都射出一发子弹。首先我们在invasion.py中创建一个编组(Group)用于存储所有子弹,以便能够管理发射出去的子弹。
这个编组是pygame.sprite.Group类的一个实例;Group类 类似于列表,但提供了有助于游戏开发的功能。在主循环中,我们使用这个编组在屏幕上绘制子弹,更新每一个子弹的位置。

import sys
import pygame
import game_function as gf

from pygame.sprite import Group
from settings import Settings
from ship import Ship


def run_game():
    # 初始化游戏并创建一个屏幕对象
    ...
    bullets = Group()
    # 开始游戏的主循环
    while True:
        gf.check_events(sett, screen, ship, bullets)
        ship.update()
        bullets.update()
        gf.update_screen(sett, screen, ship, bullets)


run_game()

我们将bullets作为实参传递给了check_events()和update_screen()。在check_event()中我们要用空格处理bullets;在update_screen中则要更新绘制到屏幕上的bullets。
当你对编组调用update()时,编组将自动对每一个"精灵"调用update(),即对每一个子弹。

开火

因为只有在按下空格键时飞船才会开火,所以我们只需修改check_keydown_events()而不用修改keyup

# game_function.py
from bullet import  Bullet

def check_keydown(event, sett, screen, ship, bullets):
    if event.key == pygame.K_RIGHT:
        ship.right_move = True
    elif event.key == pygame.K_LEFT:
        ship.left_move = True
    elif event.key == pygame.K_SPACE:
        new_bullet = Bullet(sett, screen, ship)
        bullets.add(new_bullet)

def check_events(sett, screen, ship, bullets):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown(event, sett, screen, ship, bullets)
        elif event.type == pygame.KEYUP:
            check_keyup(event, ship)

def update_screen(sett, screen, ship, bullets):
    screen.fill(sett.bg_color)
    ship.blitme()
    for bullet in bullets:
        bullet.draw_bullet()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

删除已经消失的子弹

我们需要将已经飞出屏幕的子弹删除,减少内存负担。
为此,我们需要在每次更新子弹位置后,检测rect的bottom属性小于0的子弹,并删除它们。

# invasion.py
    while True:
        gf.check_events(sett, screen, ship, bullets)
        ship.update()
        bullets.update()

		for bullet in bullets.copy():
			if bullet.rect.bottom <= 0:
				bullets.remove(bullet)
			print(len(bullets))
			
        gf.update_screen(sett, screen, ship, bullets)
  • 在for循环中,不应从列表或编组中删除条目,因此必须是遍历编组的副本,故需要调用方法copy(),返回一个编组的副本。
  • 输出编组的长度,即有效子弹的数量,是为了显示子弹的数量,核实已消失的子弹确实被删除了。

子弹效果如图:
在这里插入图片描述

限制子弹数量

多数同类型游戏里面都会有对子弹数量的限制,鼓励玩家有目标地射击。
我们在此限制子弹最大数量为4.

首先在Setting类里设置允许的最大子弹数:

	#setting.py
	
   class Settings():
   """存储游戏所有设置的类"""

   def __init__(self):
       """初始化游戏的设置"""
       # 屏幕设置
       ...
       # 子弹设置
       ...
       self.bullet_allowed = 4	

在check_keydown_event()中检测到空格前,添加if语句判断子弹数量(群组长度)是否已经超过最大限制。

# game_function.py

def check_keydown(event, sett, screen, ship, bullets):
    if event.key == pygame.K_RIGHT:
        ship.right_move = True
    elif event.key == pygame.K_LEFT
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: Python利用pygame制作游戏是一种非常流行的方法。pygame是一个基于Python游戏开发库,它提供了许多游戏开发所需的功能,如图形、声音、输入、碰撞检测等。使用pygame,开发者可以轻松地创建2D游戏。 要使用pygame制作游戏,首先需要安装pygame库。安装完成后,可以使用pygame提供的函数和类来创建游戏窗口、加载图像、播放声音、处理用户输入等。开发者可以根据自己的需求来设计游戏的逻辑和玩法。 在制作游戏时,需要注意游戏的性能和用户体验。为了提高游戏的性能,可以使用一些优化技巧,如使用双缓冲技术、避免频繁的图像绘制等。为了提高用户体验,可以添加一些特效、音效和动画效果,使游戏更加生动有趣。 总之,Python利用pygame制作游戏是一项非常有趣和有挑战性的工作。通过不断的学习和实践,开发者可以创造出各种各样的精彩游戏。 ### 回答2: Python是一种非常流行的编程语言,适用于各种应用。Python的一个优点是可以轻而易举地制作游戏,其中一个流行的Python游戏引擎是pygamepygame提供了一组功能强大的游戏开发工具,是许多Python游戏开发者的首选。 在Python制作一个pygame游戏需要以下步骤: 1.安装pygame 要使用pygame,必须先安装它。可以通过pip命令轻松地安装pygame,如下所示: pip install pygame 2.创建游戏窗口 在pygame中,游戏窗口是承载游戏场景和对象的容器。可以使用pygame.display.set_mode()方法来创建一个游戏窗口: import pygame pygame.init() # Set up the display WIN_WIDTH = 800 WIN_HEIGHT = 600 screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) 3.创建游戏对象 在游戏中,对象是游戏动态的基本单元。游戏对象可以是玩家,敌人,迷宫,道具等等。要创建一个游戏对象,需要给它一个图像和位置: import pygame pygame.init() # Load the image ball_image = pygame.image.load("ball.png") # Set the position ball_x = 400 ball_y = 300 # Create the ball object ball = {"image": ball_image, "x": ball_x, "y": ball_y} 4.运行游戏循环 游戏循环是一个无限循环,用于更新游戏状态并渲染游戏。在pygame中,可以使用pygame.display.update()来更新游戏窗口,使用pygame.event.get()来获取所有游戏事件。 import pygame pygame.init() # Set up the display WIN_WIDTH = 800 WIN_HEIGHT = 600 screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # Set up the ball ball_image = pygame.image.load("ball.png") ball_x = 400 ball_y = 300 ball = {"image": ball_image, "x": ball_x, "y": ball_y} # Set up the game loop done = False while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # Update game objects ball_x += 1 ball["x"] = ball_x # Draw game objects screen.blit(ball["image"], (ball["x"], ball["y"])) pygame.display.update() 5.添加游戏逻辑 游戏逻辑是指游戏中的规则和交互,例如碰撞检测,得分系统和游戏状态等。可以将游戏逻辑添加到游戏循环中: import pygame pygame.init() # Set up the display WIN_WIDTH = 800 WIN_HEIGHT = 600 screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # Set up the ball ball_image = pygame.image.load("ball.png") ball_x = 400 ball_y = 300 ball_speed = 5 ball = {"image": ball_image, "x": ball_x, "y": ball_y, "speed": ball_speed} # Set up the game loop done = False while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # Update game objects ball_x += ball_speed if ball_x >= WIN_WIDTH: ball_speed = -ball_speed elif ball_x <= 0: ball_speed = -ball_speed ball["x"] = ball_x # Check for collisions # ... # Draw game objects screen.blit(ball["image"], (ball["x"], ball["y"])) pygame.display.update() 总的来说,python利用pygame制作游戏是简单易上手的。通过简单的Python代码,您可以创建各种各样的游戏,并让它们拥有各种各样的功能和特性。制作一个游戏可以提高代码编写水平,设计思路等多个方面,Pygame可谓是非常值得推荐的一款游戏开发框架。 ### 回答3: Python是一种流行的编程语言,具有简单易学和优雅的语法,还具有广泛的应用领域。Pygame则是Python中用于制作游戏的库,提供了丰富的API和模块,使得开发者可以轻松地创建各种游戏场景,并实现丰富的交互体验。 使用Pygame制作游戏,首先需要安装Pygame库,并配置好相应的开发环境。接着,可以通过使用Pygame提供的各种模块来实现游戏的各种功能,比如绘制游戏场景、添加动画效果、处理用户输入、播放音效等。具体来说,制作游戏的步骤包括以下几个方面: 1.准备素材。游戏中需要使用到各种素材,比如游戏背景、角色形象、道具、音效等,这些素材可以通过拍摄、绘制、采集等方式获得。制作游戏的时候,需要使用到一些图像和声音处理工具,如PIL、Audacity等。 2.绘制游戏场景。使用Pygame库提供的Surface类来创建游戏场景。Surface类是一个矩形区域,可以在其上绘制图像和文字。可以通过使用Pygame提供的各种绘图函数来对Surface对象进行绘制。 3.添加动画效果。可以使用Pygame中的Sprite类来创建游戏中的角色和道具。Sprite类可以用来表示游戏中的各个元素,并有自己的位置、速度等属性。使用Pygame提供的库可以实现动画,添加声音等交互效果。 4.处理用户输入。在游戏中,用户操作键盘、鼠标等方式进行交互,可以使用Pygame的事件处理模块来实现用户输入的检测和响应。 5.设计游戏规则。游戏规则会影响游戏的难度和趣味性。可以使用Python的面向对象编程思想来设计游戏规则,将各种游戏元素进行拆分,实现可扩展、可复用的代码结构。 总之,使用Pygame制作游戏是一项有趣的任务,可以锻炼自己的编程能力和创造力。在制作游戏的过程中,还可以了解游戏设计的相关知识、美工等技巧,对日后的工作或学习起到有益的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值