【pygame实现星露谷物语风格游戏】20.时间流动效果

本文介绍了如何使用pygame库在游戏开发中实现时间流动,通过创建Sky类管理天色变化,通过蒙版技术模拟从白天到黑夜再到白天的过程。作者详细描述了代码的编写步骤,包括创建蒙版图片、调整颜色以及在level.py中的应用。
摘要由CSDN通过智能技术生成

一.目标

完成时间流动效果,随着时间的推移,游戏中的天色会逐渐变暗。如果天黑了玩家睡觉来到新的一天,天色会重新变亮

二.代码的书写

思路就是给游戏窗口添加上一个蒙版,用到的函数是我们在写玩家睡觉,屏幕逐渐变黑的效果的时候用到的,大体思路也是一样的,一开始蒙版的颜色为[255,255,255],也就是纯白色,以 pygame.BLEND_RGBA_MULT 的方式绘制到窗口上后会透明

随后蒙版的颜色慢慢变黑,绘制到游戏窗口上也不会再那么透明了,开始有了灰蒙蒙的效果

经过测试,直到蒙版的颜色为(38,101,189)的时候,感觉最像天完全黑透了的效果

所以我们每一帧都减小一点蒙版颜色的RGB值,直到颜色变为(38,101,189),此时天就完全暗了,然后玩家睡觉之后,再把颜色重新设回[255,255,255],此时天就亮了

我们首先要写一个sky类,在里面创建蒙版图片和实现变换蒙版颜色的函数,这个类我们在sky.py里实现

接下来只需要来到level.py中,把Sky类导入进来

并且实例化对象

接着在run函数中,调用sky的display函数

最后,每当玩家起床的时候,把天色重新设亮即可

三.完整代码

sky.py:

import pygame

from settings import *

from sprites import Generic

from random import *

from support import import_folder



#天空类,管理天色的

class Sky:

    def __init__(self):

        self.display_surface = pygame.display.get_surface()

        #创建一个与游戏窗口相同大小的图片,来当作蒙版

        self.full_surf = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))

        #开始的颜色,也就是天亮的颜色

        self.start_color = [255, 255, 255]

        #最终的颜色,也即是深夜的颜色

        self.end_color = (38, 101, 189)


    def display(self, dt):

        for index, value in enumerate(self.end_color):

            if self.start_color[index] > value:

                #R,G,B值分别每秒 减小 2

                self.start_color[index] -= 2 * dt

        #给图片填充颜色

        self.full_surf.fill(self.start_color)

        #以蒙版的形式绘制到窗口上

        self.display_surface.blit(self.full_surf, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)

#雨滴精灵

class Drop(Generic):

    def __init__(self, surf, pos, moving, groups, z):

        #参数中moving表示是否是移动的雨滴,雨滴分为两种,已经落到地上的我们就不让他移动,在空中的我们给他一个向着左下的速度

        super().__init__(pos, surf, groups, z)

        #雨滴这个精灵的存活时间

        self.lifetime = randint(400, 500)

        #计时器的开始时间

        self.start_time = pygame.time.get_ticks()


        #如果moving为true,表示这个雨滴是需要移动的

        self.moving = moving

        #精灵移动所需要的三个参数

        if self.moving:

            self.pos = pygame.math.Vector2(self.rect.topleft)

            self.direction = pygame.math.Vector2(-2, 4)

            self.speed = randint(200, 250)


    def update(self, dt):

        #让雨滴动起来

        if self.moving:

            self.pos += self.direction * self.speed * dt

            self.rect.topleft = (round(self.pos.x), round(self.pos.y))

        #过了存活时间,把这个精灵kill掉

        if pygame.time.get_ticks() - self.start_time >= self.lifetime:

            self.kill()


#掌管下雨的类

