pygame - 贪吃蛇小游戏

蛇每吃掉一个身体块,蛇身就增加一个长度。为了统一计算,界面的尺寸和游戏元素的位置都是身体块长度的倍数
1. 上下左右方向键(或者ASDW键)控制蛇的移动方向
2. 空格键暂停和继续蛇的身体图片文件,复制到项目的asset\img目录下

import sys
import pygame
from pygame import Rect, font
import random# control panel contains the controllers and score
ControlPanelColor = (100, 100, 100)
# game panel is the main area for gaming
GamePanelColor = (0, 0, 0)
SnakeSize = 30
MaxWidthBlock = 15
MaxHeightBlock = 10
ControlPanelHeightBlock = 2
SnakeStartX = MaxWidthBlock // 2
SnakeStartY = MaxHeightBlock // 2
ControlPanelHeight = ControlPanelHeightBlock * SnakeSize
GamePanelWidth = MaxWidthBlock * SnakeSize
GamePanelHeight = MaxHeightBlock * SnakeSize
ControlPanelRect = Rect((0, 0), (GamePanelWidth, ControlPanelHeight))
GamePanelRect = Rect((0, ControlPanelHeight), (GamePanelWidth, GamePanelHeight - ControlPanelHeight))
Tick = 20
Tick_Snake_Move = 10
# two buttons to increase and decrease the game speed
minus_btn_rect = None
plus_btn_rect = None
# score
score_value = 0# the SnakeBody
class SnakeBody:def __init__(self, x, y, direction, ishead=False, istail=False):'''身体块,蛇身是由多个身体块组成,头和尾也是图案不同的身体块:param x: 身体块坐标x:param y: 身体块坐标y:param direction: 身体块显示的方向:param ishead: 是否头身体块:param istail:是否尾身体块'''self.__x = xself.__y = yself.__ishead = isheadself.__istail = istailself.__direction = directionname = Noneif self.__ishead:name = "head.png"elif self.__istail:name = "tail.png"else:name = "body.png"angle = 0match direction:case pygame.K_UP:angle = 0case pygame.K_DOWN:angle = 180case pygame.K_LEFT:angle = 90case pygame.K_RIGHT:angle = -90img = pygame.image.load(f"asset/img/{name}")img = pygame.transform.rotate(img, angle)self.image = pygame.transform.scale(img, (SnakeSize, SnakeSize))def get_rect(self):return Rect((self.__x, self.__y), (SnakeSize, SnakeSize))def move(self, x, y):self.__x = self.__x + xself.__y = self.__y + ydef set_direction(self, direction):if self.__direction == direction:returnself.__direction = directionname = Noneif self.__ishead:name = "head.png"elif self.__istail:name = "tail.png"else:name = "body.png"angle = 0match direction:case pygame.K_UP:angle = 0case pygame.K_DOWN:angle = 180case pygame.K_LEFT:angle = 90case pygame.K_RIGHT:angle = -90img = pygame.image.load(f"asset/img/{name}")img = pygame.transform.rotate(img, angle)self.image = pygame.transform.scale(img, (SnakeSize, SnakeSize))def get_direction(self):return self.__directionclass Snake:bodys = []new_body = None__new_direction = pygame.K_UP__tick_movement = 0__tick_create_body = 0__stop = False__is_paused = Falsedef __init__(self):self.bodys.insert(0, SnakeBody(SnakeSize * SnakeStartX, SnakeSize * SnakeStartY, pygame.K_UP, True, False))self.bodys.insert(1,SnakeBody(SnakeSize * SnakeStartX, SnakeSize * (SnakeStartY + 1), pygame.K_UP, False, False))self.bodys.insert(2,SnakeBody(SnakeSize * SnakeStartX, SnakeSize * (SnakeStartY + 2), pygame.K_UP, False, True))def set_direction(self, direction):# do not set inverse directionif ((self.bodys[0].get_direction() == pygame.K_UP and direction != pygame.K_DOWN) or(self.bodys[0].get_direction() == pygame.K_DOWN and direction != pygame.K_UP) or(self.bodys[0].get_direction() == pygame.K_LEFT and direction != pygame.K_RIGHT) or(self.bodys[0].get_direction() == pygame.K_RIGHT and direction != pygame.K_LEFT)):self.__new_direction = directiondef move(self):if self.__stop:returnif self.__is_paused:returnself.__tick_movement += 1if self.__tick_movement <= Tick_Snake_Move:returnself.__tick_movement = 0length = len(self.bodys)head = self.bodys[0]oldheadpos = head.get_rect()oldheaddirection = head.get_direction()# update head direction and movehead.set_direction(self.__new_direction)match self.__new_direction:case pygame.K_UP:head.move(0, -SnakeSize)case pygame.K_DOWN:head.move(0, SnakeSize)case pygame.K_LEFT:head.move(-SnakeSize, 0)case pygame.K_RIGHT:head.move(SnakeSize, 0)if ((self.new_body is not None) and(head.get_rect().x == self.new_body.get_rect().x and head.get_rect().y == self.new_body.get_rect().y)):# as head move, the old head position is empty,# add the new body at the second positionself.new_body.set_direction(head.get_direction())offsetx = oldheadpos.x - self.new_body.get_rect().xoffsety = oldheadpos.y - self.new_body.get_rect().yself.new_body.move(offsetx, offsety)self.bodys.insert(1, self.new_body)self.new_body = Noneglobal score_valuescore_value += 1else:# as head move, the old head position is empty,# move the second-to-last body to the second bodysecond2lastbody = self.bodys[length - 2]second2lastpos = second2lastbody.get_rect()second2lastdirection = second2lastbody.get_direction()offsetx = oldheadpos.x - second2lastpos.xoffsety = oldheadpos.y - second2lastpos.ysecond2lastbody.set_direction(oldheaddirection)second2lastbody.move(offsetx, offsety)self.bodys.remove(second2lastbody)self.bodys.insert(1, second2lastbody)# move tail to the direction of the second-to-last bodytailbody = self.bodys[length - 1]tailbody.set_direction(second2lastdirection)offsetx = second2lastpos.x - tailbody.get_rect().xoffsety = second2lastpos.y - tailbody.get_rect().ytailbody.move(offsetx, offsety)def stop(self):self.__stop = Truedef create_body(self):self.__tick_create_body += 1if self.__tick_create_body <= 30:returnif self.is_paused():returnself.__tick_create_body = 0if self.new_body is not None:returnx, y = 0, 0while True:isspare = Trueintx = random.randint(0, MaxWidthBlock - 1)inty = random.randint(ControlPanelHeightBlock, MaxHeightBlock - 1)x = intx * SnakeSizey = inty * SnakeSizefor b in self.bodys:rect = b.get_rect()if rect.x == x and rect.y == y:isspare = Falsebreakif isspare:breakprint(f"create body block at {intx}, {inty}")self.new_body = SnakeBody(x, y, pygame.K_UP, False, False)def is_collided(self):iscollided = Falsehead = self.bodys[0]headrect = self.bodys[0].get_rect()# boundary collisionif headrect.x <= (0 - SnakeSize) or headrect.x >= GamePanelWidth or \headrect.y <= (ControlPanelHeight - SnakeSize) or headrect.y >= (ControlPanelHeight + GamePanelHeight):iscollided = True# body collisionelse:if head.get_direction() == pygame.K_LEFT:passfor b in self.bodys[1:len(self.bodys)]:if head.get_rect().colliderect(b.get_rect()):iscollided = Truebreakreturn iscollideddef pause(self):self.__is_paused = not self.__is_pauseddef is_paused(self):return self.__is_pauseddef display_result():final_text1 = "Game Over"final_surf = pygame.font.SysFont("Arial", SnakeSize * 2).render(final_text1, 1, (242, 3, 36))  # 设置颜色screen.blit(final_surf, [screen.get_width() / 2 - final_surf.get_width() / 2,screen.get_height() / 2 - final_surf.get_height() / 2])  # 设置显示位置def display_paused():paused_text = "Paused"paused_surf = pygame.font.SysFont("Arial", SnakeSize * 2).render(paused_text, 1, (242, 3, 36))screen.blit(paused_surf, [screen.get_width() / 2 - paused_surf.get_width() / 2,screen.get_height() / 2 - paused_surf.get_height() / 2])def display_control_panel():global minus_btn_rect, plus_btn_rectcolor = (242, 3, 36)speed_text = "Speed"speed_surf = pygame.font.SysFont("Arial", SnakeSize).render(speed_text, 1, "blue")  # 设置颜色speed_rect = speed_surf.get_rect()speed_rect.x, speed_rect.y = 0, 0screen.blit(speed_surf, speed_rect)offsetx = speed_rect.x + speed_rect.width + 10text_minus = "-"minus_btn = pygame.font.SysFont("Arial", SnakeSize).render(text_minus, 1, color)  # 设置颜色minus_btn_rect = minus_btn.get_rect()minus_btn_rect.x, minus_btn_rect.y = offsetx, 0screen.blit(minus_btn, minus_btn_rect)offsetx = minus_btn_rect.x + minus_btn_rect.width + 10text_speed_value = str(Tick - Tick_Snake_Move)speed_value_surf = pygame.font.SysFont("Arial", SnakeSize).render(text_speed_value, 1, color)  # 设置颜色speed_value_rect = speed_value_surf.get_rect()speed_value_rect.x, speed_value_rect.y = offsetx, 0screen.blit(speed_value_surf, speed_value_rect)offsetx = speed_value_rect.x + speed_value_rect.width + 10text_plus = "+"plus_btn = pygame.font.SysFont("Arial", SnakeSize).render(text_plus, 1, color)  # 设置颜色plus_btn_rect = plus_btn.get_rect()plus_btn_rect.x, plus_btn_rect.y = offsetx, 0screen.blit(plus_btn, plus_btn_rect)score_value_text = str(score_value)score_value_surf = pygame.font.SysFont("Arial", SnakeSize).render(score_value_text, 1, color)  # 设置颜色score_value_rect = score_value_surf.get_rect()score_value_rect.x = GamePanelWidth - score_value_rect.widthscore_value_rect.y = 0screen.blit(score_value_surf, score_value_rect)score_text = "Score"score_surf = pygame.font.SysFont("Arial", SnakeSize).render(score_text, 1, "blue")  # 设置颜色score_rect = score_surf.get_rect()score_rect.x = score_value_rect.x - score_rect.width - 10score_rect.y = 0screen.blit(score_surf, score_rect)def check_click(position):global Tick_Snake_Moveif minus_btn_rect == None or plus_btn_rect == None:returnx, y = position[0], position[1]minus_btn_x, minus_btn_y = minus_btn_rect.x, minus_btn_rect.yplus_btn_x, plus_btn_y = plus_btn_rect.x, plus_btn_rect.yif minus_btn_x < x < minus_btn_x + minus_btn_rect.width and \minus_btn_y < y < minus_btn_y + minus_btn_rect.height:Tick_Snake_Move += 1elif plus_btn_x < x < plus_btn_x + plus_btn_rect.width and \plus_btn_y < y < plus_btn_y + plus_btn_rect.height:Tick_Snake_Move -= 1pygame.init()
pygame.font.init()  # 初始化字体
screen = pygame.display.set_mode((GamePanelWidth, ControlPanelHeight + GamePanelHeight))
clock = pygame.time.Clock()
snake = Snake()screen.fill(ControlPanelColor, ControlPanelRect)while True:clock.tick(20)for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_LEFT or event.key == pygame.K_a:snake.set_direction(pygame.K_LEFT)elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:snake.set_direction(pygame.K_RIGHT)elif event.key == pygame.K_UP or event.key == pygame.K_w:snake.set_direction(pygame.K_UP)elif event.key == pygame.K_DOWN or event.key == pygame.K_s:snake.set_direction(pygame.K_DOWN)elif event.key == pygame.K_SPACE:snake.pause()if pygame.mouse.get_pressed()[0]:check_click(pygame.mouse.get_pos())screen.fill(GamePanelColor, (0, ControlPanelHeight, GamePanelWidth, ControlPanelHeight + GamePanelHeight))snake.move()for body in snake.bodys:screen.blit(body.image, body.get_rect())# collision detectionif snake.is_collided():snake.stop()display_result()else:# new bodysnake.create_body()if snake.new_body is not None:screen.blit(snake.new_body.image, snake.new_body.get_rect())screen.fill(ControlPanelColor, (0, 0, GamePanelWidth, ControlPanelHeight))display_control_panel()if snake.is_paused():display_paused()pygame.display.flip()

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python逐日填补Excel中的日期并用0值填充缺失日期的数据

