Search code examples
pythonif-statementpygame

Why does my code output the shapes on top of each other and at the wrong spots?


This part of my code is meant to create two shapes on either side of shape already displayed.

pygame.draw.circle(screen, black, button_positions[i], button_radius)
        pygame.draw.polygon(screen, white, button_star_points[i])
        if i == 0:
            g = random.choice([1,2])
            if g == 1:
                j = 2
            elif g == 2:
                j = 1
        if i == 1:
            g = random.choice([0,2])
            if g == 0:
                j = 2
            elif g == 2:
                j = 0
        if i == 2:
            g = random.choice([0,1])
            if g == 0:
                j = 1
            elif g == 1:
                j = 0

        pygame.draw.polygon(screen, white, button_triangle_points[g])
        pygame.draw.polygon(screen, white, button_heart_points[j])
        pygame.display.update()

Here is the full code block for reference.

import pygame
import csv
import time 
import math
import random
from datetime import datetime
#import RPi.GPIO as GPIO
#from picamera2 import Picamera2 , Preview
#from libcamera import controls
#from picamera2.encoders import H264Encoder

# Constants
ITI = 2 # Inter-trial interval in seconds

# Initialize pygame starts
pygame.init()

# Set the dimensions of the screen
screen_width = 1275
screen_height = 750

# Set the colors
white = (255, 255, 255)
black = (0, 0, 0)

# Set the font
font = pygame.font.SysFont('Arial', 20)

# Set the button properties
button_radius = 70
button_x_spacing = 400
button_y_spacing = 200

# Set the button positions
button_positions = [
    (button_x_spacing, button_y_spacing),
    (button_x_spacing, button_y_spacing + 200),
    (button_x_spacing, button_y_spacing + 400)
]

# Drawing Star Function
def generate_star_points(center_x, center_y, outer_radius, inner_radius, points):
    star_points = []
    step = 2 * math.pi / points
    half_step = step / 2
    start_angle = -math.pi * 2 # Start the star with one point facing to the right

    for i in range(points):
        set_point = lambda angle, radius: (
            int(center_x + math.cos(angle - start_angle) * radius),
            int(center_y - math.sin(angle - start_angle) * radius)
        )
        outer_point_angle = i * step
        inner_point_angle = outer_point_angle + half_step
        star_points.append(set_point(outer_point_angle, outer_radius))
        star_points.append(set_point(inner_point_angle, inner_radius))

    return star_points

# Create the star points for each button
num_points = 5  # Number of points in the star
outer_radius = button_radius  # Outer radius of the star
inner_radius = button_radius * 0.5  # Inner radius of the star

# List for star points
button_star_points1 = generate_star_points(button_x_spacing, button_y_spacing, outer_radius, inner_radius, num_points)
button_star_points2 = generate_star_points(button_x_spacing, button_y_spacing + 200, outer_radius, inner_radius, num_points)
button_star_points3 = generate_star_points(button_x_spacing, button_y_spacing + 400, outer_radius, inner_radius, num_points)
button_star_points = [button_star_points1, button_star_points2, button_star_points3]

# Creating the triangle points
def create_triangle(center_x, center_y, radius):
    num_points = 3  # For a triangle
    points = []
    for i in range(num_points):
        angle = 2 * math.pi * i / num_points
        x = center_x + int(radius * math.cos(angle))
        y = center_y + int(radius * math.sin(angle))
        points.append((x, y))
    return points

# List for triangle points
button_triangle_points1 = create_triangle(button_x_spacing, button_y_spacing, button_radius)
button_triangle_points2 = create_triangle(button_x_spacing, button_y_spacing + 200, button_radius)
button_triangle_points3 = create_triangle(button_x_spacing, button_y_spacing + 400, button_radius)
button_triangle_points = [button_triangle_points1, button_triangle_points2, button_triangle_points3]


button_heart_points1 = []
button_heart_points2 = []
button_heart_points3 = []
num_points = 100  # Increase this value for a smoother heart shape
radius = button_radius

for i in range(num_points):
    angle = 2 * math.pi * i / num_points
    x1 = button_x_spacing + int(radius * (13 * math.cos(angle) - 5 * math.cos(2 * angle) - 2 * math.cos(3 * angle) - math.cos(4 * angle)) / 16)
    y1 = button_y_spacing + int(radius * math.sin(angle) ** 3)
    x2 = button_x_spacing + int(radius * (13 * math.cos(angle) - 5 * math.cos(2 * angle) - 2 * math.cos(3 * angle) - math.cos(4 * angle)) / 16)
    y2 = button_y_spacing + 200 + int(radius * math.sin(angle) ** 3)
    x3 = button_x_spacing + int(radius * (13 * math.cos(angle) - 5 * math.cos(2 * angle) - 2 * math.cos(3 * angle) - math.cos(4 * angle)) / 16)
    y3 = button_y_spacing + 400 + int(radius * math.sin(angle) ** 3)
    button_heart_points1.append((x1, y1))
    button_heart_points2.append((x2, y2))
    button_heart_points3.append((x3, y3))

button_heart_points = [button_heart_points1, button_heart_points2, button_heart_points3]

# Inputs
trials = int(input("Number of trials: "))
AnimalName = input("Animal Name: ")
Trial_Duration = int(input("Trial Duration (s): "))

# Setting up Camera
#camera = Picamera2()
#vidconfig = camera.create_video_configuration()
#camera.configure(vidconfig)
#encoder = H264Encoder(bitrate=10000000)
#vidname = f"{AnimalName}_WCST_S3_{datetime.now().strftime('%Y%m%d_%H%M%S')}_Video.h264"
#camera.start_preview(Preview.QTGL)
#camera.start_recording(encoder,vidname)
#camera.annotate_text = f"{AnimalName}_WCST_S3_{datetime.now().strftime('%Y%m%d_%H%M%S')}"


# Initialize the screen
screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN)

# Set the caption
pygame.display.set_caption("Marmoset Buttons")

# Set the clock
clock = pygame.time.Clock()

# Set the counters
correctleft = 0
correctmiddle = 0
correctright = 0
incorrectleft = 0
incorrectmiddle = 0
incorrectright = 0
trialnum = 0
timeouts = 0

# Set the lists
timelistleft = []
timelistmiddle = []
timelistright = []
summarysequence = []

# GPIO Setup
#GPIO.setmode(GPIO.BCM)
#GPIO.setwarnings(False)

# Psuedorandom sequence of numbers
sequence = [1,1,2,2,1,2,1,0,1,1, 1,2,1,0,1,0,1,2,1,1, 2,1,0,1,2,1,1,0,1,2, 2,1,0,2,1,1,1,0,1,1,
           1,1,0,1,1,1,2,0,2,1, 2,1,0,1,0,1,1,2,2,1, 1,0,1,1,0,0,1,1,2,2, 1,1,2,1,1,2,1,0,1,1,
           1,1,1,0,1,1,2,0,2,1, 0,1,1,2,1,0,1,2,1,0, 1,1,0,1,1,2,1,2,1,0, 2,1,2,1,1,2,1,1,0,1,
           1,0,1,1,0,1,1,1,1,1, 1,1,2,1,1,1,0,1,1,2, 1,2,1,0,1,2,2,2,1,0, 1,2,1,0,0,1,2,1,2,0,
           1,0,1,1,1,0,1,1,2,1, 0,1,2,2,1,1,1,0,1,1, 1,0,1,2,0,1,0,1,1,2, 0,1,2,1,2,1,2,2,1,0,
           1,1,1,0,1,1,0,1,1,0, 1,2,2,1,0,1,1,2,0,1, 1,0,1,2,1,0,1,2,1,0, 1,0,1,1,2,2,1,1,0,0,
           1,2,1,2,1,1,1,0,1,0, 1,1,0,1,2,1,1,2,1,0, 1,2,1,1,0,1,0,1,1,0, 1,2,0,2,1,2,1,0,0,1,
           1,1,1,1,0,0,1,2,0,1, 0,1,2,0,1,2,1,2,1,0, 1,0,1,2,1,1,2,0,1,2, 0,0,1,0,2,1,2,1,2,1,
           1,2,2,2,1,1,2,1,1,0, 1,2,1,1,0,2,1,2,1,1, 1,2,2,1,1,2,1,0,0,1, 2,1,2,1,0,2,1,2,0,0,
           1,0,1,1,2,2,1,0,1,0, 0,1,2,1,1,0,1,2,0,1, 1,0,0,1,2,1,2,1,0,0, 1,2,0,0,2,1,0,2,1,1,
           1,1,1,1,2,1,1,0,1,1, 2,1,0,1,1,0,1,2,1,0, 0,1,2,1,2,1,0,1,2,1, 2,1,0,2,1,2,1,1,2,1,
           1,1,0,1,1,1,2,1,1,1, 2,1,2,1,0,0,1,2,1,2, 1,0,1,2,1,2,0,1,2,2, 2,0,1,2,1,2,1,0,1,1,
           1,2,1,0,1,2,0,2,2,2, 1,2,2,1,1,0,1,1,0,0, 1,1,0,1,0,0,1,2,1,2, 1,0,2,1,2,1,2,1,0,1,
           1,2,1,1,0,1,1,0,0,1, 1,1,1,2,1,1,0,1,1,1, 1,2,1,0,2,2,1,2,0,1, 1,1,2,2,1,0,1,2,1,0,
           1,2,0,1,1,0,1,1,2,1, 1,2,2,2,1,1,1,0,1,0, 1,2,0,0,0,1,2,2,0,1, 0,2,1,0,0,1,2,2,2,1,
           1,1,2,1,0,1,0,1,2,1, 1,2,1,0,1,1,2,1,0,2, 1,0,2,2,1,0,1,0,2,1, 1,0,2,1,2,1,1,0,0,1,
           1,2,1,2,1,1,1,0,1,1, 1,1,0,0,1,2,1,2,1,0, 1,2,1,2,2,1,0,1,0,0, 2,1,0,2,0,1,0,1,2,1,
           1,1,0,1,0,1,1,1,0,1, 1,2,1,0,1,0,1,2,1,0, 2,1,2,2,1,0,1,0,1,1, 2,1,2,0,1,2,1,2,0,0,
           1,1,2,0,2,1,2,1,1,0, 1,2,1,0,0,1,1,2,1,2, 1,2,2,1,1,1,1,2,0,0, 1,2,1,0,0,2,1,0,2,1,
           1,0,1,1,2,1,2,0,1,2, 2,1,0,1,1,0,1,2,1,0, 0,1,0,1,2,1,1,2,1,0, 2,2,1,0,0,1,2,1,2,1]

# Truncating list
#trials = int(input("Number of trials: "))
n = len(sequence)
for i in range(0, n - trials):
    sequence.pop()

# Setting up CSV title
thedatetime = datetime.now()
thetime = thedatetime.strftime("%H:%M:%S")
title = f"{AnimalName}_WCST_S5a_SimpleShape2_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"

# Write headers to csv file
data = open(title, 'w')
writer = csv.writer(data)
writer.writerow(["Trial#", "Event Code", "Time"])

time_start = time.time()

# For loop parsing through sequence 
for i in sequence:

    trialnum += 1
    summarysequence.append(i)

    # Writing summary csv 
    if trialnum%10 == 0:
        if trialnum == 10:
            title2 = f"{AnimalName}_WCST_S5a_SimpleShape2_{datetime.now().strftime('%Y%m%d_%H%M%S')}_Summary.txt"
            summary = open(title2, "a+")
            summary.write(f"Trial Duration: {Trial_Duration}\n")
            summary.write(f"ITI: {ITI}\n")
        meanleft = sum(timelistleft) / len(timelistleft)
        meanmiddle = sum(timelistmiddle) / len(timelistmiddle)
        meanright = sum(timelistright) / len(timelistright)
        summary.write(f"Completed Trials (saved every 10th): {trialnum}\n")
        summary.write("Sequence: " + str(summarysequence) + "\n")
        summary.write(f"Correct: {correctleft},{correctmiddle},{correctright}\n")
        summary.write(f"Incorrect: {incorrectleft},{incorrectmiddle},{incorrectright}\n")
        summary.write(f"Total Reward: {correctleft+correctmiddle+correctright}\n")
        summary.write(f"Total No Reponses: {timeouts}\n")
        summary.write(f"Mean Reaction Times: {meanleft}, {meanmiddle}, {meanright}\n")
        summary.write("------------------------------------------------------------\n")

    # Delay between buttons
    screen.fill(black)
    pygame.display.update()

    # ITI
    time_before = time.time()
    loop_counter = 0
    
    while time.time() - time_before < ITI:
        pygame.draw.rect(screen, white, pygame.Rect(button_x_spacing - 10, button_y_spacing + 200 - button_radius + 10, 20, button_radius*2 - 20))
        pygame.draw.rect(screen, white, pygame.Rect(button_x_spacing - button_radius + 10, button_y_spacing + 200 - 10, button_radius*2 - 20, 20))
        pygame.display.update()
        pygame.time.delay(100)
        pygame.event.pump()
        if pygame.mouse.get_pressed()[0]:
            if i == 0:
                writer.writerow([trialnum, 210, time.time() - time_start])
            elif i == 1:
                writer.writerow([trialnum, 211, time.time() - time_start])
            elif i == 2:
                writer.writerow([trialnum, 212, time.time() - time_start])
    
    screen.fill(black)
    pygame.display.update()

    # While loop variable 
    correct = False

    # Starts Timer 
    #start_time = pygame.time.get_ticks()
    start_time = time.time()
    
    # Writing the button in csv file
    timedisplay = time.time()
    writer.writerow([trialnum, i, timedisplay - time_start])

    # Loops while button isn't correct 
    while correct == False:

        # Time out for 15 seconds 
        seconds = (time.time() - start_time)
        if seconds >= Trial_Duration:
            timeouts +=1
            timenow = time.time()
            writer.writerow([trialnum, 250, timenow - time_start])
            break

        # Checks when screen is touched 
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONDOWN:

                # Distance between point touched and button 
                distance_button = pygame.math.Vector2(button_positions[i]) - pygame.math.Vector2(pygame.mouse.get_pos())

                # Checks if distance is within button 
                if distance_button.length() < button_radius:

                    correct = True
                    timecorrect = time.time()
                    writer.writerow([trialnum, 150, timecorrect - time_start])

                    # Reward
                    #GPIO.setup(12,GPIO.OUT)
                    #GPIO.output(12,GPIO.HIGH)
                    #time.sleep(0.1)
                    #GPIO.output(12,GPIO.LOW)
                    #GPIO.cleanup()

                    # Counts which buttons were pressed 
                    if i == 0:
                        timecorrect = time.time()
                        timedifference = timecorrect - timedisplay
                        timelistleft.append(timedifference)
                        correctleft += 1
                    elif i == 1:
                        timecorrect = time.time()
                        timedifference = timecorrect - timedisplay
                        timelistmiddle.append(timedifference)
                        correctmiddle += 1
                    elif i == 2:
                        timecorrect = time.time()
                        timedifference = timecorrect - timedisplay
                        timelistright.append(timedifference)
                        correctright += 1

                # Counts when touch was outside of button 
                elif distance_button.length() > button_radius:
                    correct = True
                    x, y = pygame.mouse.get_pos()
                    if y <= (screen_height/3):
                        incorrectleft += 1
                        timenow = time.time()
                        writer.writerow([trialnum, 201, timenow - time_start])
                    elif y <= 2*(screen_height/3):
                        incorrectmiddle += 1
                        timenow = time.time()
                        writer.writerow([trialnum, 200, timenow - time_start])
                    elif y > 2*(screen_height/3):
                        incorrectright += 1
                        timenow = time.time()
                        writer.writerow([trialnum, 202, timenow - time_start])   

        # Draws the button 
        pygame.draw.circle(screen, black, button_positions[i], button_radius)
        pygame.draw.polygon(screen, white, button_star_points[i])
        if i == 0:
            g = random.choice([1,2])
            if g == 1:
                j = 2
            elif g == 2:
                j = 1
        if i == 1:
            g = random.choice([0,2])
            if g == 0:
                j = 2
            elif g == 2:
                j = 0
        if i == 2:
            g = random.choice([0,1])
            if g == 0:
                j = 1
            elif g == 1:
                j = 0

        pygame.draw.polygon(screen, white, button_triangle_points[g])
        pygame.draw.polygon(screen, white, button_heart_points[j])
        pygame.display.update()

# Closing objects 
data.close()
summary_contents = summary.read()
print(summary_contents)
summary.close()
#camera.stop_recording()
#camera.stop_preview()

It displays both the triangle and the heart shape at both sides of the star. I want the heart shape on one side and the triangle on the other. I tried to test it out with just simple terminal print instead of drawing the shapes and it seemed to work.

This is what the output looks like.

I'm not sure how this is as inside the while loop I'm only calling for the shape to generate once.


Solution

  • You must select the random objects before the while correct loop, but not in the loop. The loop is run in each frame, if you select new random objects in each frame, they will be drawn on top each other.

        if i == 0:
            g = random.choice([1,2])
            if g == 1:
                j = 2
            elif g == 2:
                j = 1
        if i == 1:
            g = random.choice([0,2])
            if g == 0:
                j = 2
            elif g == 2:
                j = 0
        if i == 2:
            g = random.choice([0,1])
            if g == 0:
                j = 1
            elif g == 1:
                j = 0
    
        # Loops while button isn't correct 
        while correct == False:
    
            # [...]