Anyway, I applied the UI changes and made the Credits button work.
Code: Select all
# Conway's Game of Life--a tutorial
# Made by squareroot12621.
import random, time, turtle
turtle.setup(1280, 720)
window = turtle.Screen()
canvas = window.getcanvas()
window.title("Conway's Game of Life\u2014a tutorial")
turtle.tracer(0)
t = turtle.Turtle() # Draws objects that are refreshed every frame
f = turtle.Turtle() # Draws objects that are refreshed when mode changes
mode = 'loading'
lastMode = None # Must be different from 'loading'
# so that draw_loading_first() triggers
lastLoadingFrame = -1
def in_rectangle(x, y, leftX, topY, rightX, bottomY, border=0):
'''Return whether (x, y) is within border pixels of the rectangle
(leftX, topY) to (rightX, bottomY).
'''
return (leftX - border / 2 <= x <= rightX + border / 2
and bottomY - border / 2 <= y <= topY + border / 2)
def read_and_parse_lesson_file():
'''Yield loading messages until file 'CGOLATUTORIAL-lessons.txt' is
read and parsed.
'''
global mode
# I removed the part of the code that opens a file and parses it,
# so that you don't have to make the file yourself.
yield 'Loading message #1...'
yield 'Loading message #2...'
yield 'Loading message #3...'
def draw_loading_first():
'''Draws the part of the loading screen that's only drawn once.'''
global lessonParser
lessonParser = read_and_parse_lesson_file() # Makes loading messages
window.bgcolor('#000000')
# Write the "Loading..." text
f.goto(0, 0)
f.color('#FFFFFF')
f.write('Loading...', align='center', font=('Arial', 28, 'normal'))
def draw_loading():
'''Draws the part of the loading screen that's drawn every frame.'''
global lastLoadingFrame, lessonParser, mode
# Draw the p30 glider stream
loadingFrame = int(time.time() * 18 % 30) # 18 FPS, 30 frames
if loadingFrame != lastLoadingFrame:
lastLoadingFrame = loadingFrame
gliderPhases = [[(1, 0), (2, 1), (0, 2), (1, 2), (2, 2)],
[(0, 1), (2, 1), (1, 2), (2, 2), (1, 3)],
[(2, 1), (0, 2), (2, 2), (1, 3), (2, 3)],
[(1, 1), (2, 2), (3, 2), (1, 3), (2, 3)]]
# Generate the cells
cellsOn = []
for glider in range(20):
for cell in gliderPhases[(loadingFrame + 30 * glider) % 4]:
cellsOn.append([dimension + (loadingFrame + 30 * glider) // 4
for dimension in cell])
# Draw the cells and delete the old ones
canvas.delete('loading')
for cell in cellsOn:
leftX = 6*cell[0] - 220
topY = 6*cell[1] - 396
canvas.create_rectangle(leftX, topY, leftX + 5, topY - 5,
fill='#FFFFFF', width=0, tag='loading')
# Write loading messages
t.color('#CCCCCC')
t.goto(0, -30)
try:
loadingMessage = next(lessonParser)
except StopIteration:
loadingMessage = 'Done!'
mode = 'main'
t.write(loadingMessage, align='center', font=('Arial', 18, 'normal'))
def draw_main_first():
'''Draws the part of the main menu that's only drawn once.'''
window.bgcolor('#222222')
canvas.delete('loading')
# Conway's Game of Life
f.color('#FFFFFF')
f.goto(0, 250)
f.write("Conway's Game of Life", align='center',
font=('Arial', 40, 'normal'))
# --- the tutorial ---
f.color('#999999')
f.goto(0, 210)
f.write('\u2014\u2014\u2014 the tutorial \u2014\u2014\u2014',
align='center', font=('Arial', 24, 'italic'))
# Buttons
f.pensize(3)
for x, text, top, bottom in [(-420, 'Play',
"Learn Conway's Game of",
'Life with 5-minute lessons'),
(-140, 'Sandbox',
"Play with Conway's Game",
'of Life on your own'),
(140, 'Settings',
'Change your language,',
'reset your progress, etc.'),
(420, 'Credits',
'Thanks to everyone who',
'has contributed to this!')]:
# Button outline and fill
f.goto(x - 120, 100)
if text == 'Play':
f.pencolor('#BFDEB2')
f.fillcolor('#1C3210')
elif text == 'Sandbox':
f.pencolor('#DED1B2')
f.fillcolor('#322610')
elif text == 'Settings':
f.pencolor('#D1B2DE')
f.fillcolor('#261032')
elif text == 'Credits':
f.pencolor('#B2BFDE')
f.fillcolor('#101C32')
f.pendown()
f.begin_fill()
f.goto(x + 120, 100)
f.goto(x + 120, -200)
f.goto(x - 120, -200)
f.goto(x - 120, 100)
f.end_fill()
f.penup()
# Artwork for each button
if text == 'Play':
# "Lessons"
for rectX, rectY, num in [(-490, -90, '1'), (-450, 0, '2'),
(-350, -10, '3'), (-380, -100, '4')]:
# Inner border and fill
f.fillcolor('#77B359')
f.pencolor('#1C3210')
f.goto(rectX - 27, rectY + 27)
f.pendown()
f.begin_fill()
f.goto(rectX + 27, rectY + 27)
f.goto(rectX + 27, rectY - 27)
f.goto(rectX - 27, rectY - 27)
f.goto(rectX - 27, rectY + 27)
f.end_fill()
f.penup()
# Outer border
f.pencolor('#BFDEB2')
f.goto(rectX - 30, rectY + 30)
f.pendown()
f.goto(rectX + 30, rectY + 30)
f.goto(rectX + 30, rectY - 30)
f.goto(rectX - 30, rectY - 30)
f.goto(rectX - 30, rectY + 30)
f.penup()
# Text
f.pencolor('#1C3210')
for deltaX in range(2):
for deltaY in range(-22, -20):
f.goto(rectX + deltaX, rectY + deltaY)
f.write(num, align='center', font=('Arial', 28, 'normal'))
# Lines between "lessons"
f.pencolor('#BFDEB2')
for x1, y1, x2, y2 in [(-540, -85, -520, -90),
(-480, -60, -460, -30),
(-420, -2, -380, -8),
(-355, -40, -375, -70),
(-350, -100, -300, -90)]:
f.goto(x1, y1)
f.pendown()
f.goto(x2, y2)
f.penup()
elif text == 'Sandbox':
# Sandbox
f.goto(-220, 10)
f.pendown()
f.goto(-60, 10)
f.goto(-40, -100)
f.goto(-240, -100)
f.goto(-220, 10)
f.penup()
f.goto(-40, -100)
f.pendown()
f.goto(-40, -120)
f.goto(-240, -120)
f.goto(-240, -100)
f.goto(-40, -100)
f.penup()
# Boat
f.fillcolor('#B39559')
f.goto(-100, 0)
f.begin_fill()
f.goto(-97, -24)
f.goto(-107, -24)
f.goto(-108, -16)
f.goto(-88, -16)
f.goto(-89, -8)
f.goto(-109, -8)
f.goto(-108, -16)
f.goto(-118, -16)
f.goto(-120, 0)
f.goto(-100, 0)
f.end_fill()
# Beacon
f.goto(-150, -50)
f.begin_fill()
f.goto(-150, -58)
f.goto(-160, -58)
f.goto(-160, -66)
f.goto(-170, -66)
f.goto(-170, -50)
f.goto(-150, -50)
f.end_fill()
f.goto(-130, -82)
f.begin_fill()
f.goto(-130, -66)
f.goto(-140, -66)
f.goto(-140, -74)
f.goto(-150, -74)
f.goto(-150, -82)
f.goto(-130, -82)
f.end_fill()
# Block
f.goto(-195, -20)
f.begin_fill()
f.goto(-193, -4)
f.goto(-173, -4)
f.goto(-175, -20)
f.goto(-195, -20)
f.end_fill()
elif text == 'Settings':
f.goto(140, -80)
f.pensize(20)
f.pendown()
f.circle(30)
f.penup()
f.pensize(10)
f.goto(f.xcor() - 1, f.ycor() - 2)
for tooth in range(8):
f.backward(4)
f.right(90)
f.pendown()
f.forward(18)
f.left(90)
f.forward(10)
f.left(90)
f.forward(18)
f.right(180)
f.penup()
f.left(90)
f.backward(4)
f.circle(30, 45)
f.pensize(3)
elif text == 'Credits':
# Glider trophy
f.pencolor('#B2BFDE')
f.fillcolor('#5977B3')
f.goto(465, 39)
f.pendown()
f.begin_fill()
f.goto(375, 39)
f.goto(375, 7)
f.goto(435, 7)
f.goto(435, -57)
f.goto(405, -57)
f.goto(405, -25)
f.goto(465, -25)
f.goto(465, 39)
f.end_fill()
f.penup()
# Left stickman
f.goto(375, -140) # Body
f.pendown()
f.goto(375, -110)
f.circle(17) # Head
f.penup()
f.goto(369, -140) # Left arm
f.pendown()
f.goto(370, -135)
f.goto(375, -126)
f.goto(390, -115) # Right arm
f.goto(394, -108)
f.goto(397, -102)
f.goto(401, -90)
f.goto(404, -61) # Right hand
f.goto(409, -61)
f.goto(409, -60)
f.goto(404, -60)
f.penup()
f.goto(383, -84) # Eye
f.pendown()
f.goto(384, -87)
f.penup()
f.goto(384, -96) # Mouth
f.pendown()
f.goto(388, -98)
f.goto(390, -98)
f.penup()
# Middle stickman
f.goto(428, -140) # Body
f.pendown()
f.goto(428, -105)
f.circle(15) # Head
f.penup()
f.goto(413, -60) # Left hand
f.pendown()
f.goto(418, -60)
f.goto(418, -61)
f.goto(413, -61)
f.goto(413, -68) # Left arm
f.goto(414, -74)
f.goto(415, -82)
f.penup()
f.goto(420, -104)
f.pendown()
f.goto(423, -111)
f.goto(428, -116) # Right arm
f.goto(432, -111)
f.goto(434, -104)
f.penup()
f.goto(436, -76)
f.pendown()
f.goto(436, -74)
f.goto(435, -61) # Right hand
f.goto(430, -61)
f.goto(430, -60)
f.goto(435, -60)
f.penup()
f.pensize(2)
f.goto(421, -86) # Left eye
f.pendown()
f.goto(422, -83)
f.goto(423, -82)
f.goto(424, -83)
f.goto(425, -86)
f.penup()
f.goto(431, -86) # Right eye
f.pendown()
f.goto(432, -83)
f.goto(433, -82)
f.goto(434, -83)
f.goto(435, -86)
f.penup()
f.pensize(3)
f.fillcolor('#B2BFDE')
f.goto(422, -94) # Mouth
f.pendown()
f.begin_fill()
f.goto(434, -94)
f.goto(431, -97)
f.goto(428, -98)
f.goto(425, -97)
f.goto(422, -94)
f.end_fill()
f.penup()
# Right stickman
f.goto(479, -140) # Body
f.pendown()
f.goto(479, -105)
f.circle(16) # Head
f.penup()
f.goto(451, -28) # Left hand
f.pendown()
f.goto(447, -28)
f.goto(447, -29)
f.goto(451, -29)
f.goto(465, -80) # Left arm
f.penup()
f.goto(470, -101)
f.pendown()
f.goto(473, -111)
f.goto(476, -114)
f.goto(479, -117)
f.penup() # (waving right arm is drawn by the t turtle)
f.goto(474, -83) # Left eye
f.pendown()
f.goto(474, -85)
f.penup()
f.goto(484, -83) # Right eye
f.pendown()
f.goto(484, -85)
f.penup()
f.pensize(2) # Mouth
f.goto(472, -92)
f.pendown()
f.goto(486, -92)
f.goto(483, -96)
f.goto(479, -98)
f.goto(475, -96)
f.goto(472, -92)
f.penup()
f.pensize(3)
# Button name and subtitle
f.goto(x, 50)
f.write(text, align='center', font=('Arial', 28, 'normal'))
f.goto(x, -170)
f.write(top, align='center', font=('Arial', 14, 'normal'))
f.goto(x, -192)
f.write(bottom, align='center', font=('Arial', 14, 'normal'))
def draw_main():
'''Draws the part of the main menu that's redrawn every frame.'''
# Draw the animated waving hand on the right stick figure
t.pencolor('#B2BFDE')
t.pensize(3)
t.goto(479, -117)
t.pendown()
if time.time() * 5 % 1 > 0.7:
t.goto(491, -115)
t.goto(495, -112)
t.penup()
t.pensize(2)
t.goto(498, -105)
t.pendown()
t.goto(500, -109)
t.penup()
t.goto(502, -100)
t.pendown()
t.goto(505, -107)
t.penup()
t.pensize(3)
elif int(time.time() * 5 % 2) == 0:
t.goto(490, -115)
t.goto(494, -111)
t.goto(501, -98)
else:
t.goto(492, -116)
t.goto(505, -110)
t.penup()
def draw_credits_first():
'''Draws the part of the credits that's only drawn once.'''
window.bgcolor('#203763')
# Back button
f.pensize(3)
f.pencolor('#B2BFDE')
f.fillcolor('#101C32')
f.goto(-700, -320)
f.pendown()
f.begin_fill()
f.goto(-700, -272)
f.goto(-480, -272)
f.goto(-480, -320)
f.goto(-700, -320)
f.end_fill()
f.penup()
f.goto(-490, -315)
f.write('\u2039 Back', align='right', font=('Arial', 24, 'normal'))
f.goto(-300, 316)
for role, *people in [('PROJECT STARTER', 'Aura'),
('EXERCISE CREATORS', 'confocaloid',
'hotcrystal0',
'hotdogPi', ''),
('CONCEPT ARTIST', 'squareroot12621'),
('UI DESIGNERS', 'squareroot12621',
'wirehead', ''),
('SOFTWARE DEVELOPER', 'squareroot12621'),
]:
if role == '\n': # Column break
f.goto(300, 316)
continue
f.write(role + ' \u2013 ', align='right', font=('Arial', 14, 'bold'))
f.goto(f.xcor(), f.ycor() - 1)
for person in people:
f.write(person, align='left', font=('Arial', 16, 'normal'))
f.goto(f.xcor(), f.ycor() - 20)
f.goto(f.xcor(), f.ycor() - 4)
def draw_credits():
'''Draws the part of the credits that's redrawn every frame.'''
pass
def draw_screen():
'''Draws the screen depending on the mode.'''
global lastMode
newMode = mode != lastMode # Triggers draw_<mode>_first() functions
lastMode = mode
if newMode:
f.reset()
f.hideturtle()
f.penup()
t.reset()
t.hideturtle()
t.penup()
if mode == 'loading':
if newMode:
draw_loading_first()
draw_loading()
elif mode == 'main':
if newMode:
draw_main_first()
draw_main()
elif mode == 'credits':
if newMode:
draw_credits_first()
draw_credits()
window.update()
window.ontimer(draw_screen, 20)
def click_handler(x, y):
'''Handles clicks from the user.'''
global mode
if mode == 'main':
if in_rectangle(x, y, -540, 100, -300, -200, 3): # Play
mode = 'main' # Doesn't do anything yet
elif in_rectangle(x, y, -260, 100, -20, -200, 3): # Sandbox
mode = 'main' # Doesn't do anything yet
elif in_rectangle(x, y, 20, 100, 260, -200, 3): # Settings
mode = 'main' # Doesn't do anything yet
elif in_rectangle(x, y, 300, 100, 540, -200, 3): # Credits
mode = 'credits'
elif mode == 'credits':
if in_rectangle(x, y, -700, -272, -480, -320, 3): # Back from Credits
mode = 'main'
window.onclick(click_handler, btn=1) # Activate on left-click
draw_screen()
window.listen()
window.mainloop()