本文介绍基于Python语言&#xff0c;读取一个不同的列表示不同的日期的.csv格式文件&#xff0c;将其中缺失的日期数值加以填补&#xff1b;并用0值对这些缺失日期对应的数据加以填充的方法。 首先&#xff0c;我们明确一下本文的需求。现在有一个.csv格式文件&#xff0c;其第…

1.7.C++项目:仿muduo库实现并发服务器之Poller模块的设计

项目完整在&#xff1a; 文章目录 一、Poller模块&#xff1a;描述符IO事件监控模块二、提供的功能三、实现思想&#xff08;一&#xff09;功能&#xff08;二&#xff09;意义&#xff08;三&#xff09;功能设计 四、封装思想五、代码&#xff08;一&#xff09;框架&#…

轻量级网络IP扫描器WatchYourLAN

什么是 WatchYourLAN &#xff1f; WatchYourLAN 是一款带有 Web GUI 的轻量级网络 IP 扫描器。支持使用不同的主题和色彩模式进行个性化设置。 准备工作 扫描网络&#xff0c;首先要找到对应的网络接口&#xff0c;一般常见的包括 eth0、lo、docker0 等&#xff0c;可以在 SS…

Spring的依赖注入(DI)以及优缺点

Spring的依赖注入&#xff08;DI&#xff09;&#xff1a;解释和优点 依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;是Spring框架的核心概念之一&#xff0c;也是现代Java应用程序开发的重要组成部分。本文将深入探讨DI是什么&#xff0c;以及它的…

react项目从webpack迁移到vite的解决方案

虽然webpack是前端工程编译工具的王者&#xff0c;但是最近vite牛逼吹的震天响&#xff0c;说什么开发/生产打包速度甩webpack 100条街。不管是不是事实&#xff0c;总得尝试一下吧。 于是说干就干&#xff0c;在网上找了很多资料&#xff0c;终于搞定了&#xff0c;以下就是r…

[Linux]线程互斥

[Linux]线程互斥 文章目录 [Linux]线程互斥线程并发访问问题线程互斥控制--加锁pthread_mutex_init函数pthread_mutex_destroy函数pthread_mutex_lock函数pthread_mutex_unlock函数锁相关函数使用示例使用锁的细节加锁解锁的实现原理 线程安全概念常见的线程不安全的情况常见的…

C++:stl:stack、queue、priority_queue介绍及模拟实现和容量适配器deque介绍

本文主要介绍c中stl的栈、队列和优先级队列并对其模拟实现&#xff0c;对deque进行一定介绍并在栈和队列的模拟实现中使用。 目录 一、stack的介绍和使用 1.stack的介绍 2.stack的使用 3.stack的模拟实现 二、queue的介绍和使用 1.queue的介绍 2.queue的使用 3.queue的…

“在 ArchiMate EA 建模中的组合关系:构建块和依赖关系

简介 在企业架构&#xff08;EA&#xff09;建模领域&#xff0c;结构关系在描绘架构内静态一致性方面起着至关重要的作用。其中一个关键的结构关系是组合关系&#xff0c;这是 ArchiMate 语言中深植的概念&#xff0c;提供了一个全面的框架&#xff0c;用于表达元素如何组合形…

正点原子嵌入式linux驱动开发——TF-A移植

经过了之前的学习&#xff0c;除了TF-A的详细启动流程仍待更新&#xff0c;TF-A的使用和其对应的大致启动流程已经进行过了学习。但是当我们实际做产品时&#xff0c;硬件平台肯定会和ST官方的有区别&#xff0c;比如DDR容量会改变&#xff0c;自己的硬件没有使用到官方EVK开发…

Ubuntu使用cmake和vscode开发自己的项目,引用自己的头文件和openCV

创建文件夹 mkdir my_proj 继续创建include 和 src文件夹&#xff0c;形成如下的目录结构 用vscode打开项目 创建add.h #ifndef ADD_H #define ADD_Hint add(int numA, int numB);#endif add.cpp #include "add.h"int add(int numA, int numB) {return numA nu…

盒子阴影和网页布局

盒子阴影 box-shadow: 10px 10px 10px 4px rgba(0,0,0,.3);//最后一个是透明度 传统网页布局的三种方式 标准流 就是按照规定好的默认方式排列 1.块级元素&#xff1a;div、hr、p、h1~h2、ul、ol、dl、form、table 行内元素会按照书顺序&#xff0c;从左到右顺序排列&#…

黑豹程序员-架构师学习路线图-百科:Git/Gitee(版本控制)

文章目录 1、什么是版本控制2、特点3、发展历史4、SVN和Git比较5、Git6、GitHub7、Gitee&#xff08;国产&#xff09;8、Git的基础命令 1、什么是版本控制 版本控制系统&#xff08; Version Control &#xff09;版本控制是一种管理和跟踪软件开发过程中的代码变化的系统。它…