0

I'm having an issue with my snakegame on the collision detection side. What I wrote originally to do so was this:

snakecollisionchecklist = len(snake.snake_coord_list)
snakecollisionchecklistset = len(set(snake.snake_coord_list))
if snakecollisionchecklist != snakecollisionchecklistset:
    return

The idea being that if any segment position in the snake was equal to another segment position it would abort the program. The problem I found was that the .position() function I was using to find the position of each segment returned a 10 decimal float value, and for whatever reason this wasn't consistent even if the snake was sharing the same place. Converting it to int doesnt work either as that sometimes will make 60 59 etc. if the variance is high/low. To deal with this I put this together, but I feel like this isn't the most efficient way to handle this:

        values_to_convert = segments.position()
        xvaluestoconvert = round(values_to_convert[0],2)
        yvaluestoconvert = round(values_to_convert[1],2)
        self.snake_coord_list[segloc] = (xvaluestoconvert, yvaluestoconvert)

This just takes the individual pieces of the position() and forces it to be rounded. I also had a similar issue with trying to make food not spawn inside the snake, which ended up looking like this:

    newloc= positionlist[0]
    while newloc in positionlist:
        randomx = round((random.randint(-7,7) * 20))
        randomy = round((random.randint(-7,7) * 20))
        newloc = [randomx, randomy]
    self.goto(float(randomx),float(randomy))
    print(f"{randomx} and {randomy}")

But then I still get overlap. Is there a better way to do this? If you're curious about full code it's here:

gamesetup.py

import turtle as t

class FullSnake:
    def __init__(self) -> None:

        self.snake_part_list = []
        self.snake_coord_list = [(-40,0),(-60,0), (-80,0)]
        self.moment_prior_coord_list = [(-40,0),(-60,0), (-80,0)]
        for nums in range(3):
            new_segment = t.Turtle("circle")
            new_segment.penup()
            new_segment.color("white")
            self.snake_part_list.append(new_segment)
            new_segment.goto(self.snake_coord_list[nums])
        self.snake_head = self.snake_part_list[0]
        self.headingverification = 0

    def add_segment(self,):
        """This adds a segment to the snake. the segment added should be initialized to be add the end of the list."""
        new_segment = t.Turtle("circle")
        new_segment.penup()
        new_segment.color("white")
        self.snake_part_list.append(new_segment)
        #self.snake_coord_list.append((self.snake_part_list[0].xcor(),self.snake_part_list[0].ycor()))
        #self.snake_coord_list.append(new_segment)
        # current_final_seg = self.snake_part_list[-2]
        current_final_seg_pos = self.moment_prior_coord_list[-1]
        #self.move_snake()
        new_segment.goto(current_final_seg_pos[0],current_final_seg_pos[1])
        self.snake_coord_list.append(current_final_seg_pos)

    def right(self):
        if self.headingverification != 180:
            self.snake_head.setheading(0)
    # time.sleep(0.031)
    # self.move_snake()
        #ime.sleep(0.05)
    
    def up(self):
        if self.headingverification != 270:
            self.snake_head.setheading(90)
    # time.sleep(0.031)
        #self.move_snake()
        
    def left(self):
        if self.headingverification != 0:
            self.snake_head.setheading(180)
    # time.sleep(0.031)
    # self.move_snake()
        
    def down(self):
        if self.headingverification != 90:
            self.snake_head.setheading(270)
        #time.sleep(0.031)
    # self.move_snake()
        

    def move_snake(self):
        """moves snake. snake moves forward 20 units, and prior units get updated"""
        self.moment_prior_coord_list = list(self.snake_coord_list)
        for seg_num in range(len(self.snake_part_list)-1,0,-1):
            new_x = round(self.snake_part_list[seg_num-1].xcor(),2)
            new_y = round(self.snake_part_list[seg_num-1].ycor(),2)
            self.snake_part_list[seg_num].goto(new_x, new_y)
        self.snake_head.forward(20)
        #print(self.snake_head.position())
        for segments in self.snake_part_list:
            segloc = self.snake_part_list.index(segments)

            #for some reason segments.position() a varied float, so this just forces it to be samesies
            values_to_convert = segments.position()
            xvaluestoconvert = round(values_to_convert[0],2)
            yvaluestoconvert = round(values_to_convert[1],2)
            self.snake_coord_list[segloc] = (xvaluestoconvert, yvaluestoconvert)
        print(self.snake_coord_list)
        

main.py:

import turtle as t
from gamesetup import FullSnake
import time
import food
import score_board as sb

screen = t.Screen()
screen.setup(food.screensize[0],food.screensize[1])
screen.bgcolor("Black")
screen.title("My Snake Game")
screen.tracer(0)


snakefood = food.Food()
snake = FullSnake()
scoreboard = sb.ScoreBoard()

screen.listen()
screen.onkey(snake.up,"Up")
screen.onkey(snake.down,"Down")
screen.onkey(snake.right,"Right")
screen.onkey(snake.left,"Left")

#game_is_on = True

#while game_is_on:

def snakemovefct(): 
    snake.move_snake()      
    screen.update()


    #what happens when you hit food, add to length of snake, increase score and move pellet to place that snake isnt
    if snake.snake_head.distance(snakefood) <5:
        snake.add_segment()
        snakefood.refresh(snake.snake_coord_list)
        scoreboard.score_event()
        screen.update()
        time.sleep(0.1)

    #set gameover if you hit boundary
    if snake.snake_head.xcor() > 150 or snake.snake_head.xcor() < -150 or snake.snake_head.ycor() > 150 or snake.snake_head.ycor() < -150:
        scoreboard.game_over()
        return

    #check collision
    snakecollisionchecklist = len(snake.snake_coord_list)
    snakecollisionchecklistset = len(set(snake.snake_coord_list))
    if snakecollisionchecklist != snakecollisionchecklistset:
        scoreboard.game_over()
        return
    #this makes sure you cant press up and left when moving right to go left
    snake.headingverification = snake.snake_head.heading()
    #keep snake moving in loop, if no recursion it only moves once
    screen.ontimer(snakemovefct,150)


screen.update()
screen.ontimer(snakemovefct,150)
screen.mainloop()

food.py

from turtle import Turtle
import random

screensize = (340, 340)

class Food(Turtle):

    def __init__(self) -> None:
        super().__init__()
        self.shape("square")
        self.penup()
        #self.shapesize(stretch_len=0.5, stretch_wid=0.5)
        self.color("red")
        self.speed("fastest")
        self.refresh([(20,0),(0,0), (-20,0)])

    def refresh(self, positionlist):
        newloc= positionlist[0]
        while newloc in positionlist:
            randomx = "{:.2f}".format(random.randint(-7,7) * 20)
            randomy = "{:.2f}".format(random.randint(-7,7) * 20)
            newloc = [randomx, randomy]
        self.goto(float(randomx),float(randomy))
        print(f"{randomx} and {randomy}")

scoreboard.py

import turtle as t

class ScoreBoard(t.Turtle):

    def __init__(self) -> None:
        super().__init__()
        self.hideturtle()
        self.penup()
        self.pencolor("white")
        self.speed("fastest")
        self.score = 0
        self.goto(0,120)
        self.write(f"Current score: {self.score}", False, align="center")

    def score_event(self):
        self.score +=1
        self.clear()
        self.write(f"Current score: {self.score}", False, align="center")
    
    def game_over(self):
        self.goto(0,0)
        self.write("GAME OVER", False, align="center")
Dragnipur
  • 125
  • 8
  • 1
    Why are you using floats at all? Pixel coordinates are all integers. Why not keep everything in integers? – Tim Roberts Aug 15 '22 at 23:14
  • They don't come out as integers - position() doesn't produce an integer. Then when I store the values from position() into something it turns into lots of decimal places like 59.999999999973 – Dragnipur Aug 15 '22 at 23:16
  • 1
    You could write a little function that calls position(), rounds off its value to the nearest integer, and returns that integer. Then call that function instead of position() every time. – Paul Cornelius Aug 15 '22 at 23:37

0 Answers0