Suggestions/Improvements (pygame) - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Game Development (https://python-forum.io/forum-11.html) +--- Thread: Suggestions/Improvements (pygame) (/thread-17535.html) |
Suggestions/Improvements (pygame) - SheeppOSU - Apr-15-2019 I finally reached the start of my game. I'm gonna add more to it but before that, I would like some suggestions on what i can improve on. P.S. I'm going to add pickle so don't suggest that. Thx in Advance! DestinationFunc.py import pygame class Screen_Display(): def text_objects(text, font, color): textSurface = font.render(text, True, color) return textSurface, textSurface.get_rect() def message_display(gD, text, size, color, centerX, centerY): font = pygame.font.SysFont('arial', size) textSurf, TextRect = Screen_Display.text_objects(text, font, color) TextRect.center = ((centerX),(centerY)) gD.blit(textSurf, TextRect) class Button(): def __init__(self, rect, text, textsize, textcolor): self.rect = rect self.font = pygame.font.SysFont('arial', textsize) self.textSurf, self.textRect = Screen_Display.text_objects(text, self.font, textcolor) self.textRect.center = ((rect[0] + (rect[2]/2), rect[1] + (rect[3]/2))) def draw(self, gD, ButColor): pygame.draw.rect(gD, ButColor, (self.rect)) gD.blit(self.textSurf, self.textRect) def optClick(self, gD, ShadowColor, ButColor, command=None, command2=None): mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() if self.rect[0] + self.rect[2] > mouse[0] > self.rect[0] and self.rect[1] + self.rect[3] > mouse[1] > self.rect[1]: pygame.draw.rect(gD, ShadowColor, (self.rect)) gD.blit(self.textSurf, self.textRect) if click[0] == 1: if command != None: command() if command2 != None: command2() else: pygame.draw.rect(gD, ButColor, (self.rect)) gD.blit(self.textSurf, self.textRect)Main.py import pygame import random import time import threading from pygame.locals import * from DestinationFunc import Screen_Display as SD from DestinationFunc import Button as BT """ """ width = 1000 height = 800 pygame.init() gD = pygame.display.set_mode((width, height)) #Files WoodBat = (pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/WoodenBat.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/WoodenBatRight.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/WoodenBatDown.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/WoodenBatLeft.png")) SpikeBat = (pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/Spiked_Bat.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/Spiked_BatRight.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/Spiked_BatDown.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/Spiked_BatLeft.png")) IronBat = (pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/MetalBat.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/MetalBatRight.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/MetalBatDown.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/MetalBatLeft.png")) IronSword = (pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/IronSword.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/IronSwordRight.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/IronSwordDown.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/IronSwordLeft.png")) DiamondSword = (pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/DiamondSword.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/DiamondSwordRight.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/DiamondSwordDown.png"), pygame.image.load("C:/Users/Chadd/Desktop/Ayden Stuff/DiamondSwordLeft.png")) #Colors black = (0,0,0) white = (255,255,255) red = (255,0,0) darker_red = (200,0,0) green = (0,255,0) lightest_blue = (0,0,255) lighter_blue = (0,0,200) light_blue = (0,0,160) blue = (0,0,120) brown = (165,42,42) light_brown = (139,69,19) CustomColor1 = (48,150,140) CustomColor2 = (36,112.5,105) Unique_Color = (190,140,210) ColorList = [black, red, green, blue, white, brown, lightest_blue, lighter_blue, light_blue] pause = False class GameData(): def __init__(self): signInList = {'Sheepposu' : 'rachl032078', 'gg' : 'rachl1979', 'Tallish Walk' : '092404Aw'} UserArmor = {'Sheepposu' : light_blue, 'gg' : brown, 'Tallish Walk' : brown} UserWeap = {'Sheepposu' : DiamondSword, 'gg' : WoodBat, 'Tallish Walk' : WoodBat} UserLvl = {'Sheepposu' : '1', 'gg' : '1', 'Tallish Walk' : '1'} self.signInList = signInList self.UserArmor = UserArmor self.UserWeap = UserWeap self.UserLvl = UserLvl def getListings(self): return self.signInList, self.UserArmor, self.UserWeap, self.UserLvl #Config fps = 100 pygame.display.set_caption('Destination') clock = pygame.time.Clock() gD.fill(blue) clock.tick(15) #Variables Confirm = True username = None class Player(): def __init__(self, x, y, width, height, color, weapType): self.x = x self.y = y self.width = width self.height = height self.rect = (x, y, width, height) self.color = color self.direct = None self.weapon = None self.weaponPos = None self.weapType = weapType self.damageDealt = 0 if weapType == WoodBat: self.damage = .5 elif weapType == DiamondSword: self.damage = 5 def draw(self): pygame.draw.rect(gD, self.color, (self.rect)) self.drawWeap() def drawWeap(self): if self.direct == 'Left': self.weapon = gD.blit(self.weapType[3], (self.x - round(self.width*.8), self.y + round(self.height/2))) self.weaponPos = (self.x - round(self.width*.8), self.y + round(self.height/2)) if self.direct == 'Right': self.weapon = gD.blit(self.weapType[1], (self.x + round(self.width*.8), self.y + round(self.height/2))) self.weaponPos = (self.x + round(self.width*.8), self.y + round(self.height/2)) if self.direct == 'Up': self.weapon = gD.blit(self.weapType[0], (self.x + round(self.width/2), self.y - round(self.height*.8))) self.weaponPos = (self.x + round(self.width/2), self.y - round(self.height*.8)) if self.direct == 'Down': self.weapon = gD.blit(self.weapType[2], (self.x + round(self.width/2), self.y + round(self.height*.8))) self.weaponPos = (self.x + round(self.width/2), self.y + round(self.height*.8)) self.update() def getWeapPos(self): if self.weaponPos != None: return self.weaponPos def move(self, e): keyed = pygame.key.get_pressed() self.takeHit(e.getWeapPos()) if self.x >= 0 and self.x + self.width <= width and self.y >= 0 and self.y + self.height <= height: if keyed[pygame.K_LEFT] or keyed[pygame.K_a]: self.x -= 1 self.direct = 'Left' if keyed[pygame.K_RIGHT] or keyed[pygame.K_d]: self.x += 1 self.direct = 'Right' if keyed[pygame.K_UP] or keyed[pygame.K_w]: self.y -= 1 self.direct = 'Up' if keyed[pygame.K_DOWN] or keyed[pygame.K_s]: self.y += 1 self.direct = 'Down' elif self.x <= 0: self.x += 5 elif self.x - self.width >= width: self.x -= 5 elif self.y <= 0: self.y += 5 elif self.y - self.height >= height: self.y -= 5 self.update() def update(self): self.rect = (self.x, self.y, self.width, self.height) def getPos(self): return self.x, self.y def getDamageDealt(self): return self.damageDealt def healthBar(self, num): pygame.draw.rect(gD, black, (self.rect[0], self.rect[1] - 20, self.rect[2], 10)) pygame.draw.rect(gD, red, (self.rect[0] + 2, self.rect[1] - 18, self.rect[2] - num, 6)) if self.rect[2] - num == 0: End_Game(Died=True) def takeHit(self, weapPos): if weapPos: EnPos = (self.x, self.y, self.x + self.width, self.y + self.height) if weapPos[0] >= EnPos[0] and weapPos[0] <= EnPos[2] and weapPos[1] >= EnPos[1] and weapPos[1] <= EnPos[3]: self.damageDealt += self.damage class Enemy(): def __init__(self, x, y, width, height, color, weapType, diff): self.x = x self.y = y self.width = width self.height = height self.rect = (x, y, width, height) self.color = color self.direct = None self.weapon = None self.damageDealt = 0 self.weapType = weapType self.weaponPos = None self.diff = diff self.dead = False if weapType == WoodBat: self.damage = .5 def draw(self): if not self.dead: pygame.draw.rect(gD, self.color, (self.rect)) self.drawWeap() def drawWeap(self): if not self.dead: if self.direct == 'Left': self.weapon = gD.blit(self.weapType[3], (self.x - round(self.width*.8), self.y + round(self.height/2))) self.weaponPos = (self.x - round(self.width*.8), self.y + round(self.height/2)) if self.direct == 'Right': self.weapon = gD.blit(self.weapType[1], (self.x + round(self.width*.8), self.y + round(self.height/2))) self.weaponPos = (self.x + round(self.width*.8), self.y + round(self.height/2)) if self.direct == 'Up': self.weapon = gD.blit(self.weapType[0], (self.x + round(self.width/2), self.y - round(self.height*.8))) self.weaponPos = (self.x + round(self.width/2), self.y - round(self.height*.8)) if self.direct == 'Down': self.weapon = gD.blit(self.weapType[2], (self.x + round(self.width/2), self.y + round(self.height*.8))) self.weaponPos = (self.x + round(self.width/2), self.y + round(self.height*.8)) self.update() def move(self, p): if not self.dead: plrPos = p.getPos() plrX = plrPos[0] plrY = plrPos[1] self.takeHit(p.getWeapPos()) DownRight = ['Down', 'Right'] UpRight = ['Right', 'Up'] UpLeft = ['Up', 'Left'] DownLeft = ['Down', 'Left'] AnyDirect = ['Down', 'Up', 'Left', 'Right'] if plrX > self.x and plrY > self.y: self.x += .2 self.y += .2 num = random.randint(1, 100) if num < 3: self.direct = random.choice(DownRight) elif plrX > self.x and plrY < self.y: num = random.randint(1, 100) if num < 3: self.direct = random.choice(UpRight) self.x += .2 self.y -= .2 elif plrX < self.x and plrY < self.y: num = random.randint(1, 100) if num < 3: self.direct = random.choice(UpLeft) self.x -= .2 self.y -= .2 elif plrX < self.x and plrY > self.y: num = random.randint(1, 100) if num < 3: self.direct = random.choice(DownLeft) self.x -= .2 self.y += .2 elif plrX == self.x and plrY > self.y: num = random.randint(1, 100) if num < 3: self.direct = 'Down' self.y += .2 elif plrX == self.x and plrY < self.y: num = random.randint(1, 100) if num < 3: self.direct = 'Up' self.y -= .2 elif plrY == self.y and plrX > self.x: num = random.randint(1, 100) if num < 3: self.direct = 'Right' self.x += .2 elif plrY == self.y and plrX < self.x: num = random.randint(1, 100) if num < 3: self.direct = 'Left' self.x -= .2 elif plrX == self.x and plrY == self.y: num = random.randint(1, 100) if num < 3: self.direct = random.choice(AnyDirect) self.update() def getDamageDealt(self): return self.damageDealt def healthBar(self, num): if not self.dead: pygame.draw.rect(gD, black, (self.rect[0], self.rect[1] - 20, self.rect[2], 10)) pygame.draw.rect(gD, red, (self.rect[0] + 2, self.rect[1] - 18, self.rect[2] - num, 6)) if self.rect[2] - num <= 0: print('It\'s dead') self.dead = True def update(self): self.rect = (self.x, self.y, self.width, self.height) def takeHit(self, weapPos): if weapPos: EnPos = (self.x, self.y, self.x + self.width, self.y + self.height) if weapPos[0] >= EnPos[0] and weapPos[0] <= EnPos[2] and weapPos[1] >= EnPos[1] and weapPos[1] <= EnPos[3]: self.damageDealt += self.damage def getWeapPos(self): if self.weaponPos != None: return self.weaponPos def Pause(): global pause for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_p: pause = True SD.message_display(gD, 'Paused', round(width/10), black, width/2, height/2) while pause: print('Pause = True') for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_p: pause = False def Confirm_QUIT(): global Confirm Confirm = False def Confirm_Screen(username): global Confirm clock.tick(fps) while Confirm: for event in pygame.event.get(): if event.type == pygame.QUIT: End_Game() gD.fill(blue) SD.message_display(gD, 'You\'re %s, correct?' %username, round(width/17), Unique_Color, round(width/2), height * .25) b1 = BT((round(width * .3), round(height * .7), round(width * .4), round(height * .2)), 'Confirm!', round(width/20), blue) b2 = BT((round(width * .75), round(height * .8), round(width * .2), round(height * .1)), "No!", round(width/50), blue) b1.draw(gD, CustomColor1) b2.draw(gD, red) b1.optClick(gD, CustomColor2, CustomColor1, Confirm_QUIT) b2.optClick(gD, darker_red, red, End_Game, pygame.quit) pygame.display.update() clock.tick(15) def SignIn(): global username GD = GameData() listings = GD.getListings() signInList = listings[0] UserArmor = listings[1] UserWeap = listings[2] UserLvl = listings[3] username = input('(Type "new" for new account) Type in username: ') if username == 'new': newUsername = input('Type your Username: ') newPassword = input('Type your Password: ') signInList.update({newUsername : newPassword}) UserArmor.update({newUsername : brown}) UserWeap.update({newUsername : light_brown}) UserLvl.update({newUsername : '1'}) username = newUsername else: if username in signInList: password = input('Please type your password: ') if password == signInList[username]: pass else: print('Invalid Password') time.sleep(2) SignIn() else: print('Invalid Username') time.sleep(2) SignIn() def Main(): global username global pause SignIn() Confirm_Screen(username) GD = GameData() listings = GD.getListings() UserArmor = listings[1] UserWeap = listings[2] armor = UserArmor[username] weap = UserWeap[username] p = Player(width/2, height/2, 50, 50, armor, weap) e = Enemy(0 ,0, 50, 50, brown, WoodBat, 'noob') play = True while play: for event in pygame.event.get(): if event.type == pygame.QUIT: End_Game() if not pause: gD.fill(green) plrPos = p.getPos() eDamage = e.getDamageDealt() pDamage = p.getDamageDealt() t1 = threading.Thread(target=p.draw) t2 = threading.Thread(target=p.move, args=(e,)) t3 = threading.Thread(target=p.healthBar, args=(4 + eDamage,)) t4 = threading.Thread(target=e.draw) t5 = threading.Thread(target=e.move, args=(p,)) t6 = threading.Thread(target=e.healthBar, args=(4 + pDamage,)) t7 = threading.Thread(target=Pause) t1.start() t2.start() t3.start() t4.start() t5.start() t6.start() t7.start() t1.join() t2.join() t3.join() t4.join() t5.join() t6.join() t7.join() pygame.display.update() clock.tick(fps) End_Game() def End_Game(Died=None): play = False GD = GameData() listings = GD.getListings() print(listings[0]) print('') print(listings[1]) print('') print(listings[2]) print('') print(listings[3]) OverPosY = 0 if Died == None: gD.fill(red) pygame.display.update() if Died: while True: OverPosY += 1 gD.fill(red) SD.message_display(gD, 'Game Over', round(width/10), black, round(width/2), OverPosY) pygame.display.update() if OverPosY == height/2: time.sleep(5) pygame.quit() SD.message_display(gD, "Fill in info on console", round(int(width/20)), Unique_Color, width/2, height/2) pygame.display.update() Main() pygame.quit()This is the largest game I've ever made and I'm excited to finish it. If you do things well one at a time, you end up in a really good place. Don't get ahead of yourself. Control the things you can. - Ron Johnson RE: Suggestions/Improvements (pygame) - Windspar - Apr-16-2019 Since you are't catching my drift. Probably my last post. 1. Threading will slow game down. 2. You need one post. When dealing with same code. 3. I have not ran your code. It needs to be redone. 4. You don't follow python style guide. PEP 8 -- Style Guide for Python Code Example has no battle system. This example is a rough draft. Haven't finish pause scene. show button, pygame sprites and groups are used, and more. import pygame import random # Simple Scene Interface class Scene: def draw(self, surface, game): pass def event(self, event, game): pass def update(self, game): pass class Game: def __init__(self, caption, width, height): # Basic pygame setup pygame.display.set_caption(caption) self.rect = pygame.Rect(0, 0, width, height) self.surface = pygame.display.set_mode(self.rect.size) self.clock = pygame.time.Clock() self.running = False self.fps = 30 self.delta = 0 # Scene Interface self.scene = Scene() self.scenes = {} Game.info = self def mainloop(self): self.running = True while self.running: for event in pygame.event.get(): self.scene.event(event, self) self.keys = pygame.key.get_pressed() self.scene.update(self) self.scene.draw(self.surface, self) pygame.display.flip() self.delta = self.clock.tick(self.fps) class Button(pygame.sprite.Sprite): def __init__(self, caption, rect, callback, font, text_color, color, hover_color): pygame.sprite.Sprite.__init__(self) image = font.render(caption, 1, text_color) position = image.get_rect() position.center = rect.center position.x -= rect.x position.y -= rect.y self.normal_image = self.create_image(color, rect.size, image, position) self.hover_image = self.create_image(hover_color, rect.size, image, position) self.callback = callback self.hover = False self.rect = rect def create_image(self, color, size, text_image, position): image = pygame.Surface(size) image.fill(color) image.blit(text_image, position) print("Button position: ", position) return image def update(self): if self.hover: self.image = self.hover_image else: self.image = self.normal_image def on_mousemotion(self, event): self.hover = self.rect.collidepoint(event.pos) def on_mousebuttonup(self, event): if event.button == 1: if self.hover: self.callback(self) class HoverInfo(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.font = pygame.font.Font(None, 18) self.info_image = self.font.render("Info", 1, pygame.Color("white")) self.image = None self.hover = None self.parent = None def update(self): if self.hover is None: if self.image != self.info_image: self.image = self.info_image self.rect = self.image.get_rect() self.rect.centerx = Game.info.rect.centerx self.rect.y = 5 else: if self.image != self.hover: self.image = self.hover self.rect = self.image.get_rect() self.rect.centerx = Game.info.rect.centerx self.rect.y = 5 class Character(pygame.sprite.Sprite): def __init__(self, image, att, hp, weapon, armor): pygame.sprite.Sprite.__init__(self) self.image = image self.rect = self.image.get_rect() self.hp = hp self.att = att if weapon: self.weapon = Weapon.inventory[weapon] else: self.weapon = None if armor: self.armor = Armor.inventory[armor] else: self.armor = None def on_hover(self, event, info): if self.rect.collidepoint(event.pos): if info.parent != self: if self.weapon: weapon = self.weapon.name else: weapon = "none" if self.armor: armor = self.armor.name else: armor = "none" text = "Weapon: {}, Armor: {}, Hp: {}, Att: {}".format( weapon, armor, self.hp, self.att) info.hover = info.font.render(text, 1, pygame.Color("white")) info.parent = self else: if info.parent == self: info.hover = None info.parent = None class CharacterBase: def __init__(self, image, att, hp, weapons, armors): self.image = image self.rect = self.image.get_rect() self.hp = hp self.att = att self.weapons = weapons self.armors = armors def create(self): def grab(items): if isinstance(items, (tuple, list)): return random.choice(items) return items def rnd(group): if isinstance(group, (tuple, list)): return random.randint(group[0], group[1]) return group return Character(self.image, rnd(self.att), rnd(self.hp), grab(self.weapons), grab(self.armors)) class Weapon: inventory = {} def __init__(self, name, damage): self.name = name self.damage = damage Weapon.inventory[name] = self class Armor: inventory = {} def __init__(self, name, defense): self.name = name self.defense = defense Armor.inventory[name] = self class GameScene(Scene): def __init__(self): self.characters = pygame.sprite.Group() self.sprites = pygame.sprite.Group() self.enemies = pygame.sprite.Group() self.buttons = pygame.sprite.Group() self.create_characters() self.hover_info = HoverInfo() self.hover_info.add(self.sprites) for i in range(10): self.add_enemy((60 + 30 * i, 50)) # Buttons font = pygame.font.Font(None, 16) rect = pygame.Rect(20, 100, 150, 30) b = Button("New Player", rect.copy(), self.push_new_player, font, pygame.Color("skyblue"), pygame.Color("slateblue"), pygame.Color("dodgerblue")) b.add(self.sprites, self.buttons) rect.x = 200 b = Button("New Enemies", rect.copy(), self.push_new_enemies, font, pygame.Color("skyblue"), pygame.Color("slateblue"), pygame.Color("dodgerblue")) b.add(self.sprites, self.buttons) def push_new_player(self, button): self.player.kill() self.player = self.playerbase.create() self.player.rect.topleft = 20, 50 self.player.add(self.sprites, self.characters) def push_new_enemies(self, button): for enemy in self.enemies: enemy.kill() for i in range(10): self.add_enemy((60 + 30 * i, 50)) def add_enemy(self, position): key = random.choice(list(self.enemy_list.keys())) e = self.enemy_list[key].create() e.rect.topleft = position e.add(self.sprites, self.characters, self.enemies) def create_characters(self): images = { "human": pygame.Surface((24, 24)), "goblin": pygame.Surface((18, 18)), "orc": pygame.Surface((20, 20)) } images["human"].fill(pygame.Color("dodgerblue")) images["goblin"].fill(pygame.Color("lawngreen")) images["orc"].fill(pygame.Color("seagreen")) self.playerbase = CharacterBase(images["human"], (8, 11), (8, 13), "Sword", "Leather") self.player = self.playerbase.create() self.player.rect.topleft = 20, 50 self.player.add(self.sprites, self.characters) self.enemy_list = { "Goblin": CharacterBase(images["goblin"], (4, 6), (3, 4), ["Dagger", "Darts"], None), "Human": CharacterBase(images["human"], (7, 10), (7, 10), "Sword", None), "Orc": CharacterBase(images["orc"], (5, 7), (4, 7), ["Sword", "Dagger"], None) } def draw(self, surface, game): surface.fill(pygame.Color("Black")) self.sprites.update() self.sprites.draw(surface) def event(self, event, game): if event.type == pygame.QUIT: game.running = False elif event.type == pygame.MOUSEMOTION: for sprite in self.characters: sprite.on_hover(event, self.hover_info) for sprite in self.buttons: sprite.on_mousemotion(event) elif event.type == pygame.MOUSEBUTTONUP: for sprite in self.buttons: sprite.on_mousebuttonup(event) class PauseScene(Scene): def __init__(self): self.pause = None def create_weapons_and_armor(): Weapon("Sword", 4) Weapon("Dagger", 3) Weapon("Darts", 2) Armor("Leather", 5) def main(): create_weapons_and_armor() pygame.init() game = Game("Rpg Example", 400, 300) game.scenes["Game"] = GameScene() game.scenes["Pause"] = PauseScene() game.scene = game.scenes["Game"] game.mainloop() pygame.quit() main() RE: Suggestions/Improvements (pygame) - metulburr - Apr-16-2019 i have mentioned a few suggestions here and here. Since you didnt heed my advice on the numerous pygame updates, you will find out what happens when you make spaghetti code. You can make spaghetti code all you want. The problem arises when other people (us on the forum) need to help you. Its a turn off when trying to help people that refuse to take the advice given. As you can see Windspar doesnt even want to respond anymore. Please read and compare the two code snippets at the bottom of this thread. The first looks like yours. It needs to look more like the second snippet. There are comments in the second code snippet as to why the old is commented out. You can apply this to your own code. I would also read the organization tutorial here. RE: Suggestions/Improvements (pygame) - SheeppOSU - Apr-16-2019 Sorry I'll rewrite everything |