class Rain:

    def __init__(self,all_sprites):

        self.all_sprites = all_sprites

        #导入雨滴正在落下的图片,一共三张,以列表的形式返回

        self.rain_drops = import_folder('../graphics/rain/drops/')

        # 导入雨滴落到地板的图片,一共三张,以列表的形式返回

        self.rain_floor = import_folder('../graphics/rain/floor/')

        #整张地图的宽度和高度,我们需要这两个数据取随机数,在随机的位置生成雨滴

        self.floor_w, self.floor_h = pygame.image.load('../graphics/world/ground.png').get_size()


    #生成落到地板上的雨滴

    def create_floor(self):

        Drop(

            surf=choice(self.rain_floor),

            pos=(randint(0, self.floor_w), randint(0, self.floor_h)),

            moving=False,

            groups=self.all_sprites,

            z=LAYERS['rain floor'])


    #生成在空中的雨滴

    def create_drops(self):

        Drop(

            surf=choice(self.rain_drops),

            pos=(randint(0, self.floor_w), randint(0, self.floor_h)),

            moving=True,

            groups=self.all_sprites,

            z=LAYERS['rain drops'])


    def update(self):

        self.create_floor()

        self.create_drops()

 

level.py:

import pygame

from settings import *

from player import Player

from overlay import Overlay

from sprites import *

from pytmx.util_pygame import load_pygame

from support import *

from transition import Transition

from soil import SoilLayer

from sky import Rain,Sky


class Level():

    def __init__(self):

        #得到屏幕的画面,得到的这个画面与main.py中的screen相同

        self.display_surface = pygame.display.get_surface()


        #创建精灵组

        self.all_sprites = CameraGroup()

        #具有碰撞箱的精灵组

        self.collision_sprites = pygame.sprite.Group()

        #树木精灵组

        self.tree_sprites = pygame.sprite.Group()

        #特殊区域精灵组

        self.interaction_sprites = pygame.sprite.Group()


        #调用setup方法

        self.setup()

        #创建工具和种子显示图层

        self.overlay = Overlay(self.player)

        #创建transition对象

        self.transition = Transition(self.reset,self.player)


        #实例化Rain对象

        self.rain = Rain(self.all_sprites)

        #一个bool值,表示是否正在下雨,有1/10的概率为true

        self.raining = randint(0,10) > 8

        self.soil_layer.raining = self.raining

        #实例化天空对象

        self.sky = Sky()


    def setup(self):


        #土地管理类

        self.soil_layer = SoilLayer(self.all_sprites,self.collision_sprites)


        #载入.tmx文件

        tmx_data = load_pygame('../data/map.tmx')


        #绘制房子与栅栏,他们都属于Generic类

        for layer in ['HouseFloor', 'HouseFurnitureBottom']:

            for x, y, surf in tmx_data.get_layer_by_name(layer).tiles():

                Generic((x * TILE_SIZE, y * TILE_SIZE), surf, self.all_sprites, LAYERS['house bottom'])


        for layer in ['HouseWalls', 'HouseFurnitureTop','Fence']:

            for x, y, surf in tmx_data.get_layer_by_name(layer).tiles():

                Generic((x * TILE_SIZE, y * TILE_SIZE), surf, [self.all_sprites, self.collision_sprites])




        #水流

        water_frames = import_folder('../graphics/water')

        for x, y, surf in tmx_data.get_layer_by_name('Water').tiles():

            Water((x * TILE_SIZE, y * TILE_SIZE), water_frames, self.all_sprites)


        #树木

        for obj in tmx_data.get_layer_by_name('Trees'):

            Tree(

                pos=(obj.x, obj.y),

                surf=obj.image,

                groups=[self.all_sprites, self.collision_sprites, self.tree_sprites],

                name=obj.name,

                player_add=self.player_add)

        #野花

        for obj in tmx_data.get_layer_by_name('Decoration'):

            WildFlower((obj.x, obj.y), obj.image,[self.all_sprites, self.collision_sprites])


        #空气墙

        for x, y, surf in tmx_data.get_layer_by_name('Collision').tiles():

            Generic((x * TILE_SIZE, y * TILE_SIZE), pygame.Surface((TILE_SIZE, TILE_SIZE)), self.collision_sprites)


        #玩家

        for obj in tmx_data.get_layer_by_name('Player'):

            if obj.name == 'Start':

                self.player = Player(

                    pos=(obj.x, obj.y),

                    group=self.all_sprites,

                    collision_sprites=self.collision_sprites,

                    tree_sprites=self.tree_sprites,

                    interaction = self.interaction_sprites,

                    soil_layer = self.soil_layer)


            if obj.name == 'Bed':

                Interaction((obj.x, obj.y), (obj.width, obj.height), self.interaction_sprites, obj.name)


        Generic(

            pos = (0,0),

            surf = pygame.image.load('../graphics/world/ground.png').convert_alpha(),

            groups = self.all_sprites,

            z = LAYERS['ground']

        )


    def run(self,dt):

        #窗口的背景设为黑色

        self.display_surface.fill('black')

        #调用精灵组的draw方法

        self.all_sprites.custom_draw(self.player)

        #调用精灵组的update方法

        self.all_sprites.update(dt)

        #收获植物

        self.plant_collision()


        self.overlay.display()


        #如果在睡觉,执行相应的函数

        if self.player.sleep:

            self.transition.play()


        #如果在下雨,就生成雨滴

        if self.raining:

            self.rain.update()


        #天色变暗

        self.sky.display(dt)


    def player_add(self, item):

        #item是一个str类型的数据,代表要对哪一种物品加一

        self.player.item_inventory[item] += 1


    def reset(self):

        #更新植物状态

        self.soil_layer.update_plants()


        # 清除农田里的水渍

        self.soil_layer.remove_water()


        #每天重新随机一下是否要下雨

        self.raining = randint(0, 10) > 8

        self.soil_layer.raining = self.raining

        #如果新的一天下雨了,就自动灌溉所有被开垦过的土地

        if self.raining:

            self.soil_layer.water_all()


        #苹果重新长在树上

        for tree in self.tree_sprites.sprites():

            for apple in tree.apple_sprites.sprites():

                apple.kill()

            tree.create_fruit()


        #天色重新变量

        self.sky.start_color = [255, 255, 255]


    def plant_collision(self):

        #如果plant_sprite这个精灵组不为空

        if self.soil_layer.plant_sprites:

            #遍历精灵组中的所有精灵

            for plant in self.soil_layer.plant_sprites.sprites():

                #如果作物成熟了并且与玩家发生了碰撞

                if plant.harvestable and plant.rect.colliderect(self.player.hitbox):

                    #背包增加相应的作物

                    self.player_add(plant.plant_type)

                    #消除植物

                    plant.kill()

                    self.soil_layer.grid[plant.rect.centery // TILE_SIZE][plant.rect.centerx // TILE_SIZE].remove('P')

                    #绘制粒子效果

                    Particle(plant.rect.topleft, plant.image, self.all_sprites, z=LAYERS['main'])

class CameraGroup(pygame.sprite.Group):

    def __init__(self):

        super().__init__()

        #获取窗口

        self.display_surface = pygame.display.get_surface()

        #这是一个偏移量,代表的是玩家的实际位置与屏幕中间的矢量

        self.offset = pygame.math.Vector2()

    def custom_draw(self,player):

        self.offset.x = player.rect.centerx - SCREEN_WIDTH / 2

        self.offset.y = player.rect.centery - SCREEN_HEIGHT / 2


        for layer in LAYERS.values():#按照z轴从小到达绘制

            for sprite in sorted(self.sprites(),key = lambda sprite: sprite.rect.centery):

                if sprite.z == layer:#如果该精灵的z值等于当前要绘制的z值,才绘制

                    offset_rect = sprite.rect.copy()

                    offset_rect.center -= self.offset

                    #if sprite == player:

                        #print("player.rect.center为:(" +

                             # str(player.rect.centerx)+"," + str(player.rect.centery)+")")

                        #print("offset_rect为:(" + str(offset_rect.x)

                             # +"," +str(offset_rect.y)+")")

                    self.display_surface.blit(sprite.image,offset_rect)

 

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

owooooow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值