Advertisement
cookertron

Python Pygame - Snake 360

Jun 30th, 2022
1,022
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.20 KB | None | 0 0
  1. import pygame
  2. from pygame import Vector2 as V
  3. from pygame import Rect as R
  4. from pygame.locals import *
  5. from itertools import product
  6. from random import randint
  7. import time
  8.  
  9. SPATIAL_GRID_SIZE = 32
  10.  
  11. class spatial_hash:
  12.     def __init__(s):
  13.         s.grid = {}
  14.  
  15.     def insert(s, rect, entity):
  16.         cells = []
  17.         for cell in s._rect_cells(rect):
  18.             cells.append(cell)
  19.             items = s.grid.get(cell)
  20.             if items is None:
  21.                 s.grid[cell] = [entity]
  22.             else:
  23.                 items.append(entity)
  24.         return cells
  25.  
  26.     def _rect_cells(s, rect):
  27.         x1, y1 = rect.topleft
  28.         x1 //= SPATIAL_GRID_SIZE
  29.         y1 //= SPATIAL_GRID_SIZE
  30.         x2, y2 = rect.bottomright
  31.         x2 = x2 // SPATIAL_GRID_SIZE + 1
  32.         y2 = y2 // SPATIAL_GRID_SIZE + 1
  33.         return product(range(x1, x2), range(y1, y2))
  34.  
  35.     def query(s, rect):
  36.         items = []
  37.         for cell in s._rect_cells(rect):
  38.             items.extend(s.grid.get(cell, ()))
  39.         return items
  40.  
  41. class segment:
  42.     def __init__(s, pos, size, id):
  43.         s.pos = pos
  44.         s.rect = R(s.pos - (size, size), (size * 2, size * 2))
  45.         s.grid_refs = SH.insert(s.rect, s)
  46.         s.id = id
  47.  
  48. class worm:
  49.     INIT_DIRECTION = V(0, -1)
  50.     INIT_LENGTH = 200
  51.     TURNING_SPEED = 3
  52.     GROW_TIME = 1
  53.  
  54.     def __init__(s):
  55.         s.dead = False
  56.  
  57.         s.pos = V(PDR.center) - (0, s.INIT_LENGTH // 2)
  58.         s.dv = V(s.INIT_DIRECTION)
  59.  
  60.         s.id = s.INIT_LENGTH
  61.         s.safe_collision_distance = int(V().distance_to((SEGMENT_SIZE, SEGMENT_SIZE))) + SEGMENT_SIZE + 3
  62.  
  63.         s.body = [segment(s.pos // 1, SEGMENT_SIZE, s.id)]
  64.  
  65.         s.grow_timestamp = None
  66.  
  67.         for y_off in range(1, s.INIT_LENGTH):
  68.             pos = s.body[0].pos + (0, y_off)
  69.             s.body.append(segment(pos, SEGMENT_SIZE, s.id + y_off))
  70.             pygame.draw.circle(PDS, WHITE, pos, SEGMENT_SIZE)
  71.  
  72.     def update(s):
  73.         global FOOD
  74.  
  75.         s.pos += s.dv * TIME_DELTA
  76.  
  77.         if s.pos.x < -SEGMENT_SIZE: s.pos.x = PDR.w + SEGMENT_SIZE
  78.         if s.pos.x > PDR.w + SEGMENT_SIZE: s.pos.x = -SEGMENT_SIZE
  79.         if s.pos.y < -SEGMENT_SIZE: s.pos.y = PDR.h + SEGMENT_SIZE
  80.         if s.pos.y > PDR.h + SEGMENT_SIZE: s.pos.y = -SEGMENT_SIZE
  81.  
  82.         ipos = s.pos // 1
  83.         if ipos != s.body[0].pos:
  84.             s.id += 1
  85.             s.body.insert(0, segment(ipos, SEGMENT_SIZE, s.id))
  86.  
  87.             now = time.perf_counter()
  88.             if s.grow_timestamp == None:
  89.                 tip = s.body.pop()
  90.                 for gr in tip.grid_refs:
  91.                     SH.grid[gr].remove(tip)
  92.                 pygame.draw.circle(PDS, BLACK, tip.pos, SEGMENT_SIZE)                    
  93.                 pygame.draw.circle(PDS, WHITE, s.body[-1].pos, SEGMENT_SIZE)
  94.             else:
  95.                 if now - (now if not s.grow_timestamp else s.grow_timestamp) >= s.GROW_TIME:
  96.                     s.grow_timestamp = None
  97.  
  98.             pygame.draw.circle(PDS, WHITE, ipos, SEGMENT_SIZE)
  99.  
  100.             potention_collision_segments = SH.query(s.body[0].rect)
  101.             for seg in potention_collision_segments:
  102.                 if seg.id <= s.body[0].id - s.safe_collision_distance:
  103.                     if s.body[0].pos.distance_to(seg.pos) <= SEGMENT_SIZE * 2:
  104.                         s.dead = True
  105.            
  106.             if s.body[0].pos.distance_to(FOOD.pos) <= FOOD_SIZE + SEGMENT_SIZE:
  107.                 FOOD.remove_food()
  108.                 FOOD = food()
  109.                 s.grow_timestamp = time.perf_counter()
  110.  
  111.         k = pygame.key.get_pressed()
  112.         if k[K_LEFT]:
  113.             s.dv.rotate_ip(-s.TURNING_SPEED * TIME_DELTA)
  114.         elif k[K_RIGHT]:
  115.             s.dv.rotate_ip(s.TURNING_SPEED * TIME_DELTA)
  116.  
  117. class food:
  118.     def __init__(s):
  119.         while True:
  120.             s.pos = V(randint(FOOD_SIZE, PDR.w - FOOD_SIZE), randint(FOOD_SIZE, PDR.h - FOOD_SIZE))
  121.             rect = R(s.pos - (FOOD_SIZE, FOOD_SIZE), (FOOD_SIZE * 2, FOOD_SIZE * 2))
  122.             space_found = True
  123.             for seg in SH.query(rect):
  124.                 if seg.pos.distance_to(s.pos) <= FOOD_SIZE + SEGMENT_SIZE:
  125.                     space_found = False
  126.                     break
  127.             if space_found:
  128.                 break
  129.         pygame.draw.circle(PDS, BLUE, s.pos, FOOD_SIZE)
  130.    
  131.     def remove_food(s):
  132.         pygame.draw.circle(PDS, BLACK, s.pos, FOOD_SIZE)
  133.  
  134.  
  135.  
  136. BLACK = (64, 64, 64)
  137. WHITE = (255, 255, 255, 255)
  138. RED = (255, 0, 0)
  139. GREEN = (0, 255, 0)
  140. BLUE = (0, 0, 255)
  141.  
  142. PDR = R(0, 0, 640, 480)
  143. FPS = 120
  144.  
  145. pygame.init()
  146. PDS = pygame.display.set_mode(PDR.size, FULLSCREEN | SCALED)
  147. PDS.fill(BLACK)
  148.  
  149. SEGMENT_SIZE = 5
  150. FOOD_SIZE = 10
  151.  
  152. SH = spatial_hash()
  153. WORM = worm()
  154. FOOD = food()
  155.  
  156. delta_timestamp = None
  157. exit_demo = False
  158.  
  159. while not exit_demo:
  160.     now = time.perf_counter()
  161.     TIME_DELTA = (now - (delta_timestamp if delta_timestamp != None else now)) * FPS
  162.     delta_timestamp = now
  163.  
  164.     events = pygame.event.get()
  165.     for event in events:
  166.         if event.type == KEYUP:
  167.             if event.key == K_ESCAPE:
  168.                 exit_demo = True
  169.  
  170.     WORM.update()
  171.     if WORM.dead == True:
  172.         exit_demo = True
  173.  
  174.     pygame.display.update()
  175.  
  176. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement