Last active
June 18, 2020 14:44
-
-
Save MichaelStett/62d68d8cab4e55e110621f22e8db208d to your computer and use it in GitHub Desktop.
Snake in Python
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
{ | |
"title": "Snake by Michal Tymejczyk", | |
"screen": { | |
"resolution": [ | |
1280, | |
720 | |
], | |
"font": null | |
}, | |
"collisions": { | |
"snake": true, | |
"apple": true, | |
"border": false | |
}, | |
"colors": { | |
"snake": [ | |
255, | |
0, | |
0 | |
], | |
"apple": [ | |
0, | |
255, | |
0 | |
], | |
"background": [ | |
255, | |
255, | |
255 | |
] | |
}, | |
"length": 5, | |
"speed": 15, | |
"size": 25, | |
"lag": 1 | |
} |
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
# Based on https://www.pygame.org/project-Snake+in+35+lines-818-.html | |
import json | |
import random | |
import sys | |
import dotmap | |
from dotmap import DotMap | |
import pygame | |
from pygame.locals import * | |
from enum import Enum | |
class Direction(Enum): | |
DOWN = 0 | |
RIGHT = 1 | |
UP = 2 | |
LEFT = 3 | |
class Game(): | |
class Apple(): | |
__color = (0, 0, 0) | |
__size = 0 | |
coords = [0, 0] | |
def __init__(self, color, size, border): | |
self.__color = color | |
self.__size = size | |
self.__limit = border | |
self.surface = pygame.Surface([self.__size] * 2) | |
self.surface.fill(self.__color) | |
self.newPosition() | |
def newPosition(self): | |
self.coords[0] = random.randint(0, self.__limit[0] - self.__size * 4) | |
self.coords[1] = random.randint(0, self.__limit[1] - self.__size * 4) | |
# -- class Apple -- | |
class Snake(): | |
# private | |
__length = 0 | |
__color = (0, 0, 0) | |
__size = 0 | |
__x = [] | |
__y = [] | |
# public | |
direction = Direction.DOWN | |
def __init__(self, length, color, size, resolution): | |
self.__length = length | |
self.__color = color | |
self.__size = size | |
# resolution so snake is centered | |
self.__x = [resolution[0] * 0.5] * length | |
for i in range(self.__length): | |
self.__y.append(resolution[1] * 0.5 - self.__size * i) | |
self.surface = pygame.Surface([self.__size] * 2) | |
self.surface.fill(self.__color) | |
def length(self): | |
return self.__length | |
def coords(self, i): | |
return (self.__x[i], self.__y[i]) | |
def updatePosition(self): | |
if self.direction == Direction.DOWN: self.update('y', 0, self.__size); return | |
if self.direction == Direction.RIGHT: self.update('x', 0, self.__size); return | |
if self.direction == Direction.UP: self.update('y', 0, -self.__size); return | |
if self.direction == Direction.LEFT: self.update('x', 0, -self.__size); return | |
def update(self, coord, index, val, byORto = True): | |
if byORto == True: | |
if coord == 'x': self.__x[index] += val; return | |
if coord == 'y': self.__y[index] += val; return | |
else: # TO VALUE | |
if coord == 'x': self.__x[index] = val; return | |
if coord == 'y': self.__y[index] = val; return | |
print(f"Updated: {coord}[{index}]: {val}") | |
def move(self): | |
for i in range(self.length() - 1, 0, -1): | |
self.update('x', i, self.coords(i - 1)[0], False) | |
self.update('y', i, self.coords(i - 1)[1], False) | |
self.updatePosition() | |
def enlarge(self): | |
self.__x.append(0) | |
self.__y.append(0) | |
self.__length += 1 | |
def isInCollisionWith(self, obj, isBorder = False): | |
if isBorder is not True: | |
return (self.__x[0] + self.__size > obj.x and | |
self.__y[0] + self.__size > obj.y and | |
self.__x[0] - self.__size < obj.x and | |
self.__y[0] - self.__size < obj.y) | |
else: | |
return (self.__x[0] + self.__size > obj.x or | |
self.__y[0] + self.__size > obj.y or | |
self.__x[0] - self.__size < 0 or | |
self.__y[0] - self.__size < 0) | |
# -- class Snake -- | |
def __init__(self): | |
self.loadSettings() | |
self.border = DotMap({ | |
"x": self.settings.screen.resolution[0], | |
"y": self.settings.screen.resolution[1] | |
}) | |
self.snake = self.Snake(self.settings.length, | |
self.settings.colors.snake, | |
self.settings.size, | |
self.settings.screen.resolution) | |
self.apple = self.Apple(self.settings.colors.apple, | |
self.settings.size, | |
self.settings.screen.resolution) | |
pygame.init() | |
pygame.display.set_caption(self.settings.title) | |
self.screen = pygame.display.set_mode(self.settings.screen.resolution) | |
self.font = pygame.font.Font(self.settings.screen.font, 40) | |
self.axis = DotMap({ | |
"surface": self.font.render(f"{self.snake.coords(0)}", False, pygame.Color("black")), | |
"coords": (self.settings.screen.resolution[0] * 0.05, self.settings.screen.resolution[1] * 0.9) | |
}) | |
self.play() | |
def loadSettings(self, filename = 'settings.json'): | |
with open(filename, 'r') as file: | |
data = json.load(file) | |
self.settings = DotMap(data) | |
# TODO: def reset(self): pass | |
def handle(self, event): | |
if event.key is K_a: | |
if self.snake.direction == Direction.DOWN: self.snake.direction = Direction.RIGHT; return | |
if self.snake.direction == Direction.RIGHT: self.snake.direction = Direction.UP; return | |
if self.snake.direction == Direction.UP: self.snake.direction = Direction.LEFT; return | |
if self.snake.direction == Direction.LEFT: self.snake.direction = Direction.DOWN; return | |
elif event.key is K_d: | |
if self.snake.direction == Direction.DOWN: self.snake.direction = Direction.LEFT; return | |
if self.snake.direction == Direction.RIGHT: self.snake.direction = Direction.DOWN; return | |
if self.snake.direction == Direction.UP: self.snake.direction = Direction.RIGHT; return | |
if self.snake.direction == Direction.LEFT: self.snake.direction = Direction.UP; return | |
elif event.key is K_ESCAPE: | |
sys.exit(0) | |
def rerender(self): | |
self.screen.fill(self.settings.colors.background) | |
self.draw(self.snake) | |
self.render(self.apple) | |
self.axis.surface = self.font.render(f"{self.snake.coords(0)}", False, pygame.Color("black")) | |
self.render(self.axis) | |
def render(self, obj): # used to render single object | |
self.screen.blit(obj.surface, obj.coords) | |
def draw(self, obj): # used to render multiple objects | |
for i in range(obj.length()): | |
self.render(DotMap({ | |
"surface": obj.surface, | |
"coords": obj.coords(i) | |
})) | |
def play(self): | |
while True: | |
self.rerender() | |
pygame.time.Clock().tick(self.settings.speed) | |
for event in pygame.event.get(): | |
if event.type == KEYDOWN: | |
self.handle(event) | |
if self.settings.collisions.snake is True: | |
for i in range(self.snake.length() - 1, 0, -1): | |
if self.snake.isInCollisionWith(DotMap({"x": self.snake.coords(i)[0], "y": self.snake.coords(i)[1]})): | |
sys.exit(1) | |
# collisions with apple | |
# if self.settings.collisions.apple == True and self.snake.isInCollisionWith(self.apple): | |
if self.settings.collisions.apple is True: | |
if self.snake.isInCollisionWith(DotMap({"x": self.apple.coords[0], "y": self.apple.coords[1]})): | |
self.snake.enlarge() | |
self.apple.newPosition() | |
if self.settings.collisions.border is True and self.snake.isInCollisionWith(self.border, isBorder=True) is True: | |
sys.exit(1) | |
self.snake.move() | |
pygame.display.update() | |
pygame.time.wait(self.settings.lag) | |
# -- class Game -- | |
Game() |
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
# Based on https://www.pygame.org/project-Snake+in+35+lines-818-.html | |
import json | |
import random | |
import sys | |
from abc import ABC | |
import pygame | |
from pygame.locals import * | |
from dotmap import DotMap | |
Settings = DotMap(json.loads('settings.json')); | |
class Element(ABC): | |
size = 0 | |
def __init__(self, size, color): | |
self.size = size | |
pygame.Surface((size, size)).fill(color) | |
class Apple(Element): | |
def __init__(self, size, color): | |
super().__init__(size, color) | |
def NewPosition(self): | |
self.x = random.randint(0, Settings["screenSize"][0] - self.size * 4) | |
self.y = random.randint(0, Settings["screenSize"][1] - self.size * 4) | |
class Snake(Element): | |
def __init__(self, size, color): | |
super().__init__(size, color) | |
# local method variables | |
width = Settings["screenSize"][0] | |
height = Settings["screenSize"][1] | |
self.x = [width / 2] * 5 | |
self.y = [height / 2 - size * 0, | |
height / 2 - size * 1, | |
height / 2 - size * 2, | |
height / 2 - size * 3, | |
height / 2 - size * 4] | |
self.direction = 0 | |
class Game: | |
# Init snake and apple | |
snake = Snake(15, Settings["color"]["snake"]) | |
apple = Apple(15, Settings["color"]["apple"]) | |
score = 0 | |
i = 0 | |
def __init__(self): | |
pygame.init() | |
pygame.display.set_caption() | |
self.screen = pygame.display.set_mode((Settings["screenSize"][0], Settings["screenSize"][1])) | |
def collide(self, x1, x2, y1, y2, _x): | |
return x1 + _x > x2 and x1 < x2 + _x and y1 + _x > y2 and y1 < y2 + _x | |
def Play(self): | |
while True: | |
pygame.time.Clock().tick(speed) | |
for event in pygame.event.get(): | |
if event.type == KEYDOWN: | |
if event.key == K_LEFT or event.key == K_a: | |
if dirs == 0: | |
dirs = 1 | |
elif dirs == 1: | |
dirs = 2 | |
elif dirs == 2: | |
dirs = 3 | |
elif dirs == 3: | |
dirs = 0 | |
elif event.key == K_RIGHT or event.key == K_d: | |
if dirs == 0: | |
dirs = 3 | |
elif dirs == 1: | |
dirs = 0 | |
elif dirs == 2: | |
dirs = 1 | |
elif dirs == 3: | |
dirs = 2 | |
elif event.key == K_ESCAPE: | |
sys.exit(0) | |
elif event.key == K_SPACE: | |
dirs = 4 | |
i = len(snake.x) - 1 | |
if Collisions["snake"]: | |
while i >= 2: | |
if collide(snake.x[0], snake.x[i], snake.y[0], snake.y[i], Element.Size): | |
Restart() | |
i -= 1 | |
if Collisions["apple"]: | |
if collide(snake.x[0], apple.x, snake.y[0], apple.y, Element.Size): | |
score += 1 | |
snake.x.append(700) | |
snake.y.append(700) | |
apple.NewPosition() | |
i = len(snake.x) - 1 | |
while i >= 1: | |
snake.x[i] = snake.x[i - 1] | |
snake.y[i] = snake.y[i - 1] | |
i -= 1 | |
if Collisions["border"]: | |
if snake.x[0] < Element.Size or snake.x[0] > ScreenSize[0] - Element.Size or snake.y[0] < Element.Size or snake.y[0] > ScreenSize[1] - Element.Size: | |
Restart() | |
if snake.direction == 0: | |
snake.y[0] += Element.Size | |
elif snake.direction == 1: | |
snake.x[0] += Element.Size | |
elif snake.direction == 2: | |
snake.y[0] -= Element.Size | |
elif snake.direction == 3: | |
snake.x[0] -= Element.Size | |
elif snake.direction == 4: | |
pygame.time.wait() | |
screen.fill() | |
for i in range(0, len(snake.x)): | |
screen.blit(snake.surface, (snake.x[i], snake.y[i])) | |
screen.blit(apple.surface, (apple.x, apple.y)) | |
Render(Renders["score"], (ScreenSize[0] / 2, 10)) | |
Render(Renders["possition"], (ScreenSize[0] * 0.05, ScreenSize[1] * 0.9)) | |
pygame.display.update() | |
def Restart(): | |
Render("Your score was: " + Renders["score"], | |
(ScreenSize[0] / 3, ScreenSize[1] / 2)) | |
Render(Renders["restart"], (ScreenSize[0] / 3, ScreenSize[1] / 3)) | |
pygame.display.update() | |
while True: | |
for event in pygame.event.get(): | |
if event.type == KEYDOWN: | |
if event.key == K_SPACE: | |
main() | |
elif event.key == K_ESCAPE: | |
sys.exit(0) | |
def Render(string, position): | |
screen.blit( | |
pygame.font.SysFont(Font, Element.Size * 1.5, True).render(string, False, (0, 0, 0)), position) | |
def main(): | |
Game() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment