1

I'm currently working on a game which is like CurveFever (http://forum.curvefever.com/play.html).

The snake trail "draws a line " - stays where it starts. Sometimes it should make a hole. As far as good.

Now to the problem: It should be game over if the snake collides with itself. I tried this with pygame.sprite.collide_circle or pygame.sprite.spritecollide. But now there's a perma-collision because of course some trail-segments reach into the head.


My code: https://pastebin.com/DCb97yd9

import pygame
import os
import math
from random import randint as rand
 
pygame.init()
width, height = 970, 970
screen = pygame.display.set_mode((width, height))
h_center = ((height / 2) - 4)
w_center = ((width / 2) - 4)
 
speed = 2  # constant
 
 
class Head(pygame.sprite.Sprite):
    def __init__(self):
        self.image = pygame.image.load('dotyellow.png')
        self.x = (width / 2)
        self.y = (height / 2)
        self.speed = {'x': 0, 'y': 0}
        self.deg = -90  # up, direction in degrees
        self.rect = self.image.get_rect()
 
    def handle_keys(self):
        key = pygame.key.get_pressed()
        dist = 1
        if key[pygame.K_RIGHT]:
            self.deg += 2.3
        elif key[pygame.K_LEFT]:
            self.deg -= 2.3
        self.speed['x'] = speed * math.cos(math.radians(self.deg))
        self.speed['y'] = speed * math.sin(math.radians(self.deg))
 
    def move(self):
        self.y += self.speed['y']
        self.x += self.speed['x']
        # wrap to other side of screen
        if self.x > width - 13:
            self.x = 5
        elif self.x < 0 + 5:
            self.x = width - 13
        if self.y > height - 13:
            self.y = 5
        elif self.y < 0 + 5:
            self.y = height - 13
 
    def draw(self, surface):
        surface.blit(self.image, (self.x, self.y))
 
    def is_collided_with(self, trail):
        return pygame.sprite.collide_circle(self, trail)
 
 
class Trail(pygame.sprite.Sprite):
    def __init__(self):
        self.image = pygame.image.load('dotred.png')
        self.segments = [None] * 100  # trail has 100 dots
        self.trailTrim = False  # set True for constant trail length
        self.rect = self.image.get_rect()
        self.hitbox = self.segments
 
 
def main():
    head = Head()
    hole = 5
    trail = Trail()
    clock = pygame.time.Clock()
    background = pygame.image.load('backgroundborder.png').convert()
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                running = False
            if event.type == pygame.KEYDOWN:
                print("keydown")
 
        head.handle_keys()
        head.move()
        screen.fill((200, 200, 200))  # clear screen
        screen.blit(background, (0, 0))
        for d in trail.segments:
            if d: screen.blit(trail.image, d)
        if trail.trailTrim:
            del trail.segments[0]  # delete trail end
        if hole >= 100 and rand(1,60) == 60:
            hole = 0
        if hole >= 16:
            trail.segments.append((head.x, head.y))  # add current postiion
        head.draw(screen)  # draw current point
        hole += 1
 
        if head.is_collided_with(trail):
            print('collision!')
        pygame.display.update()
 
        clock.tick(100)  # 100 FPS
 
 
if __name__ == '__main__':
    main()
AutMai
  • 187
  • 4
  • 18

1 Answers1

0

pygame.sprite.collide_circle use the .rect attribute, to determine the location of the Sprite. Hence you've to ensure that both Sprites have set the .rect attributes correctly:

class Head(pygame.sprite.Sprite):
    # [...]
   
    def is_collided_with(self, trail):
        self.rect = self.image.get_rect(topleft = (round(self.x), round(self.y)))
        return pygame.sprite.collide_circle(self, trail)

Note, the .rect attribute of trail has to be set, too. Be aware, that pygame.sprite.collide_circle() just test the collision of 2 Sprites (self and trail). Of course it doesn't consider additional objects stored in trail.segments.

You have to implement a for loop, which evaluates the collision of the head and each part of the tail. Alternatively you can generate a separate pygame.sprite.Sprite for each part of the tail. Add the parts in a pygame.sprite.Group and use pygame.sprite.spritecollide() to test for a collision of the head and the components of the tail in the group.

Furthermore, I recommend to read How do I chain the movement of a snake's body?.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Is 'pygame.sprite.collide_circle()' the right one now? Is the trail-sprite just the 1st circle? – AutMai Jul 31 '20 at 05:18
  • @AutMai As I mention `collide_circle` dos not evaluate the additional elements in `trail.segments`. You have to test the collision in a loop. Alternatively create a Sprite for each part of the Tail and add them to a Group. Finally you can use `pygame.sprite.spritecollide()` – Rabbid76 Jul 31 '20 at 05:29