使用Pygame做一个乒乓球游戏

项目介绍

使用Pygame做一个乒乓球游戏。左侧为电脑,右侧为玩家。

在这里插入图片描述

视频地址-YT
视频搬运-B站
视频教程约90分钟。
代码地址

环境:需要pygame库,可用pip安装:pip install pygame

1. 基础版本

v1-1

首先进行一些初始化,初始化pygame以及物体的初始状态。
然后是主循环,游戏的主循环主要包含3个内容

  1. 处理事件(这里主要是键盘按键)
  2. 更新物体的状态
  3. 在屏幕上绘制
# 基础 ping pang游戏
import sys
import random
import pygame

# 初始化
pygame.init()
clock = pygame.time.Clock()

screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("PingPang")
# 使用长方形表示球和球拍
ball = pygame.Rect(screen_width // 2 - 15, screen_height // 2 - 15, 30, 30)
player = pygame.Rect(screen_width - 20, screen_height // 2 - 70, 10, 140)
opponent = pygame.Rect(10, screen_height // 2 - 70, 10, 140)

bg_color = pygame.Color('grey12')
light_grey = (200, 200, 200)

ball_speed_x = 7 * random.choice((1, -1))
ball_speed_y = 7 * random.choice((1, -1))    
player_speed = 0
opponent_speed = 7


while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                player_speed += 7
            if event.key == pygame.K_UP:
                player_speed -= 7
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                player_speed -= 7
            if event.key == pygame.K_UP:
                player_speed += 7
    
    # update
    #ball_animation()
    #player_animation()
    #opponent_animation()
    
    # draw
    screen.fill(bg_color)
    pygame.draw.rect(screen, light_grey, player)
    pygame.draw.rect(screen, light_grey, opponent)
    pygame.draw.ellipse(screen, light_grey, ball)
    pygame.draw.aaline(screen, light_grey, (screen_width / 2, 0), (screen_width / 2, screen_height))
    pygame.display.flip()
    clock.tick(60)

v1-2

然后我们实现上面的三个更新逻辑,更新物体状态。

  • ball_animation()
  • player_animation()
  • opponent_animation()
def ball_animation():
    """更新球的运动"""
    global ball_speed_x, ball_speed_y
    ball.x += ball_speed_x
    ball.y += ball_speed_y

    if ball.top <= 0 or ball.bottom >= screen_height:
        ball_speed_y *= -1
    if ball.left <= 0 or ball.right >= screen_width:
        ball_speed_x *= -1
        ball_restart()
    if ball.colliderect(player) or ball.colliderect(opponent):
        ball_speed_x *= -1

def player_animation():
    """更新玩家的运动"""
    player.y += player_speed
    if player.top <= 0:
        player.top = 0
    if player.bottom >= screen_height:
        player.bottom = screen_height

def opponent_animation():
    """更新对手的运动"""
    if opponent.top < ball.y:
        opponent.top += opponent_speed
    if opponent.bottom > ball.y:
        opponent.bottom -= opponent_speed
    if opponent.top <= 0:
        opponent.top = 0
    if opponent.bottom >= screen_height:
        opponent.bottom = screen_height

def ball_restart():
    """重置球的位置"""
    global ball_speed_x, ball_speed_y
    ball.center = (screen_width // 2, screen_height // 2)
    ball_speed_y *= random.choice((1, -1))
    ball_speed_x *= random.choice((1, -1))

实现了这3个函数后,记得在主循环中的# update 处调用这个三个函数。

2. 添加分数和时间

  1. 为游戏添加分数显示:添加字体并渲染出分数。
  2. 发球时有3秒倒计时:通过pygame.time.get_ticks() 获得时间。

在这里插入图片描述

# 添加得分和计时器
import sys
import random
import pygame


pygame.init()
clock = pygame.time.Clock()

screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("PingPang")



ball = pygame.Rect(screen_width // 2 - 15, screen_height // 2 - 15, 30, 30)
player = pygame.Rect(screen_width - 20, screen_height // 2 - 70, 10, 140)
opponent = pygame.Rect(10, screen_height // 2 - 70, 10, 140)

bg_color = pygame.Color('grey12')
light_grey = (200, 200, 200)

ball_speed_x = 7 * random.choice((1, -1))
ball_speed_y = 7 * random.choice((1, -1))    
player_speed = 0
opponent_speed = 7

# Text Variables
player_score = 0
opponent_score = 0
# 创建字体
game_font = pygame.font.Font("freesansbold.ttf", 32)

# Timer
score_time = True


def ball_animation():
    global ball_speed_x, ball_speed_y
    global player_score, opponent_score
    global score_time
    ball.x += ball_speed_x
    ball.y += ball_speed_y

    if ball.top <= 0 or ball.bottom >= screen_height:
        ball_speed_y *= -1
    if ball.left <= 0 or ball.right >= screen_width:    
        if ball.left <= 0:
            player_score += 1
        if ball.right >= screen_width:
            opponent_score += 1
        score_time = pygame.time.get_ticks()
        

    if ball.colliderect(player) or ball.colliderect(opponent):
        ball_speed_x *= -1

def player_animation():
    player.y += player_speed
    if player.top <= 0:
        player.top = 0
    if player.bottom >= screen_height:
        player.bottom = screen_height

def opponent_animation():
    if opponent.top < ball.y:
        opponent.top += opponent_speed
    if opponent.bottom > ball.y:
        opponent.bottom -= opponent_speed
    if opponent.top <= 0:
        opponent.top = 0
    if opponent.bottom >= screen_height:
        opponent.bottom = screen_height

def ball_restart():
    global ball_speed_x, ball_speed_y
    global score_time
    ball.center = (screen_width // 2, screen_height // 2)
	# 计算耗时,并显示剩余时间
	# 获得当前时间
    current_time = pygame.time.get_ticks()
	# 与上次得分时间比较
    if current_time - score_time < 700:
        number_three = game_font.render("3", False, light_grey)
        screen.blit(number_three, (screen_width // 2 - 10, screen_height // 2 + 20))
    if 700 < current_time - score_time < 1400:
        number_two = game_font.render("2", False, light_grey)
        screen.blit(number_two, (screen_width // 2 - 10, screen_height // 2 + 20))
    if 1400 < current_time - score_time < 2100:
        number_one = game_font.render("1", False, light_grey)
        screen.blit(number_one, (screen_width // 2 - 10, screen_height // 2 + 20))
    
    if current_time - score_time < 2100:
        ball_speed_x, ball_speed_y = 0, 0
    else:
        ball_speed_y = 7 * random.choice((1, -1))
        ball_speed_x = 7 * random.choice((1, -1))
        score_time = None

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                player_speed += 7
            if event.key == pygame.K_UP:
                player_speed -= 7
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                player_speed -= 7
            if event.key == pygame.K_UP:
                player_speed += 7

   
    
    ball_animation()
    player_animation()
    opponent_animation()
    # update
    # draw
    screen.fill(bg_color)
    pygame.draw.rect(screen, light_grey, player)
    pygame.draw.rect(screen, light_grey, opponent)
    pygame.draw.ellipse(screen, light_grey, ball)
    pygame.draw.aaline(screen, light_grey, (screen_width / 2, 0), (screen_width / 2, screen_height))
	# 显示得分
    player_text = game_font.render(f"{player_score}", False, light_grey)
    screen.blit(player_text, (660, 360))

    opponent_text = game_font.render(f"{opponent_score}", False, light_grey)
    screen.blit(opponent_text, (600, 360))
    if score_time:
        ball_restart()
   
    pygame.display.flip()
    clock.tick(60)

3. 优化碰撞逻辑、添加声音

如果你运行了第2节的程序,你会发现有时候球的反弹有时很奇怪,比如有时候会在球拍上。
本节我们将

  • 优化碰撞逻辑:在ball_animation()通过判断球与球拍的位置,修改球的运动。
  • 添加碰撞和得分音效: pygame.mixer.Sound
# 添加得分和计时器
# 基础 ping pang游戏
import sys
import random
import pygame

# setup
pygame.init()
pygame.mixer.pre_init(44100, -16, 2, 512)
clock = pygame.time.Clock()


screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("PingPang")


# Reactangles
ball = pygame.Rect(screen_width // 2 - 15, screen_height // 2 - 15, 30, 30)
player = pygame.Rect(screen_width - 20 , screen_height // 2 - 70, 10, 140)
opponent = pygame.Rect(10, screen_height // 2 - 70, 10, 140)

bg_color = pygame.Color('grey12')
light_grey = (200, 200, 200)

ball_speed_x = 7 * random.choice((1, -1))
ball_speed_y = 7 * random.choice((1, -1))    
player_speed = 0
opponent_speed = 7

# Text Variables
player_score = 0
opponent_score = 0
game_font = pygame.font.Font("freesansbold.ttf", 32)

# Timer
score_time = True

# Sound
pong_sound = pygame.mixer.Sound("pong.ogg")
score_sound = pygame.mixer.Sound("score.ogg")

def ball_animation():
    global ball_speed_x, ball_speed_y
    global player_score, opponent_score
    global score_time
    ball.x += ball_speed_x
    ball.y += ball_speed_y

    if ball.top <= 0 or ball.bottom >= screen_height:
        pong_sound.play()
        ball_speed_y *= -1
    # score 
    if ball.left <= 0 or ball.right >= screen_width:    
        score_sound.play()
        if ball.left <= 0:
            player_score += 1
        if ball.right >= screen_width:
            opponent_score += 1
        score_time = pygame.time.get_ticks()
        

    if ball.colliderect(player) and ball_speed_x > 0: 
        pong_sound.play()
        if abs(ball.right - player.left) < 10 :
            ball_speed_x *= -1
        elif abs(ball.bottom - player.top) < 10 and ball_speed_y > 0:
            ball_speed_y *= -1
        elif abs(ball.top - player.bottom) < 10 and ball_speed_y < 0:
            ball_speed_y *= -1
        
    if ball.colliderect(opponent) and ball_speed_x < 0:
        pong_sound.play()
        if abs(ball.left - opponent.right) < 10:
            ball_speed_x *= -1
        elif abs(ball.bottom - opponent.top) < 10 and ball_speed_y > 0:
            ball_speed_y *= -1     
        elif abs(ball.top - opponent.bottom) < 10 and ball_speed_y < 0:
            ball_speed_y *= -1

def player_animation():
    player.y += player_speed
    if player.top <= 0:
        player.top = 0
    if player.bottom >= screen_height:
        player.bottom = screen_height

def opponent_animation():
    if opponent.top < ball.y:
        opponent.top += opponent_speed
    if opponent.bottom > ball.y:
        opponent.bottom -= opponent_speed
    if opponent.top <= 0:
        opponent.top = 0
    if opponent.bottom >= screen_height:
        opponent.bottom = screen_height

def ball_restart():
    global ball_speed_x, ball_speed_y
    global score_time
    ball.center = (screen_width // 2, screen_height // 2)

    current_time = pygame.time.get_ticks()

    if current_time - score_time < 700:
        number_three = game_font.render("3", False, light_grey)
        screen.blit(number_three, (screen_width // 2 - 10, screen_height // 2 + 20))
    if 700 < current_time - score_time < 1400:
        number_two = game_font.render("2", False, light_grey)
        screen.blit(number_two, (screen_width // 2 - 10, screen_height // 2 + 20))
    if 1400 < current_time - score_time < 2100:
        number_one = game_font.render("1", False, light_grey)
        screen.blit(number_one, (screen_width // 2 - 10, screen_height // 2 + 20))
    
    if current_time - score_time < 2100:
        ball_speed_x, ball_speed_y = 0, 0
    else:
        ball_speed_y = 7 * random.choice((1, -1))
        ball_speed_x = 7 * random.choice((1, -1))
        score_time = None

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                player_speed += 7
            if event.key == pygame.K_UP:
                player_speed -= 7
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                player_speed -= 7
            if event.key == pygame.K_UP:
                player_speed += 7

   
    
    ball_animation()
    player_animation()
    opponent_animation()
    # update
    # draw
    screen.fill(bg_color)
    pygame.draw.rect(screen, light_grey, player)
    pygame.draw.rect(screen, light_grey, opponent)
    pygame.draw.ellipse(screen, light_grey, ball)
    pygame.draw.aaline(screen, light_grey, (screen_width / 2, 0), (screen_width / 2, screen_height))

    player_text = game_font.render(f"{player_score}", False, light_grey)
    screen.blit(player_text, (660, 360))

    opponent_text = game_font.render(f"{opponent_score}", False, light_grey)
    screen.blit(opponent_text, (600, 360))
    if score_time:
        ball_restart()
   
    pygame.display.flip()
    clock.tick(60)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/475066.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis相关操作大全一篇全搞定

Redis是单线程吗? Redis 的单线程主要是指 Redis 的网络 10 和键值对读写是由一个线程来完成的&#xff0c;这也是 Redis 对外提供键值存储服务的主要流程。但Redis 的其他功能&#xff0c;比如持久化、异步删除、集群数据同步等&#xff0c;其实是由额外的线程执行的。 Redi…

怎么在Linux系统下Docker部署Excalidraw白板工具并实现无公网IP远程访问?

文章目录 1. 安装Docker2. 使用Docker拉取Excalidraw镜像3. 创建并启动Excalidraw容器4. 本地连接测试5. 公网远程访问本地Excalidraw5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 本文主要介绍如何在Ubuntu系统使用Docker部署开源白板工具Excal…

如何在CentOS搭建docker compose ui可视化工具并无公网IP远程管理容器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

CSS隐藏video标签中各种控件

1.edio标签加上controls会出现视频控件&#xff0c;如播放按钮、进度条、全屏、观看的当前时间、剩余时间、音量按钮、音量的控制条等等 <video type"video/mp4" src"" autoplay"" style"width: 400px; height: 300px;" id"e…

刚进公司第一天-电脑环境搭建

写在前面 之前在公司做过一次开发小工具的分享&#xff0c;这两天有个同事找我学习一些小工具开发的知识&#xff0c;但是我发现他的基础是真的差&#xff0c;想学开发知识却连自己本地电脑环境都没弄好&#xff0c;确实&#xff0c;有些人工作了很久&#xff0c;由于自己工作中…

【笔记】网络安全相关法规学习(网络安全法、数据安全法、个人信息保护法)

文章目录 1. 作业及Presentation2. 国家主权基本要素、基本权利、基本原则3. 网络空间主权基本要素、基本权利、基本原则4. 网络安全法、数据安全法、个人信息保护法中的用语定义4.1 网安法用语定义4.2 数据安全法用语4.3 个人信息法用语4.4 法、条例等的区别 5. 网络安全法各条…

【Greenhills】GHS-MULTI IDE-Ubuntu纯命令系统部署license文件

【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 记录在Ubuntu纯命令系统中部署license文件的步骤。 2、 问题场景 客户服务器为Linux纯命令行的环境&#xff0c;客户也无其他服务器可以部署&#xff0c;需在纯命令行上尝试安装。 3、软硬件环境 1&#xff09…

三种方式,浅谈 Cocos Creator 的动画添加

前言 虽然 Cocos 的官方文档对动画系统做了较详细的介绍&#xff0c;但是对于刚接触的同学&#xff08;比如我&#xff09;来说还是不太友好。尽管如此&#xff0c;我就按文档加社区帖子一起实践了一下。为了方便忘记后能快速捡起&#xff0c;所以就用我的方式结合使用场景&am…

大屏页面 电子数字 制作

字体包下载地址 链接: https://pan.baidu.com/s/1pjslpT5QQi7-oALDM-uX8g 提取码: zxcv 效果展示 使用前使用后 使用方式 1.解压后将文件夹放入public 2.在公用样式中加入 font-face {font-family: mFont;src: url(../../public/DS-Digital/DS-DIGI-1.ttf); } 3. 在项目…

【ONE·基础算法 || 位运算】

总言 主要内容&#xff1a;编程题举例&#xff0c;理解位运算的思想。 文章目录 总言1、常见位运算总结1.1、基础位运算1.2、位图思想1.2.1、给一个数n&#xff0c;确定它的二进制表示中的第x位是0还是11.2.2、将一个数n的二进制表示的第x位修改成 11.2.3、将一个数n的二进制表…

管理公司员工上网行为的软件都有哪些?

随着互联网的飞速发展&#xff0c;企业面临的网络安全威胁也日益加剧。为了保护企业数据安全、提高工作效率&#xff0c;上网行为管理系统及其相关管理软件应运而生。 未来&#xff0c;随着技术的不断进步和网络安全威胁的不断演变&#xff0c;上网行为管理系统及其管理软件将不…

【Unity】Plastic云同步总是password error

【背景】 Plastic是Unity的项目版本控制功能&#xff0c;可以方便在多个地点同步项目进度。原本用得挺爽的&#xff0c;结果今天遇到糟心事&#xff0c;明明Hub也正常登着&#xff0c;可Plastic的一个update的dll就是不停反复运行并报Password invalid。 【问题分析】 听说I…

CClinkie转Devicenet网关在现场的案例

CClinkie转Devicenet网关在现场的案例 随着工业自动化的不断发展&#xff0c;不同的通讯协议在工厂现场设备之间传输数据显得尤为重要。然而&#xff0c;不同的设备可能支持不同的通讯协议&#xff0c;这为设备之间的互操作性带来了挑战。在这种情况下&#xff0c;网关设备应运…

linux终端下vi文本编辑器的基础使用方法

一、linux终端下vi文本编辑器的基础使用方法&#xff1a; 下面将提供一些在Linux终端中使用vi或vim&#xff08;vi的增强版&#xff09;的基础操作方法&#xff1a; 1.打开文件&#xff1a; vi filename.txt 如果文件存在&#xff0c;则打开该文件&#xff1b;如果不存在&a…

力扣爆刷第101天之hot100五连刷91-95

力扣爆刷第101天之hot100五连刷91-95 文章目录 力扣爆刷第101天之hot100五连刷91-95一、62. 不同路径二、64. 最小路径和三、5. 最长回文子串四、1143. 最长公共子序列五、72. 编辑距离 一、62. 不同路径 题目链接&#xff1a;https://leetcode.cn/problems/unique-paths/desc…

机器人路径规划:基于冠豪猪优化算法(Crested Porcupine Optimizer,CPO)的机器人路径规划(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

Python代码规范化

什么是代码规范化&#xff1f; 代码的规范化书写是指按照一定的规范和标准编写代码&#xff0c;使得代码结构清晰、易于阅读和理解。 代码规范化的意义 Python代码规范化的意义在于提高代码可读性、可维护性和可重用性&#xff0c;从而使代码更易于理解、调试和协作&#xff0c…

QKSMS:安卓开源短信应用的替代之选

QKSMS&#xff1a;安卓开源短信应用的替代之选 1. 引言 QKSMS是一个开源的安卓短信应用&#xff0c;旨在取代安卓系统自带的短信应用。它目前可以在Google Play商店和F-Droid上获取&#xff0c;并被誉为安卓平台上最美观的短信应用之一。本文将介绍QKSMS的特点、功能和优势&am…

一分钟了解自动化测试【建议收藏】

引子 写在最前面&#xff1a;目前自动化测试并不属于新鲜的事物&#xff0c;或者说自动化测试的各种方法论已经层出不穷&#xff0c;但是&#xff0c;能够明白自动化测试并很好落地实施的团队还不是非常多&#xff0c;我们接来下用通俗的方式来介绍自动化测试…… 本文共有2410…

TouchGFX之性能测量

TouchGFX Core开放了几个信号&#xff0c;可用于测量性能。 当这些信号在内部触发时&#xff0c;用户可在应用程序中同步触发单个GPIO&#xff0c;从而实现“渲染时间”和其他有用信号的可视化。 信号在GPIO.hpp中定义 /* 用于操作GPIO的接口类&#xff0c;以便在目标硬件上进…