Created
December 3, 2020 05:19
-
-
Save Krewn/073a8cf8ed32d0d78171d409d71c74f0 to your computer and use it in GitHub Desktop.
A small game using python turtle.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""######################################### Imports ############################################""" | |
import turtle | |
import time | |
import functools | |
"""######################################### Key press ##########################################""" | |
def key_space(): # Resets Level | |
field.setLevel() | |
def key_p(): # Skips Level | |
field.nextLevel() | |
def key_k(): # For making levels | |
print([(b.x,b.y) for b in field.getBoxes()]) | |
"""######################################## Interface(s) ########################################""" | |
def stamp(self): # Interface for drawing polygons. | |
turtle.goto(self.canvasX+field.offset[0],self.canvasY+field.offset[1]) | |
turtle.shape(self.shape) | |
turtle.color(self.color) | |
turtle.stamp() | |
def frameBoiler(func): # | |
@functools.wraps(func) | |
def wrapper_frame_boiler(*args,**kwargs): | |
turtle.clear() | |
#turtle.getscreen().bgpic('Untitled.png') | |
r = func(*args, **kwargs) | |
turtle.update() | |
time.sleep(0.05) | |
return r | |
return wrapper_frame_boiler | |
"""######################################### Game Logic #########################################""" | |
class field: # Field is an abstract class which facilitates the game Mechanics | |
def place(o): # Place translates an objects board position to a pixel or canvas position | |
o.canvasX = (o.x-31)*field.spaceSize # 31 beacuse it's half of the magic number... | |
o.canvasY = (o.y-31)*field.spaceSize | |
return(o) # This method should be a void //TODO refactor... | |
class square: | |
padding = 2 | |
color = "#078900" | |
shape = "sq" # "sq" is the name of the stamp polygon geometry. | |
#//TODO refactor: eliminate redundant literals. see def turtleSetup | |
def __init__(self,x,y): | |
self.x = x | |
self.y = y | |
field.place(self) | |
def draw(self): | |
stamp(self) | |
class level: # Levels are what make the game fun. | |
class mando: # These are the spots you have to populate | |
thickness = 2 # | |
trim = 1 | |
color = "#ee0000" | |
shape = "bx" # "bx" is the name of the stamp polygon geometry. | |
#//TODO refactor: eliminate redundant literals. see def turtleSetup | |
def draw(self): # each mando needs to be visable... | |
stamp(self) # line: 15: `def stamp(self)` | |
def __init__(self,x,y): # make a mandatory space | |
self.x = x | |
self.y = y | |
self.canvasX = 0 # field isn't visible from this deeply nested class | |
self.canvasY = 0 # so these are "unplaced" | |
def __init__(self,text,spots): # make a level | |
self.text = text | |
self.mandos = [] | |
self.complete = False | |
for spot in spots: | |
self.mandos.append(self.mando(spot[0],spot[1])) | |
def checkWin(self): # If the boxes on the board match the mandos you beat the level. | |
oneLiner = set([(b.x,b.y) for b in field.getBoxes()]) | |
isTooLong = set([(m.x,m.y) for m in self.mandos]) | |
self.complete = oneLiner == isTooLong | |
def draw(self): # This draws the mandos and the level's acompanying text. | |
for mando in self.mandos: | |
mando.draw() | |
if self.complete: | |
field.nextLevel() | |
spaces = [[None]*63 for k in range(0,63)] # 63 is the magic number, ralistically it could be 8 | |
levels =[level("letsGo",[(31,33),(31,29),(29,31),(33,31)]), | |
level("Never\nEat\nShreaded\nWheat",[(27, 31), (28, 30), (28, 32), (29, 30), (29, 32), | |
(30, 28), (30, 29), (30, 33), (30, 34), (31, 27), (31, 35), (32, 28), (32, 29), | |
(32, 33), (32, 34), (33, 30), (33, 32), (34, 30), (34, 32), (35, 31)]), | |
level("Try:\nPress Space",[(29, 31), (30, 30), (31, 31), (31, 33), (32, 29), (33, 32), | |
(34, 31)]), | |
level("Flex",[(28, 27), (28, 28), (28, 29), (29, 26), (29, 30), (29, 35), (29, 36), | |
(30, 29), (30, 31), (30, 33), (30, 34), (30, 35), (30, 37), (31, 28), (31, 29), | |
(31, 33), (31, 35), (31, 36), (32, 29), (32, 31), (32, 33), (32, 34), (32, 35), | |
(32, 37), (33, 26), (33, 30), (33, 35), (33, 36), (34, 27), (34, 28), (34, 29)]), | |
level("Blast Off",[(28, 28), (28, 29), (28, 31), (29, 27), (29, 31), (29, 32), (30, 28), | |
(30, 29), (30, 31), (30, 32), (30, 33), (30, 34), (31, 33), (31, 35), (32, 28), | |
(32, 29), (32, 31), (32, 32), (32, 33), (32, 34), (33, 27), (33, 31), (33, 32), | |
(34, 28), (34, 29), (34, 31)]), | |
level("Space\nInvaders",[(27, 31), (28, 30), (28, 32), (29, 27), (29, 28), (29, 30), | |
(29, 31), (30, 26), (30, 28), (30, 29), (30, 33), (31, 27), (31, 28), (31, 31), | |
(31, 32), (32, 26), (32, 28), (32, 29), (32, 33), (33, 27), (33, 28), (33, 30), | |
(33, 31), (34, 30), (34, 32), (35, 31)]), | |
level("big oof",[(31,31),(32,31),(31,33)])] | |
levelIndex = 0 # literally the number indicating what level you're on | |
spaceSize = 40 # the number of pixels to a in gmae space. | |
offset = [-80,0] # you can arbitrailly move the gmae around the screen... | |
def hit(x,y): # toggle the presence of a box in a space on the board/field. | |
try: | |
if field.spaces[x][y] is None: | |
field.spaces[x][y] = field.place(field.square(x,y)) | |
else: | |
field.spaces[x][y] = None | |
except IndexError: | |
pass | |
def setLevel(): # clears the board puts a box in the middle and places the mandos. | |
field.spaces = [[None]*63 for k in range(0,63)] | |
field.hit(31,31) | |
[field.place(mando) for mando in field.levels[field.levelIndex].mandos] | |
def nextLevel(): # the first level is also the level after the last level. | |
field.levelIndex += 1 | |
if field.levelIndex >= len(field.levels): | |
field.levelIndex = 0 | |
field.setLevel() | |
@frameBoiler | |
def draw(): # this is the draw method for the | |
field.levels[field.levelIndex].draw() | |
for box in field.getBoxes(): | |
box.draw() | |
turtle.color("#bad4af")# // Todo figure out why the text causes a flicker. | |
turtle.goto(field.levels[field.levelIndex]. | |
mandos[-1].canvasX,field.levels[field.levelIndex].mandos[-1].canvasY) | |
turtle.write(field.levels[field.levelIndex].text, | |
font=('Courier', 33, 'italic'), align='left') | |
def click(x,y): | |
spacex = int((float(x)-field.offset[0])/field.spaceSize +31) # more magic numbers... | |
spacey = int((float(y)-field.offset[1])/field.spaceSize +32) # change them I dare you. | |
try: | |
field.bop(spacex,spacey) | |
except IndexError: | |
pass | |
field.levels[field.levelIndex].checkWin() | |
def getBoxes(): # in reality field.spaces should just be a dictionary... // TODO | |
return sum([[box for box in boxes if not box is None] for boxes in field.spaces],[]) | |
def bop(x,y): | |
if field.spaces[x][y] is None: | |
pass | |
else: | |
field.hit(x,y) | |
field.hit(x+1,y) | |
field.hit(x-1,y) | |
field.hit(x,y+1) | |
field.hit(x,y-1) | |
"""##############################################################################################""" | |
def turtleSetup(): | |
turtle.tracer(0,0) | |
turtle.register_shape("sq", # This is a square that denotes the boxes... wait | |
((field.square.padding, | |
field.square.padding), | |
(field.spaceSize-field.square.padding, | |
field.square.padding), | |
(field.spaceSize-field.square.padding, | |
field.spaceSize-field.square.padding), | |
(field.square.padding, | |
field.spaceSize-field.square.padding))) | |
turtle.register_shape("bx", # this is a box that is used to denote the mandos... woops. | |
((field.level.mando.trim,field.level.mando.trim), | |
(field.level.mando.thickness, | |
field.level.mando.thickness), | |
(field.spaceSize-field.level.mando.thickness, | |
field.level.mando.thickness), | |
(field.spaceSize-field.level.mando.thickness, | |
field.spaceSize-field.level.mando.thickness), | |
(field.level.mando.thickness, | |
field.spaceSize-field.level.mando.thickness), | |
(field.level.mando.thickness, | |
field.level.mando.thickness), | |
(field.level.mando.trim, | |
field.level.mando.trim), | |
(field.level.mando.trim, | |
field.spaceSize-field.level.mando.trim), | |
(field.spaceSize-field.level.mando.trim, | |
field.spaceSize-field.level.mando.trim), | |
(field.spaceSize-field.level.mando.trim, | |
field.level.mando.trim))) | |
turtle.ht() # Hide Turtle so you don't get a indicator on the rendering mechanism | |
turtle.pu() # Pen up so you don't see the path of the rendering mechanism. | |
turtle.onkey(key_space, "space") # Register key events. | |
turtle.onkey(key_k, "k") | |
turtle.onkey(key_p, "q") | |
turtle.getscreen().onclick(field.click) # register the click event | |
turtle.listen() # this probably needs to be here for some reason, idk delete it & see for yaself | |
"""##############################################################################################""" | |
class main: | |
def __init__(self): | |
turtleSetup() | |
field.setLevel() | |
while None is None: | |
field.draw() | |
main() # Look at how clean that main function is! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment