Completing the Sleep Feature in Stardew Valley-Style Pygame
Purpose
When the player approaches the bed and presses Enter, the screen fades to black (then brightens). After sleeping, apples on trees regenerate (future updates: crop growth, time progression).
Code Implementation
1. Bed Interaction Detection
The TMX map’s player layer includes a bed region. Create a collision sprite (via Interaction class, inheriting Generic) to detect proximity. The sprite’s image is a placeholder (not rendered, so any size).
2. Sprite Setup (level.py)
In level.py, instantiate the bed sprite and add it to interaction_sprites (for interactive areas like beds/traders):
class Level:
def setup(self):
tmx_data = load_pygame('../data/map.tmx')
# ... other layer setup (house, fence, water) ...
# Bed sprite (from TMX 'Player' layer)
for obj in tmx_data.get_layer_by_name('Player'):
if obj.name == 'Bed':
Interaction(
pos=(obj.x, obj.y),
size=(obj.width, obj.height),
groups=self.interaction_sprites,
name='Bed'
)
3. Player Collision (player.py)
Pass interaction_sprites to the Player class. Add a is_sleeping flag too track sleep state. In input(), check for Enter key + collision:
class Player(pygame.sprite.Sprite):
def __init__(self, pos, groups, obstacle_sprites, tree_sprites, interaction_sprites):
super().__init__(groups)
# ... other init ...
self.interaction_sprites = interaction_sprites
self.is_sleeping = False # Sleep state
def input(self):
keys = pygame.key.get_pressed()
if not self.timers['tool_use'].active and not self.is_sleeping:
# ... movement keys (up/down/left/right) ...
if keys[pygame.K_RETURN]: # Enter to sleep
collided = pygame.sprite.spritecollide(self, self.interaction_sprites, False)
if collided:
sprite = collided[0]
if sprite.name == 'Trader':
pass # Future trading
else:
self.status = 'left_idle' # Face bed
self.is_sleeping = True
4. Fade Animation (transition.py)
A new Transition class (in transition.py) handles the fade. It fades to black (RGB 0) then white (255). During the fade, call regenerate_apple (reset) when black, then set is_sleeping to False when bright:
import pygame
from settings import SCREEN_WIDTH, SCREEN_HEIGHT
class Transition:
def __init__(self, reset_callback, player):
self.screen = pygame.display.get_surface()
self.reset = reset_callback
self.player = player
self.color_value = 255 # Start with white (RGB 255,255,255)
self.fade_speed = -2 # Fade to black first
self.fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
def play(self):
self.color_value += self.fade_speed
# Fade to black → reverse to fade to white
if self.color_value <= 0:
self.fade_speed *= -1
self.color_value = 0
self.reset() # Regenerate apples/tasks
# Fade to white → reset sleep state
if self.color_value > 255:
self.color_value = 255
self.player.is_sleeping = False
self.fade_speed = -2 # Reset speed
# Render fade effect
self.fade_surface.fill((self.color_value, self.color_value, self.color_value))
self.screen.blit(self.fade_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
5. Reset Logic (level.py)
After the screen fades to black, call regenerate_apple() to re-grow apples on trees:
class Level:
def regenerate_apple(self):
for tree in self.tree_sprites.sprites():
for apple in tree.apple_sprites.sprites():
apple.kill()
tree.regenerate_fruit() # Tree method to create apples
def run(self, dt):
# ... draw/update game ...
if self.player.is_sleeping:
self.transition.play()
Complete Code Overview
- player.py: Handles input, collision with the bed, and
is_sleepingflag. - transition.py: Manages fade animation, resets apples, and updates
is_sleeping. - level.py: Sets up sprites, runs the game loop, and triggers the transition.
- sprites.py: Defines
Interaction(bed sprite),Tree(apple regeneration), etc.
Example Code Snippets
player.py (Input Handling)
def input(self):
keys = pygame.key.get_pressed()
if not self.timers['tool_use'].active and not self.is_sleeping:
# Movement logic (up/down/left/right)
if keys[pygame.K_RETURN]:
collided = pygame.sprite.spritecollide(self, self.interaction_sprites, False)
if collided:
sprite = collided[0]
if sprite.name == 'Trader':
pass # Future trading
else:
self.status = 'left_idle'
self.is_sleeping = True
transition.py (Fade Logic)
def play(self):
self.color_value += self.fade_speed
if self.color_value <= 0:
self.fade_speed *= -1
self.color_value = 0
self.reset() # Regenerate apples
if self.color_value > 255:
self.color_value = 255
self.player.is_sleeping = False
self.fade_speed = -2
self.fade_surface.fill((self.color_value, self.color_value, self.color_value))
self.screen.blit(self.fade_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
Final Result
When the player presses Enter near the bed, the screen fades to black (apples reset) then brightens. The is_sleeping flag is cleared, and the player "wakes up" to a new day.