美文网首页
pygame 练手项目

pygame 练手项目

作者: 圣_狒司机 | 来源:发表于2023-03-30 12:45 被阅读0次

    几个小孩在屏幕上乱跑的项目,撞人要互相说对不起!


    1.005.png

    解平对张娟说:对不起!
    张娟对解平说:对不起!
    王兵对马桂珍说:对不起!
    马桂珍对王兵说:对不起!

    一、 架构
    init.py
    play.py : 主入口文件
    player.py : 精灵类文件
    d61f0565d821438c9b7dcd4f48d5395d.png :人物图片
    所有文件全部在一个文件夹内,调用play.py运行游戏。

    二、主入口文件 play.py

    import pygame
    from player import Player,my_group
    from rich import print
    
    pygame.init()
    screen = pygame.display.set_mode((400,300))
    clock,FPS = pygame.time.Clock(),30
    running = True
    [Player() for _ in range(5)]
    step = 0
    
    while running:
        screen.fill((0, 255, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
               running = False
        
        my_group.update()
        my_group.draw(screen)
        pygame.display.flip()
        clock.tick(FPS)
        step += 1
        if step>1000:
            pygame.image.save(screen,f"{step/1000}.png")
    
    pygame.quit()
    

    这是pygame的基本框架,每个pygame项目都会这么写。

    if step>1000:
            pygame.image.save(screen,f"{step/1000}.png")
    

    是游戏运行一段时间后自动截屏。

    二、 精灵类文件player.py

    import pygame
    from pygame.sprite import Sprite
    from itertools import cycle
    import numpy as np
    from faker import Faker
    
    faker = Faker("zh_CN")
    my_group = pygame.sprite.Group()
    
    def collided(sprite, other):
        return sprite != other and sprite.rect.colliderect(other.rect)
    
    class Player(Sprite):
        img = pygame.image.load("d61f0565d821438c9b7dcd4f48d5395d.png")
        fps_p = 30
        d1 = cycle([img.subsurface((0,0,32,32))]*fps_p+[img.subsurface((32,0,32,32))]*fps_p+[img.subsurface((64,0,32,32))]*fps_p+[img.subsurface((95,0,32,32))]*fps_p)
        d2 = cycle([img.subsurface((0,32,32,32))]*fps_p+[img.subsurface((32,32,32,32))]*fps_p+[img.subsurface((64,32,32,32))]*fps_p+[img.subsurface((95,32,32,32))]*fps_p)
        d3 = cycle([img.subsurface((0,64,32,32))]*fps_p+[img.subsurface((32,64,32,32))]*fps_p+[img.subsurface((64,64,32,32))]*fps_p+[img.subsurface((95,64,32,32))]*fps_p)
        d4 = cycle([img.subsurface((0,95,32,32))]*fps_p+[img.subsurface((32,95,32,32))]*fps_p+[img.subsurface((64,95,32,32))]*fps_p+[img.subsurface((95,95,32,32))]*fps_p)
        image_lib= {"stand":d1,"go_up":d4,"go_left":d2,"go_right":d3,"go_down":d1} 
        speed_lib= {"stand":(0,0),"go_up":(1,-5),"go_left":(-5,-1),"go_right":(5,1),"go_down":(-1,5)}
    
        def __init__(self):
            self.name = faker.name()
            super().__init__()
            self.state = "stand"
            self.image = self.image_lib[self.state].__next__()
            self.spped = self.speed_lib[self.state]
            self.rect = self.image.get_rect()
            self.rect.center = np.random.randint(0,300,2)
            my_group.add(self)
            self.steps = 0
        
        def update(self):
            self.steps += 1
            keys = pygame.key.get_pressed()
            if keys[pygame.K_RIGHT]:
                self.state = "go_right"
            if keys[pygame.K_LEFT]:
                self.state = "go_left"
            if keys[pygame.K_UP]:
                self.state = "go_up"
            if keys[pygame.K_DOWN]:
                self.state = "go_down"
            if keys[pygame.K_SPACE]:
                self.state = "stand"
            if keys[pygame.K_LCTRL]:
                self.state = np.random.choice(["stand","go_up","go_left","go_right","go_down"],p=np.array([1,3,3,3,3])/np.array([1,3,3,3,3]).sum())
            if self.rect.left <0:
                self.state = np.random.choice(["stand","go_up","go_right","go_down"])
            if self.rect.right >400:
                self.state = np.random.choice(["stand","go_up","go_left","go_down"])
            if self.rect.top <0:
                self.state = np.random.choice(["stand","go_left","go_right","go_down"])
            if self.rect.bottom >300:
                self.state = np.random.choice(["stand","go_up","go_left","go_right"])
            if self.steps>100:
                self.state = np.random.choice(["stand","go_up","go_left","go_right","go_down"])
                self.steps = 0
    
            self.image = self.image_lib[self.state].__next__()
            self.spped = self.speed_lib[self.state]
            self.rect.move_ip(self.spped)
    
            col = pygame.sprite.spritecollideany(self, my_group, collided)
            if col:
                print(f"{self.name}对{col.name}说:对不起!")
    

    精灵图:


    精灵图是4*4的整合图片,pygame是每帧读取的,把任务动作分解成状态类,['站着','往左','往右','往前','往后'],站着的状态图可以取'往后'。
    每个状态用Python的itertools.cycle包裹,cycle的特性是无限循环,每次yield出一张图片,每个状态都有多张图片,cycle最适合pygame每次循环挤出一张图片的场景。
    把状态类集合成字典:

    d1 = cycle([img.subsurface((0,0,32,32))]*fps_p+[img.subsurface((32,0,32,32))]*fps_p+[img.subsurface((64,0,32,32))]*fps_p+[img.subsurface((95,0,32,32))]*fps_p)
    d2 = cycle([img.subsurface((0,32,32,32))]*fps_p+[img.subsurface((32,32,32,32))]*fps_p+[img.subsurface((64,32,32,32))]*fps_p+[img.subsurface((95,32,32,32))]*fps_p)
    d3 = cycle([img.subsurface((0,64,32,32))]*fps_p+[img.subsurface((32,64,32,32))]*fps_p+[img.subsurface((64,64,32,32))]*fps_p+[img.subsurface((95,64,32,32))]*fps_p)
    d4 = cycle([img.subsurface((0,95,32,32))]*fps_p+[img.subsurface((32,95,32,32))]*fps_p+[img.subsurface((64,95,32,32))]*fps_p+[img.subsurface((95,95,32,32))]*fps_p)
    image_lib= {"stand":d1,"go_up":d4,"go_left":d2,"go_right":d3,"go_down":d1} 
    

    fps_p 是放大的循环次数,要是没有放大,每张图片就在每个FPS里面一闪而过,根本看不清。
    每张图片的取出方法:先确定当前状态,再挤出一个图片。

    self.state = "stand"
    self.image = self.image_lib[self.state].__next__()
    

    每个精灵类都要重写update方法,因为没法在精灵类外部获得event事件,它里面有个特殊函数:keys = pygame.key.get_pressed(),获得需要的键盘事件,也可以把事件函数写在主文件里,那样主文件就很大很难看。

    三、 碰撞检测

    def collided(sprite, other):
        return sprite != other and sprite.rect.colliderect(other.rect)
    
    col = pygame.sprite.spritecollideany(self, my_group, collided)
            if col:
                print(f"{self.name}对{col.name}说:对不起!")
    

    pygame 有很丰富的碰撞检测,可是都无法直接用到本项目里!它自带的检测函数:

    方法 说明
    collide_rect() 两个精灵之间的矩形检测,即矩形区域是否有交汇,返回一个布尔值。
    collide_circle() 两个精灵之间的圆形检测,即圆形区域是否有交汇,返回一个布尔值。
    collide_mask() 两个精灵之间的像素蒙版检测,更为精准的一种检测方式。
    spritecollide() 精灵和精灵组之间的矩形碰撞检测,一个组内的所有精灵会逐一地对另外一个单个精灵进行碰撞检测,返回值是一个列表,包含了发生碰撞的所有精灵。
    spritecollideany() 精灵和精灵组之间的矩形碰撞检测,上述函数的变体,当发生碰撞时,返回组内的一个精灵,无碰撞发生时,返回 None。
    groupcollide() 检测在两个组之间发生碰撞的所有精灵,它返回值是一个字典,将第一组中发生碰撞的精灵作为键,第二个组中发生碰撞的精灵作为值。

    精灵与组碰撞检测,如果精灵在组内,结果会是精灵与组一直碰撞,调用
    pygame.sprite.spritecollideany(self, my_group),返回错误,必须加入回调函数pygame.sprite.spritecollideany(self, my_group, collided),
    collided(sprite, other)函数把spritecollideany的前两项做自己的参数,返回弹出精灵的新的组。

    相关文章

      网友评论

          本文标题:pygame 练手项目

          本文链接:https://www.haomeiwen.com/subject/lqzqddtx.html