Dec-16-2017, 03:04 AM
I would have summit this in tutorial request and submission. There is no post thread there.
First thing. Build a boiler plate. Opens a pygame screen.
It a good thing to store values in variables for later use.
Let give the snake some food to gather.
Let give the snake random start direction.
Have to have snake_head to avoid fast keys down changes.
Create a snake surface over color.
1. Rewrite this game using classes. Basic function are still aloud.
2. Make the snake grow by 2 or 3 per food.
3. Make another stage. Have it change to next stage after snake gets so big.
First thing. Build a boiler plate. Opens a pygame screen.
# Step 1. Let start out with the basic boiler plate. import os import pygame # global Container class Game: pass def main(): # Center screen os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() pygame.display.set_caption("Nibbles Tutorial") Game.screen = pygame.display.set_mode((720,420)) Game.running = True clock = pygame.time.Clock() # Mainloop while Game.running: for event in pygame.event.get(): if event.type == pygame.QUIT: Game.running = False Game.screen.fill((0,10,0)) pygame.display.flip() clock.tick(30) pygame.quit() if __name__ == '__main__': main()Next draw a snake and basic screen rect.
It a good thing to store values in variables for later use.
# Step 2. Draw the snake import os import pygame # global Container class Game: pass def main(): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() pygame.display.set_caption("Nibbles Tutorial") # Let define block size. Game.block_size = 12 # Set blocks width Game.width = 72 width = Game.block_size * Game.width # Set blocks height Game.height = 42 height = Game.block_size * Game.height # Rect to keep are snake within Game.rect = pygame.Rect(0,0,width,height) Game.screen = pygame.display.set_mode(Game.rect.size) Game.running = True Game.snake_color = pygame.Color('lawngreen') size = Game.block_size x = Game.width / 2 * size y = Game.height / 2 * size # Build the snake body Game.snake = [(x, y), (x, y + size), (x, y + size * 2)] clock = pygame.time.Clock() # Mainloop while Game.running: for event in pygame.event.get(): if event.type == pygame.QUIT: Game.running = False Game.screen.fill((0,10,0)) # Draw the snake for body in Game.snake: rect = pygame.Rect(body[0], body[1], Game.block_size, Game.block_size) Game.screen.fill(Game.snake_color, rect) pygame.display.flip() clock.tick(30) pygame.quit() if __name__ == '__main__': main()Now get the snake moving and colliding with border.
# Step 3. Make the snake move import os import pygame # Global Container class Game: pass def add_tuples(lhs, rhs): return lhs[0] + rhs[0], lhs[1] + rhs[1] def keys_down(): # let get the keypressed states keypress = pygame.key.get_pressed() # press left arrow key and it not moving right if keypress[pygame.K_LEFT] and Game.snake_direction[0] != Game.block_size: # set snake direction to left Game.snake_direction = -Game.block_size, 0 # (-10, 0) (right or left, up or down) # press right arrow key and it not moving left elif keypress[pygame.K_RIGHT] and Game.snake_direction[0] != -Game.block_size: # set snake direction to right Game.snake_direction = Game.block_size, 0 # press up arrow key and it not moving down elif keypress[pygame.K_UP] and Game.snake_direction[1] != Game.block_size: # set snake direction to up Game.snake_direction = 0, -Game.block_size # press down arrow key and it not moving up elif keypress[pygame.K_DOWN] and Game.snake_direction[1] != -Game.block_size: # set snake direction to down Game.snake_direction = 0, Game.block_size def snake_move(): # Move the snake head = add_tuples(Game.snake[0], Game.snake_direction) # Add head and drop tail. Simulate forward motion Game.snake = [head] + Game.snake[:-1] # snake collide with outside wall if not Game.rect.collidepoint(head): new_game() # Move snake here for quick restart def new_game(): size = Game.block_size # Give snake a direction Game.snake_direction = 0, -size # up x = Game.width / 2 * size y = Game.height / 2 * size Game.snake = [ (x, y), (x, y + size), (x, y + size * 2) def main(): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() pygame.display.set_caption("Nibbles Tutorial") Game.block_size = 12 Game.width = 72 width = Game.block_size * Game.width Game.height = 42 height = Game.block_size * Game.height Game.rect = pygame.Rect(0,0,width,height) Game.screen = pygame.display.set_mode(Game.rect.size) Game.running = True Game.snake_color = pygame.Color('lawngreen') new_game() clock = pygame.time.Clock() # Mainloop while Game.running: for event in pygame.event.get(): if event.type == pygame.QUIT: Game.running = False # See if key is pressed keys_down() # Move every loop snake_move() Game.screen.fill((0,10,0)) # Draw the snake for body in Game.snake: rect = pygame.Rect(body[0], body[1], Game.block_size, Game.block_size) Game.screen.fill(Game.snake_color, rect) pygame.display.flip() # reduce framerate for movement clock.tick(10) pygame.quit() if __name__ == '__main__': main()Okay now let not use framerate to control speed.
Let give the snake some food to gather.
Let give the snake random start direction.
Have to have snake_head to avoid fast keys down changes.
# Step 4. Food, better snake movement timing, and random start direction import os import pygame from random import choice, randrange # Global Container class Game: pass def add_tuples(lhs, rhs): return lhs[0] + rhs[0], lhs[1] + rhs[1] def sub_tuples(lhs, rhs): return lhs[0] - rhs[0], lhs[1] - rhs[1] def keys_down(): # let get the keypressed states keypress = pygame.key.get_pressed() if keypress[pygame.K_LEFT] and Game.snake_head[0] != Game.block_size: Game.snake_direction = -Game.block_size, 0 # (-10, 0) (right or left, up or down) elif keypress[pygame.K_RIGHT] and Game.snake_head[0] != -Game.block_size: Game.snake_direction = Game.block_size, 0 elif keypress[pygame.K_UP] and Game.snake_head[1] != Game.block_size: Game.snake_direction = 0, -Game.block_size elif keypress[pygame.K_DOWN] and Game.snake_head[1] != -Game.block_size: Game.snake_direction = 0, Game.block_size def snake_move(): # Assign snake_head to snake_direction here Game.snake_head = Game.snake_direction # Move the snake head = add_tuples(Game.snake[0], Game.snake_direction) if not Game.rect.collidepoint(head): new_game() # Snake body collision elif head in Game.snake: new_game() # Food collision elif head == Game.food: Game.snake = [head] + Game.snake # Make snake move faster Game.movement_timer['length'] -= 2 # make more food create_food() else: Game.snake = [head] + Game.snake[:-1] def create_food(): Game.food = None # Let make sure food doesn't collide with snake while Game.food is None: x = randrange(1, Game.width, 1) * Game.block_size y = randrange(1, Game.height, 1) * Game.block_size Game.food = (x, y) if Game.food in Game.snake: Game.food = None size = Game.block_size - 2 Game.food_rect = (x + 1, y + 1, size, size) def new_game(): size = Game.block_size # random start direction Game.snake_direction = choice(((0, -size), (0, size), (-size, 0), (size, 0))) d = Game.snake_direction x = Game.width / 2 * size y = Game.height / 2 * size # Give snake a head to avoid opposite collision Game.snake_head = Game.snake_direction # Build snake body according to direction. Game.snake = [(x, y), sub_tuples((x, y), d), sub_tuples(sub_tuples((x,y), d), d)] # Make a Tick Timer, Ticks are in milliseconds. Game.movement_timer = {'length': 120, 'next tick': pygame.time.get_ticks()} # New food spot on every new game create_food() def timer_elasped(timer, ticks): if ticks > timer['next tick'] + timer['length']: timer['next tick'] += timer['length'] return True return False def main(): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() pygame.display.set_caption("Nibbles Tutorial") Game.block_size = 12 Game.width = 72 width = Game.block_size * Game.width Game.height = 42 height = Game.block_size * Game.height Game.rect = pygame.Rect(0,0,width,height) Game.screen = pygame.display.set_mode(Game.rect.size) Game.running = True Game.snake_color = pygame.Color('lawngreen') Game.food_color = pygame.Color('yellow') new_game() clock = pygame.time.Clock() # Mainloop while Game.running: for event in pygame.event.get(): if event.type == pygame.QUIT: Game.running = False keys_down() # Get pygame ticks ticks = pygame.time.get_ticks() # Only move snake if timer elasped if timer_elasped(Game.movement_timer, ticks): snake_move() Game.screen.fill((0,10,0)) # Draw food Game.screen.fill(Game.food_color, Game.food_rect) # Draw the snake for body in Game.snake: rect = pygame.Rect(body[0], body[1], Game.block_size, Game.block_size) Game.screen.fill(Game.snake_color, rect) pygame.display.flip() clock.tick(60) pygame.quit() if __name__ == '__main__': main()Final let create a stage. Walls for the snake to avoid.
Create a snake surface over color.
# Step 5. Walls and better looking snake import os import pygame from random import choice, randrange # Global Container class Game: pass def add_tuples(lhs, rhs): return lhs[0] + rhs[0], lhs[1] + rhs[1] def sub_tuples(lhs, rhs): return lhs[0] - rhs[0], lhs[1] - rhs[1] def keys_down(): # let get the keypressed states keypress = pygame.key.get_pressed() if keypress[pygame.K_LEFT] and Game.snake_head[0] != Game.block_size: Game.snake_direction = -Game.block_size, 0 # (-10, 0) (right or left, up or down) elif keypress[pygame.K_RIGHT] and Game.snake_head[0] != -Game.block_size: Game.snake_direction = Game.block_size, 0 elif keypress[pygame.K_UP] and Game.snake_head[1] != Game.block_size: Game.snake_direction = 0, -Game.block_size elif keypress[pygame.K_DOWN] and Game.snake_head[1] != -Game.block_size: Game.snake_direction = 0, Game.block_size def snake_move(): # Assign snake_head to snake_direction here Game.snake_head = Game.snake_direction # Move the snake head = add_tuples(Game.snake[0], Game.snake_direction) if not Game.rect.collidepoint(head): new_game() # Snake body collision elif head in Game.snake or head in Game.walls: new_game() # Food collision elif head == Game.food: Game.snake = [head] + Game.snake # Make snake move faster Game.movement_timer['length'] -= 2 # make more food create_food() else: Game.snake = [head] + Game.snake[:-1] def create_food(): Game.food = None # Let make sure food doesn't collide with snake while Game.food is None: x = randrange(1, Game.width, 1) * Game.block_size y = randrange(1, Game.height, 1) * Game.block_size Game.food = (x, y) # Don't have food spawn in walls if Game.food in Game.snake or Game.food in Game.walls: Game.food = None size = Game.block_size - 2 Game.food_rect = (x + 1, y + 1, size, size) def new_game(): # First Stage create_stage1() size = Game.block_size # random start direction Game.snake_direction = choice(((0, -size), (0, size), (-size, 0), (size, 0))) d = Game.snake_direction x = Game.width / 2 * size y = Game.height / 2 * size # Give snake a head to avoid opposite collision Game.snake_head = Game.snake_direction # Build snake body according to direction. Game.snake = [(x, y), sub_tuples((x, y), d), sub_tuples(sub_tuples((x,y), d), d)] # Make a Tick Timer, Ticks are in milliseconds. Game.movement_timer = {'length': 120, 'next tick': pygame.time.get_ticks()} # New food spot on every new game create_food() def timer_elasped(timer, ticks): if ticks > timer['next tick'] + timer['length']: timer['next tick'] += timer['length'] return True return False def create_snake(): surface = pygame.Surface((Game.block_size, Game.block_size)) surface.fill(pygame.Color('lawngreen')) size = Game.block_size mid = int(Game.block_size / 2) color = pygame.Color('forestgreen') for i in [1,2,3]: j = i * 2 pygame.draw.line(surface, color, (mid - i, j), (mid - i, size - j)) pygame.draw.line(surface, color, (mid + i, j), (mid + i, size - j)) pygame.draw.line(surface, color, (j, mid - i), (size - j, mid - i)) pygame.draw.line(surface, color, (j, mid + i), (size - j, mid + i)) return surface def create_stage1(): # Classic first stage Game.walls = [] for y in range(7, Game.height - 7): Game.walls.append((12 * Game.block_size, y * Game.block_size)) Game.walls.append(((Game.width - 12) * Game.block_size, y * Game.block_size)) def main(): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() pygame.display.set_caption("Nibbles Tutorial") Game.block_size = 12 Game.width = 72 width = Game.block_size * Game.width Game.height = 42 height = Game.block_size * Game.height Game.rect = pygame.Rect(0,0,width,height) Game.screen = pygame.display.set_mode(Game.rect.size) Game.running = True Game.snake_body = create_snake() Game.food_color = pygame.Color('yellow') new_game() clock = pygame.time.Clock() # Mainloop while Game.running: for event in pygame.event.get(): if event.type == pygame.QUIT: Game.running = False keys_down() # Get pygame ticks ticks = pygame.time.get_ticks() # Only move snake if timer elasped if timer_elasped(Game.movement_timer, ticks): snake_move() Game.screen.fill((0,10,0)) # Draw food Game.screen.fill(Game.food_color, Game.food_rect) # Draw walls for wall in Game.walls: rect = pygame.Rect(wall[0], wall[1], Game.block_size, Game.block_size) Game.screen.fill(pygame.Color('gray30'), rect) # Draw the snake for body in Game.snake: rect = pygame.Rect(body[0], body[1], Game.block_size, Game.block_size) #Game.screen.fill(Game.snake_color, rect) Game.screen.blit(Game.snake_body, rect) pygame.display.flip() clock.tick(60) pygame.quit() if __name__ == '__main__': main()Challenges.
1. Rewrite this game using classes. Basic function are still aloud.
2. Make the snake grow by 2 or 3 per food.
3. Make another stage. Have it change to next stage after snake gets so big.