【pygame实现星露谷物语风格游戏】18.种植作物

一.目的

实现种植植物的功能,并且如果当天浇水了,植物会在第二天长大,直到成熟为止

二.代码的书写

和浇水类似,首先就是玩家如果使用了种植,就检测所有被开垦过的土壤是否与玩家工作的位置坐标重合,如果发现有一块土地坐标重合,说明正在这个地方种植,就创建一个植物精灵,显示覆盖到这个地方

这里Plant报错是因为我们还没实现这个类,我们一会就实现。我们希望植物会被绘制出来,因此我们把它加入到all_sprite精灵组,我们还希望植物能够有碰撞箱,因此把它加入到collision_sprite精灵组。这时候,我们发现我们的soil.py里并没有collision_sprites这个变量,所以我们还得把它当作参数传递进来

并且接收这个参数

此外,我们还需要创建一个植物精灵组来管理里面的植物

现在让我们去player里面,当使用种子的时候调用这个函数。

接下来我们书写Plant类

其中,参数中的soil是种植这株植物的土壤,我们可以从soil.rect里获取坐标,这样就不用单独把坐标当作参数传递进来了,而check_watered是检擦这株植物所在的土地是否浇水了的函数,这个函数我们一会在实现

接下来,为了实现植物生长的效果,我们还需要设置如下几个变量,这些变量的含义都在注释中了

接下来是设置植物的图片和坐标,图层

由于植物需要浇水才会生长,所以我们先完成上面提到的检擦该土地是否浇水的函数,代码很简单,只是需要两个坐标系的简单坐标变换即可

这个函数是写在Soil_layer类里面的,我们在创建Plant对象的时候把这个函数当作参数传递进来了,不过我们忘记了接收这个参数,让我们来接收一下

接下来就书写植物的grow函数

grow函数的作用是实现植物的一次生长,比如植物的age是1,grow之后age就变成了2,并且还会改变对应年龄的贴图。

此外我们还希望完成如下的效果:当植物的age为0的时候,也就是他还是种子状态的时候,我们希望他没有碰撞箱,当他稍微成长一些,才有碰撞箱。这个功能很容易实现,只要它的age大于0的时候再给他设置hitbox即可。

接下来我们还需要判断,如果它的age超过了限制,我们就把他的age设为最大状态,并且把它标记为可以收获的

接下来,我们的思路就是,每天起床的时候,就会调用所有植物的grow函数,我们先来完成调用所有植物的grow函数这一操作,把它写道update_plant函数里

接下来,我们去level.py中,在每天起床的时候调用这个函数即可

值得注意的是,要在新的一天清除水渍和下雨water_all之前调用这个函数,因为我们需要检测的是昨天是否浇水,如果先清楚了水渍,那么所有的土壤都没有水了,即使昨天浇水了所有的植物都不会生长。同样的,如果写到water_all下面,那么如果今天下雨,即使昨天没浇水也会生长

三.完整代码

soil.py:

import pygame

from settings import *

from pytmx.util_pygame import load_pygame

from support import *

from random import choice


#开垦过的土地

class SoilTile(pygame.sprite.Sprite):

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

       super().__init__(groups)

       self.image = surf

       self.rect = self.image.get_rect(topleft = pos)

       self.z = LAYERS['soil']


#浇过水的土地

class WaterTile(pygame.sprite.Sprite):

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

       super().__init__(groups)

       self.image = surf

       self.rect = self.image.get_rect(topleft = pos)

       self.z = LAYERS['soil water']


#植物

