In the following basic code, I have centipede segments form a longer centipede class. As the first segment follows the “head” and then the second segment follows the first segment, etc. they are to be spaced exactly one segment size distance behind each other. For the most part it works but depending what speed I have them at, the spacing sometimes does not stay consistent with segments overlapping or spacing further apart when the move down and reverse direction.
What would be the best way code the spacing to keep it consistent no matter what speed it may be going?
import pygame
import random
# Initialize Pygame
pygame.init()
# Screen dimensions
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 800
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()
# Colors
BLACK = (0, 0, 0)
CYAN = (0, 255, 255)
# Centipede settings
SEGMENT_SIZE = 20
class CentipedeSegment(pygame.sprite.Sprite):
def __init__(self, x, y, speed):
super().__init__()
self.image = pygame.Surface((SEGMENT_SIZE, SEGMENT_SIZE), pygame.SRCALPHA)
pygame.draw.circle(self.image, CYAN, (SEGMENT_SIZE // 2, SEGMENT_SIZE // 2), SEGMENT_SIZE // 2)
self.rect = self.image.get_rect(topleft=(x, y))
# self.image = centipedes_sprites[0]
self.rect = self.image.get_rect(topleft=(x, y))
self.speed = speed
self.x_direction = 1 # 1 for right, -1 for left
self.y_direction = SEGMENT_SIZE # 20 for down, -20 for up
self.move_down_next_frame = False # Flag to control down movement after edge collision
self.move_up_next_frame = False # Flag to control up movement after edge collision
self.current_frame = 0 # Set frame counter for images in list
def update(self, mushrooms, delta_time):
# self.image = centipedes_sprites[self.current_frame]
# self.current_frame = (self.current_frame + 1) % len(centipedes_sprites)
# if self.x_direction == -1:
# screen.blit(pygame.transform.flip(self.image, True, False),(self.rect.x,self.rect.y))
# else:
# screen.blit(self.image,(self.rect.x,self.rect.y))
screen.blit(self.image,(self.rect.x,self.rect.y))
if self.move_down_next_frame:
self.rect.y += self.y_direction
self.move_down_next_frame = False
if self.move_up_next_frame:
self.move_up_next_frame = False
# Calculate movement with delta time
self.rect.x += int(self.speed * self.x_direction * delta_time)
# Check for collisions with mushrooms
for mushroom in mushrooms:
if self.x_direction == 1 and self.rect.right >= mushroom.rect.left and self.rect.left < mushroom.rect.left and self.rect.colliderect(mushroom.rect):
self.x_direction = -1
self.move_down_next_frame = True
if self.rect.y >= SCREEN_HEIGHT - 40:
self.y_direction *= -1 # Reverse vertical direction
break
elif self.x_direction == -1 and self.rect.left <= mushroom.rect.right and self.rect.right > mushroom.rect.right and self.rect.colliderect(mushroom.rect):
self.x_direction = 1
self.move_down_next_frame = True
if self.rect.y >= SCREEN_HEIGHT - 40:
self.y_direction *= -1 # Reverse vertical direction
break
# Check for screen edges and toggle direction if reached
if self.rect.left <= 0 and self.x_direction == -1:
self.x_direction = 1
self.move_down_next_frame = True
if self.rect.y >= SCREEN_HEIGHT - 40:
self.y_direction *= -1 # Reverse vertical direction
elif self.rect.right >= SCREEN_WIDTH and self.x_direction == 1:
self.x_direction = -1
self.move_down_next_frame = True
if self.rect.y >= SCREEN_HEIGHT - 40:
self.y_direction *= -1 # Reverse vertical direction
# Reverse y_direction logic
if self.y_direction < 0: # Moving up
if self.rect.y <= SCREEN_HEIGHT - 120:
for mushroom in mushrooms:
if self.rect.colliderect(mushroom.rect):
self.y_direction *= -1 # Reverse to move down when hitting a mushroom
self.move_up_next_frame = True
break
if self.rect.left <= 0 or self.rect.right >= SCREEN_WIDTH:
self.y_direction *= -1 # Reverse to move down when hitting screen edges
self.move_up_next_frame = True
class Centipede(pygame.sprite.Sprite):
def __init__(self, x, y, num_segments, base_speed):
super().__init__()
self.segments = []
self.base_speed = base_speed
# Create each segment of the centipede
for i in range(num_segments):
segment_x = x - i * SEGMENT_SIZE
segment = CentipedeSegment(segment_x, y, base_speed)
self.segments.append(segment)
def update_speed(self):
"""Adjust speed based on the current number of segments."""
if len(self.segments) == 1:
speed = self.base_speed + 125 # * 1.5
elif 2 <= len(self.segments) < 6:
speed = self.base_speed + 75 # * 1.25
else:
speed = self.base_speed
# Update each segment's speed
for segment in self.segments:
segment.speed = speed
def update(self, mushrooms, delta_time):
# Adjust speed based on segment count
self.update_speed()
# Update each segment in order, starting from the head
for i, segment in enumerate(self.segments):
segment.update(mushrooms, delta_time)
if i > 0:
# Align current segment based on the previous segment
prev_segment = self.segments[i - 1]
if segment.x_direction == prev_segment.x_direction:
# Ensure the current segment does not overlap or leave space from the previous segment
if segment.x_direction == 1: # Moving right
segment.rect.x = max(segment.rect.x, prev_segment.rect.x - SEGMENT_SIZE)
else: # Moving left
segment.rect.x = min(segment.rect.x, prev_segment.rect.x + SEGMENT_SIZE)
class Mushroom(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.full_height = SEGMENT_SIZE
self.image = pygame.Surface((SEGMENT_SIZE, self.full_height))
self.health = 3 # Mushrooms take 3 hits to destroy
self.update_mushroom()
self.rect = self.image.get_rect(topleft=(x, y))
def update_mushroom(self):
# Update the mushroom's color based on health, starting dark red and getting lighter
red_value = min(255, 80 + (self.health * 60)) # Increase red with each hit, keeping visibility
self.image.fill((red_value, 0, 0))
# Adjust the visible portion of the mushroom
height_visible = self.full_height * (self.health / 3)
self.image = pygame.Surface((SEGMENT_SIZE, int(height_visible)))
self.image.fill((red_value, 0, 0))
def take_hit(self):
# Increase health when hit and update mushroom sprite
self.health += 1
if self.health < 4:
self.update_mushroom()
else:
self.kill() # Remove mushroom when health reaches 4
def update(self):
pass # No need for continuous updates unless needed in the future
def is_position_valid(x, y, mushrooms):
"""Check if the position (x, y) is valid (not overlapping/touching existing mushrooms)."""
for mushroom in mushrooms:
if mushroom.rect.colliderect(pygame.Rect(x, y, SEGMENT_SIZE, SEGMENT_SIZE)):
return False
return True
# Main game loop setup
# Create sprites groups
centipedes = [Centipede(200, -20, 10, 300), Centipede(240, -100, 12, 225), Centipede(200, -60, 8, 275)]
mushrooms = pygame.sprite.Group()
# Adding a few initial mushrooms ensuring no overlaps
while len(mushrooms) < 40:
x = random.randint(20, SCREEN_WIDTH - SEGMENT_SIZE)
if x % 20 != 0:
x = 20 * round(x/20)
y = random.randint(40, SCREEN_HEIGHT - (SEGMENT_SIZE * 8))
if y % 20 != 0:
y = 20 * round(y/20)
if is_position_valid(x, y, mushrooms):
mushrooms.add(Mushroom(x, y))
running = True
while running:
delta_time = clock.tick(60) / 1000.0 # Convert milliseconds to seconds
screen.fill(BLACK)
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Update centipedes and mushrooms
mushrooms.update()
for centipede in centipedes:
centipede.update(mushrooms, delta_time)
# Draw everything
# for centipede in centipedes:
# for segment in centipede.segments:
# screen.blit(segment.image, segment.rect)
mushrooms.draw(screen)
pygame.display.flip()
pygame.quit()