一.目标
完成时间流动效果,随着时间的推移,游戏中的天色会逐渐变暗。如果天黑了玩家睡觉来到新的一天,天色会重新变亮
二.代码的书写
思路就是给游戏窗口添加上一个蒙版,用到的函数是我们在写玩家睡觉,屏幕逐渐变黑的效果的时候用到的,大体思路也是一样的,一开始蒙版的颜色为[255,255,255],也就是纯白色,以 pygame.BLEND_RGBA_MULT 的方式绘制到窗口上后会透明
随后蒙版的颜色慢慢变黑,绘制到游戏窗口上也不会再那么透明了,开始有了灰蒙蒙的效果
经过测试,直到蒙版的颜色为(38,101,189)的时候,感觉最像天完全黑透了的效果
所以我们每一帧都减小一点蒙版颜色的RGB值,直到颜色变为(38,101,189),此时天就完全暗了,然后玩家睡觉之后,再把颜色重新设回[255,255,255],此时天就亮了
我们首先要写一个sky类,在里面创建蒙版图片和实现变换蒙版颜色的函数,这个类我们在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()
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)