class Plant(pygame.sprite.Sprite):

    def __init__(self, plant_type, groups, soil, check_watered):

        super().__init__(groups)


        #种子的类型

        self.plant_type = plant_type

        #载入植物图片,里面存放的是植物不同年龄下的图片

        self.frames = import_folder(f'../graphics/fruit/{plant_type}')

        #种植该植物的那块土壤

        self.soil = soil

        #检查该土地是否浇水的函数

        self.check_watered = check_watered


        #植物的年龄,一开始是0,表示种子状态

        self.age = 0

        #植物的最大年龄

        #植物的最大年龄取决于我们准备了多少张不同年龄植物的图片,由于我们的年龄是从0开始计数的,所以还得减一

        self.max_age = len(self.frames) - 1

        #植物的生长速度

        self.grow_speed = GROW_SPEED[plant_type]

        #植物是否可以被收获了

        self.harvestable = False


        #设置植物的图片

        self.image = self.frames[self.age]

        #植物的坐标相对于土地的偏移量

        self.y_offset = -16 if plant_type == 'corn' else -8

        #植物的坐标

        self.rect = self.image.get_rect(midbottom=soil.rect.midbottom + pygame.math.Vector2(0, self.y_offset))

        #植物的图层

        self.z = LAYERS['ground plant']


    def grow(self):

        if self.check_watered(self.rect.center):

            self.age += self.grow_speed

            if int(self.age) > 0:

                self.z = LAYERS['main']

                self.hitbox = self.rect.copy().inflate(-26, -self.rect.height * 0.4)

            if self.age >= self.max_age:

                self.age = self.max_age

                self.harvestable = True

            self.image = self.frames[int(self.age)]

            self.rect = self.image.get_rect(midbottom=self.soil.rect.midbottom + pygame.math.Vector2(0, self.y_offset))


#管理所有土地的类

class SoilLayer:

    def __init__(self,all_sprites,collision_sprites):

        #all_sprites精灵组

        self.all_sprites = all_sprites

        #碰撞精灵组

        self.collision_sprites = collision_sprites

        #创建开垦过的土地精灵组

        self.soil_sprites = pygame.sprite.Group()

        #浇过水的土地精灵组

        self.water_sprites = pygame.sprite.Group()

        #植物精灵组

        self.plant_sprites = pygame.sprite.Group()


        #导入开垦过的土地的图片

        self.soil_surf = pygame.image.load('../graphics/soil/o.png')

        #获取浇水图片,一共有三张

        self.water_surfs = import_folder('../graphics/soil_water')


        self.create_soil_grid()

        self.create_hit_rects()


    def create_soil_grid(self):

        #导入地图的图片

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

        #地图的宽度,高度除以64,就是一共有多少块(64*64)的土地

        h_tiles, v_tiles = ground.get_width() // TILE_SIZE, ground.get_height() // TILE_SIZE

        #创建一个三维列表,最一开始,所有土地的属性都是空的

        self.grid = [[[] for col in range(h_tiles)] for row in range(v_tiles)]

        #如果是可以被耕种的土地块,就给他的列表添加一个标记'F'

        for x, y, _ in load_pygame('../data/map.tmx').get_layer_by_name('Farmable').tiles():

            self.grid[y][x].append('F')


    def create_hit_rects(self):

        #列表里存放的是所有能被耕种的土地,数据类型是pygame里提供的Rect数据类型,包含了坐标和宽高

        self.hit_rects = []

        for index_row, row in enumerate(self.grid):

            for index_col, cell in enumerate(row):

                #如果是能被耕种的

                if 'F' in cell:

                    x = index_col * TILE_SIZE

                    y = index_row * TILE_SIZE

                    rect = pygame.Rect(x, y, TILE_SIZE, TILE_SIZE)

                    self.hit_rects.append(rect)


    def get_hit(self, point):

        #point是传入的参数,代表的是玩家挥舞的锄头的落点的坐标

        for rect in self.hit_rects:

            #如果该可耕种的土地块与玩家的锄头坐标发生了重叠,说明玩家锄的就是这块地,就给他的属性再加上一个标记'X'

            if rect.collidepoint(point):

                #相反,这里得把pygame的坐标系转换成tmx文件中的坐标系

                x = rect.x // TILE_SIZE

                y = rect.y // TILE_SIZE


                if 'F' in self.grid[y][x]:

                    self.grid[y][x].append('X')

                    SoilTile(

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

                        surf=self.soil_surf,

                        groups=[self.all_sprites, self.soil_sprites])

                    if self.raining:

                        self.water(point)

                    #self.create_soil_tiles()


    def water(self, target_pos):

        for soil_sprite in self.soil_sprites.sprites():

            if soil_sprite.rect.collidepoint(target_pos):

                x = soil_sprite.rect.x // TILE_SIZE

                y = soil_sprite.rect.y // TILE_SIZE

                #给grid添加”W“标记

                self.grid[y][x].append('W')


                pos = soil_sprite.rect.topleft

                #随机选择三张之中的一张图片,来作为这个精灵的image

                surf = choice(self.water_surfs)

                WaterTile(pos, surf, [self.all_sprites, self.water_sprites])


    def remove_water(self):

        #删除所有的精灵

        for sprite in self.water_sprites.sprites():

            sprite.kill()

        #同时别忘了清理grid中的标记

        for row in self.grid:

            for cell in row:

                if 'W' in cell:

                    cell.remove('W')


    #给所有被开垦过的农田浇水

    def water_all(self):

        for index_row, row in enumerate(self.grid):

            for index_col, cell in enumerate(row):

                if 'X' in cell and 'W' not in cell:

                    cell.append('W')

                    x = index_col * TILE_SIZE

                    y = index_row * TILE_SIZE

                    WaterTile((x, y), choice(self.water_surfs), [self.all_sprites, self.water_sprites])


    #检擦某块土地是否浇水

    def check_watered(self, pos):

        x = pos[0] // TILE_SIZE

        y = pos[1] // TILE_SIZE

        cell = self.grid[y][x]

        is_watered = 'W' in cell

        return is_watered


    #种植植物

    def plant_seed(self, target_pos, seed):

        for soil_sprite in self.soil_sprites.sprites():

            if soil_sprite.rect.collidepoint(target_pos):


                x = soil_sprite.rect.x // TILE_SIZE

                y = soil_sprite.rect.y // TILE_SIZE


                if 'P' not in self.grid[y][x]:

                    self.grid[y][x].append('P')

                    Plant(seed, [self.all_sprites, self.plant_sprites, self.collision_sprites], soil_sprite,

                          self.check_watered)


    #更新植物的状态

    def update_plants(self):

        for plant in self.plant_sprites.sprites():

            plant.grow()


    """

    def create_soil_tiles(self):

        self.soil_sprites.empty()

        for index_row, row in enumerate(self.grid):

            for index_col, cell in enumerate(row):

                if 'X' in cell:

                    SoilTile(

                        pos=(index_col * TILE_SIZE, index_row * TILE_SIZE),

                        surf=self.soil_surf,

                        groups=[self.all_sprites, self.soil_sprites])"""

 

player.py

import pygame

from settings import *

from support import *

from timer import Timer


class Player(pygame.sprite.Sprite):

    def __init__(self,pos,group,collision_sprites,tree_sprites,interaction,soil_layer):

        #这个参数可以传一个精灵组,这样就会自动把该精灵加入到该精灵组中

        #也可以为空,这样需要在外面手动调用精灵组的add函数来将这个精灵加入到精灵组中

        super().__init__(group)


        self.import_assets()

        self.status = 'down_idle'

        self.frame_index = 0


        #这里的变量名一定要叫image,因为这是它父类Sprite规定的

        self.image = self.animations[self.status][self.frame_index]



        #这个get_rect()也是父类中设置的方法

        #返回值是有很多,大概有x,y,centerx,centery,center,width,height这几类

        #大概就是image的x坐标,y坐标,中心的x坐标,中心的y坐标,中心点的坐标,宽度,高度等

        #参数可以不填,那么位置就默认是(0,0),也可以填一个列表,比如(100,100),那么初始的位置就是(100,100)

        #也可以是center = 一个坐标,这表示设置该图像的中心在这个坐标上

        #同样的这里的变量名也一定要叫rect,这是父类规定的

        self.rect = self.image.get_rect(center = pos)


        #z轴

        self.z = LAYERS['main']


        #创建一个二维的向量,参数不填默认是(0,0)

        self.direction = pygame.math.Vector2()#速度的方向

        self.pos = pygame.math.Vector2(self.rect.center)#位置

        self.speed = 200#速度


        #碰撞箱

        self.hitbox = self.rect.copy().inflate((-126,-70))

        self.collision_sprites = collision_sprites


        self.timers = {

            'tool use':Timer(350,self.use_tool),

            'tool switch': Timer(200),

            'seed use': Timer(350, self.use_seed),

            'seed switch': Timer(200),

        }


        self.tools = ['hoe', 'axe', 'water']

        self.tool_index = 0

        self.selected_tool = self.tools[self.tool_index]


        self.seeds = ['corn', 'tomato']

        self.seed_index = 0

        self.selected_seed = self.seeds[self.seed_index]


        #玩家的背包

        self.item_inventory = {

            'wood': 0,

            'apple': 0,

            'corn': 0,

            'tomato': 0

        }


        #接收树木精灵组

        self.tree_sprites = tree_sprites

        #接收特殊区域精灵组

        self.interaction = interaction

        #是否在睡觉

        self.sleep = False


        #泥土管理

        self.soil_layer = soil_layer



    def use_tool(self):

        if self.selected_tool == 'hoe':

            self.soil_layer.get_hit(self.target_pos)


        if self.selected_tool == 'axe':

            for tree in self.tree_sprites.sprites():

                if tree.rect.collidepoint(self.target_pos):

                    tree.damage()


        if self.selected_tool == 'water':

            self.soil_layer.water(self.target_pos)


    def get_target_pos(self):

        # 获取工具的作用区域坐标

        self.target_pos = self.rect.center + PLAYER_TOOL_OFFSET[self.status.split('_')[0]]


    def use_seed(self):

        self.soil_layer.plant_seed(self.target_pos, self.selected_seed)

    def import_assets(self):

        self.animations = {'up': [], 'down': [], 'left': [], 'right': [],

                           'right_idle': [], 'left_idle': [], 'up_idle': [], 'down_idle': [],

                           'right_hoe': [], 'left_hoe': [], 'up_hoe': [], 'down_hoe': [],

                           'right_axe': [], 'left_axe': [], 'up_axe': [], 'down_axe': [],

                           'right_water': [], 'left_water': [], 'up_water': [], 'down_water': []}


        for animation in self.animations.keys():

            full_path = '../graphics/character/' + animation

            self.animations[animation] = import_folder(full_path)


    def animate(self, dt):


        # 4 是比较合适的数字

        # 数字 决定做动作的快慢

        # 做一个动作需要 1/4秒

        # fream_index += dt 的话,要经过1s,才能变成下一个整数,做下一个动作

        # fream_index += 4*dt,那么增加的速度就快了四倍,经过1/4秒就能做下一个动作了

        self.frame_index += 4 * dt

        # print(self.frame_index)

        if self.frame_index >= len(self.animations[self.status]):

            self.frame_index = 0


        self.image = self.animations[self.status][int(self.frame_index)]


    def input(self):

        keys = pygame.key.get_pressed()

        #已经在使用工具的时候,或者正在睡觉的时候,停止对按键的检测

        if not self.timers['tool use'].active and not self.sleep:

            if keys[pygame.K_UP]:

                self.direction.y = -1

                self.status = 'up'

            elif keys[pygame.K_DOWN]:

                self.direction.y = 1

                self.status = 'down'

            else:

                self.direction.y = 0#不要忘记加上这一句,不然按下键盘后再松开也不会停


            if keys[pygame.K_RIGHT]:

                self.direction.x = 1

                self.status = 'right'

            elif keys[pygame.K_LEFT]:

                self.direction.x = -1

                self.status = 'left'

            else:

                self.direction.x = 0


            if keys[pygame.K_SPACE]:

                #启动计时器

                self.timers['tool use'].activate()

                #实用工具的时候是不能移动的

                self.direction = pygame.math.Vector2()

                #要从第一张图片开始绘制

                self.frame_index = 0


            #按下左边的shift键更换工具

            if keys[pygame.K_LSHIFT] and not self.timers['tool switch'].active:

                self.timers['tool switch'].activate()

                self.tool_index += 1

                self.tool_index = self.tool_index if self.tool_index < len(self.tools) else 0

                self.selected_tool = self.tools[self.tool_index]


            #按下右边的ctrl键,使用种子

            if keys[pygame.K_RCTRL]:

                self.timers['seed use'].activate()

                self.direction = pygame.math.Vector2()

                self.frame_index = 0


            #按下右边的shift键,切换种子

            if keys[pygame.K_RSHIFT] and not self.timers['seed switch'].active:

                self.timers['seed switch'].activate()

                self.seed_index += 1

                self.seed_index = self.seed_index if self.seed_index < len(self.seeds) else 0

                self.selected_seed = self.seeds[self.seed_index]


            #按下回车键,进行睡觉

            if keys[pygame.K_RETURN]:

                #返回值是与第一个参数的精灵发生碰撞的精灵

                collided_interaction_sprite = pygame.sprite.spritecollide(self, self.interaction, False)

                #参数False表示,如果发生了重叠,不会kill掉第二个参数的精灵,如果是True,就Kill掉第二个参数的精灵

                if collided_interaction_sprite:

                    #交易的部分以后再说

                    if collided_interaction_sprite[0].name == 'Trader':

                        pass

                    else:

                        #为了视觉效果设置成面朝床边

                        self.status = 'left_idle'

                        self.sleep = True


    def get_status(self):


        # idle

        if self.direction.magnitude() == 0:

            # self.status += '_idle'

            # 上面这种方法不可取因为每一帧都会在字符串后面加上一个_idel

            # 所以status会变成 xxx_idle_idle_idle

            # 实际上当出现两个_idle的时候就已经报错了

            # 下面这种方法

            # split('_')是把一个字符串 以 '_' 为分节符分开

            # 他返回的是一个列表

            # 比如 a_b_c_d

            # 返回的就是[a,b,c,d]

            # 所以下面的【0】获取的就是_之前的内容

            self.status = self.status.split('_')[0] + '_idle'


        if self.timers['tool use'].active:

            self.status = self.status.split('_')[0] + '_' + self.selected_tool


    def update_timers(self):

        for timer in self.timers.values():

            timer.update()



    def collision(self,direction):

        # 遍历碰撞箱精灵组的所有精灵

        for sprite in self.collision_sprites.sprites():

            # 如果该精灵有一个叫hitbox的属性

            #实际上collision_sprites精灵组内的所有精灵都应该有hitbox这个属性,这句话属实多余

            if hasattr(sprite,'hitbox'):

                #如果该精灵的hitbox与玩家的hitbox有重叠

                if sprite.hitbox.colliderect(self.hitbox):

                    #如果此时正在水平方向移动

                    if direction == 'horizontal':

                        if self.direction.x > 0:  #玩家正在向右移动

                            self.hitbox.right = sprite.hitbox.left

                        if self.direction.x < 0:  # 玩家正在向左移动

                            self.hitbox.left = sprite.hitbox.right

                        self.rect.centerx = self.hitbox.centerx

                        self.pos.x = self.hitbox.centerx

                    #如果此时正在竖直方向移动

                    if direction == 'vertical':

                        if self.direction.y > 0:  # 玩家正在向下移动

                            self.hitbox.bottom = sprite.hitbox.top

                        if self.direction.y < 0:  # 玩家正在向上移动

                            self.hitbox.top = sprite.hitbox.bottom

                        self.rect.centery = self.hitbox.centery

                        self.pos.y = self.hitbox.centery



    def move(self,dt):

        #向量归一化,比如一个n维向量为(x1,x2,x3...,xn)

        #那么向量归一化的操作就是等比例缩放x1到xn的大小让 根号下(x1的平方+x2的平方+...+xn的平方) 等于1

        #归一化的目的是如果同时按右键和上,那么direction就会变成(1,1),他的速度向量就是一个大小为根2,方向右上的向量了

        #magnitude()返回的是一个float类型的数据,他的大小为根号下(x1的平方+x2的平方+...+xn的平方)

        if self.direction.magnitude() > 0:#这表示如果有按键按下,如果向量里面全是0,会使归一化中的数学计算出现错误

            self.direction = self.direction.normalize()


        #位移 = 方向 * 速度 * 变化的时间()

        #水平方向

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

        self.hitbox.centerx = round(self.pos.x)

        self.rect.centerx = self.hitbox.centerx

        self.collision('horizontal')


        #竖直方向

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

        self.hitbox.centery = round(self.pos.y)

        self.rect.centery = self.hitbox.centery

        self.collision('vertical')


    def update(self,dt):

        self.input()

        self.get_status()

        self.update_timers()

        self.get_target_pos()


        self.move(dt)

        self.animate(dt)

 

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


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


    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.overlay.display()


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

        if self.player.sleep:

            self.transition.play()


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

        if self.raining:

            self.rain.update()


    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()



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)

 

  • 30
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

owooooow

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

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

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

打赏作者

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

抵扣说明:

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

余额充值