栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

pygame模拟下雪场景

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

pygame模拟下雪场景

想象一下冬夜,鹅毛大雪纷纷扬扬飘下,覆盖在地上,树顶上……,我一直想用代码模拟一下这个场景,今天总算完成了一个,虽然效果不怎么样,但是基本思路是有了。这个场景需要三种对象,一种是会被雪覆盖的对象,例如树木、房屋、道路等,一种是雪,我这个程序里简单用一种精灵模拟,更好的做法应该是用粒子系统,还有一种是积雪。雪与被雪覆盖的对象或其上面覆盖的积雪发生碰撞,在碰撞发生处生成一个积雪。每过一段时间,最上面的积雪发生溶化。按上面的思路,被雪覆盖的对象只用了一棵树(还是下雪的时候不可能存在的树),编写的程序运行截图如下:

可以看到树顶和路上有了一点点积雪。

代码如下:

import os
import random
import pygame

screen_width = 500
screen_height = 600

pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
imgs_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),'imgs')
tree_img = pygame.image.load(os.path.join(imgs_path, 'tree.png')).convert()
snow_image = pygame.image.load(os.path.join(imgs_path, 'snow.png')).convert()
snow_image.set_colorkey((0, 0, 0))
snow_cover_image = pygame.image.load(os.path.join(imgs_path, 'snow_cover.png')).convert()
tree_img = pygame.transform.scale(tree_img, (200,300))
tree_img.set_colorkey((0,0,0))
running = True
last_loop_time = 0
#最后一次融化积雪的时间
last_cover_time = 0
# 预备融化的积雪
cover = [0 for _ in range(screen_width)]

'''树'''
class Tree(pygame.sprite.Sprite):
    def __init__(self, image, screen, left, bottom):
        pygame.sprite.Sprite.__init__(self)
        self.screen = screen
        self.image = image
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect()
        self.rect.left = left
        self.rect.bottom = bottom

    '''绘制自身'''

    def draw(self):
        self.screen.blit(self.image, self.rect)

'''雪花'''
class Snow(pygame.sprite.Sprite):
    def __init__(self, image, screen):
        pygame.sprite.Sprite.__init__(self)
        self.screen = screen
        self.last_rotate_time = 0
        # 将雪花缩放成随机生成的大小
        self.image = pygame.transform.scale(image,
                                            (random.randrange(2,5),
                                             random.randrange(2,5)))
        self.mask = pygame.mask.from_surface(self.image)
        self.image_origin = self.image
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(0, screen_width)
        self.rect.y = random.randrange(-1000, -10)
        self.speedx = random.randrange(-3, 3)
        self.speedy = random.randrange(1, 3)
        self.rotate_angle = 0
        self.rotate_speed = random.randrange(-5, 5)

    '''绘制自身'''

    def draw(self):
        self.screen.blit(self.image, self.rect)

    '''
        由于岩石图片不是一个真圆,每次旋转后图片的中心会发生偏移,
        经过多次旋转后图片会偏移到非预期位置。为防止这种情况发生,每
        次旋转后需要将图片的中心设置为原始图片的中心,每次旋转都从原
        始状态开始
    '''

    def rotate(self):
        now = pygame.time.get_ticks()
        if now - self.last_rotate_time > 30:
            self.rotate_angle = (self.rotate_angle + self.rotate_speed) % 360
            old_center = self.rect.center
            # 每次旋转都从原始状态开始
            self.image = pygame.transform.rotate(self.image_origin, self.rotate_angle)
            self.rect = self.image.get_rect()
            # 将旋转后的图片的中心调整为原始图片的中心
            self.rect.center = old_center
            self.last_time = now

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy
        self.rotate()
        cover_floor = screen_height - snow_cover_image.get_rect().height
        # 精灵矩形区域被移出屏幕外后重置其位置
        if self.rect.left > screen_width or 
                self.rect.right < 0:
            self.rect.x = random.randrange(0, screen_width)
            self.rect.y = random.randrange(-100, -40)
        elif self.rect.left < screen_width and 
                self.rect.right >= 0 and self.rect.top > cover_floor :
            snow_cover = Snow_cover(snow_cover_image, screen, self.rect.x, cover_floor)
            snow_covers.add(snow_cover)
            cover[self.rect.x] = snow_cover
            self.rect.x = random.randrange(0, screen_width)
            self.rect.y = random.randrange(-100, -40)
'''积雪'''
class Snow_cover(pygame.sprite.Sprite):
    def __init__(self, image, screen, left, top):
        pygame.sprite.Sprite.__init__(self)
        self.screen = screen
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.left = left
        self.rect.top = top

    '''绘制自身'''

    def draw(self):
        self.screen.blit(self.image,self.rect)
#场景上放一棵树
tree = Tree(tree_img, screen, 130, screen_height)
#场景中的积雪
snow_covers = pygame.sprite.Group()
#场景中的雪花
snows = pygame.sprite.Group()

def update():
    global  last_cover_time
    now = pygame.time.get_ticks()
    # 每100000毫秒化一次雪
    if (now - last_cover_time) > 100000:
        last_cover_time = now
        for i in range(screen_width):
            if cover[i]!=0:
                cover[i].kill()
                cover[i] = 0
    #更新背景
    screen.fill((0,0,0),(0,0,screen_width,screen_height))
    #绘制树
    tree.draw()
    #绘制雪花和积雪
    for snow in snows:
        snow.update()
        snow.draw()
    for snow_cover in snow_covers:
        snow_cover.draw()
    pygame.display.update()

def check_collide():
    # 雪撞上积雪
    hits = pygame.sprite.groupcollide(snows, snow_covers, False, False)
    # 在屏幕范围内,生成一个新积雪,更新预备融化的积雪数组
    for hit in hits:
        if hit.rect.left >=0 and hit.rect.left< screen_width:
            snow_cover = Snow_cover(snow_cover_image, screen, hit.rect.left, hit.rect.bottom - 2)
            snow_covers.add(snow_cover)
            cover[hit.rect.left] = snow_cover
        hit.rect.x = random.randrange(0, screen_width)
        hit.rect.y = random.randrange(-100, -40)

    # 雪撞上树,生成一个新积雪,更新预备融化的积雪数组
    hits = pygame.sprite.spritecollide(tree, snows, True, pygame.sprite.collide_mask)
    for hit in hits:
        snow_cover = Snow_cover(snow_cover_image, screen, hit.rect.left, hit.rect.bottom - 1)
        snow_covers.add(snow_cover)
        cover[hit.rect.left] = snow_cover
        hit.rect.x = random.randrange(0, screen_width)
        hit.rect.y = random.randrange(-100, -40)

for i in range(300):
    snow = Snow(snow_image, screen)
    snows.add(snow)

while running:
    now = pygame.time.get_ticks()
    if now - last_loop_time >= 1000 / 60:
        last_loop_time = now
        for event in pygame.event.get():
            key_pressed = pygame.key.get_pressed()
            # 按下窗体上的关闭按钮或者ESC键则停止主事件循环
            if event.type == pygame.QUIT or key_pressed[pygame.K_ESCAPE]:
                running = False

        if running:
            check_collide()
            update()

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/272531.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号