pygame学习笔记04-贪吃蛇
运行效果:
代码如下:
import collections
import copy
import random
import sys
import time
import pygame
from pygame import locals
class CSnake(object):
#I_WIDTH = 600
#I_HEIGHT = 480
I_WIDTH = 300
I_HEIGHT = 240
I_STEP = 20
I_LINE_WIDTH = 1
F_MOVE_TIME_DELTA_ORG = 0.5
I_MAX_X = I_WIDTH//I_STEP -1
I_MAX_Y = I_HEIGHT//I_STEP -1
T_COLOR_BG = (40, 40, 60) #背景色
T_COLOR_BLACK = (0, 0, 0) #网格线颜色
T_COLOR_DARK = (200, 200, 200) # 蛇颜色
T_COLOR_LIGHT = (150, 150, 150) # 食物颜色
T_COLOR_RED = (255, 0, 0) # 红色
LIST_ORG_FOOD = [12, 8]
LIST_ORG_DIRECTION = [1, 0]
def __init__(self):
self.s_game_state = 'waiting' #waiting, running, over, pause
self.i_score = 0
self.i_level = 0
self.f_move_time_delta = self._gen_move_time_delta()
self.list_snake = self._init_snake()
self.list_food = self._init_food()
self.list_direction = self._init_direction()
self.list_direction_tmp = self._init_direction()
self.o_last_time = time.time()
self.o_surface = pygame.display.set_mode((self.I_WIDTH, self.I_HEIGHT))
self._run()
def _init_snake(self):
_list = list()
_list.append((9, 3))
_list.append((8, 3))
_list.append((7, 3))
_list.append((6, 3))
return _list
def _init_food(self):
_list = list()
_list.extend(self.LIST_ORG_FOOD)
return _list
def _init_direction(self):
_list = list()
_list.extend(self.LIST_ORG_DIRECTION)
return _list
def _gen_new_list_direction_on_move_time(self):
_list = list()
#if new direction is reverse
_i_delta_x = self.list_direction[0] + self.list_direction_tmp[0]
_i_delta_y = self.list_direction[1] + self.list_direction_tmp[1]
if _i_delta_x==0 and _i_delta_y==0:
#reverse direction, not accept
_list = copy.copy(self.list_direction)
else:
#accept new direciton
_list = copy.copy(self.list_direction_tmp)
return _list
def _run(self):
pygame.init()
pygame.display.set_caption(f'Snake, score:{self.i_score}, level:{self.i_level}')
while True:
for event in pygame.event.get():
if event.type == locals.QUIT:
pygame.quit()
sys.exit()
elif event.type == locals.KEYDOWN: #键盘按下
self.list_snake = self._gen_new_list_snake_on_key_down(event.key)
self.list_direction = self._gen_new_list_direction_on_key_down(event.key)
self.list_direction_tmp = self._gen_new_list_direction_tmp_on_key_down(event.key)
self.s_game_state = self._gen_new_game_state_on_key_down(event.key)
else:
pass
self._update_window()
_o_curr_time = time.time()
if self.s_game_state=='running' and _o_curr_time - self.o_last_time >= self.f_move_time_delta:
self.o_last_time = _o_curr_time
self.list_direction = self._gen_new_list_direction_on_move_time()
#self.list_snake = self._gen_new_list_snake_on_move_time()
self._update_snake_and_food()
self._update_window()
else:
pass
def _draw_nets(self):
#画横网格线
for y in range(self.I_STEP, self.I_HEIGHT, self.I_STEP):
pygame.draw.line(self.o_surface, self.T_COLOR_BLACK, (0, y), (self.I_WIDTH, y), self.I_LINE_WIDTH)
#画竖网格线
for x in range(self.I_STEP, self.I_WIDTH, self.I_STEP):
pygame.draw.line(self.o_surface, self.T_COLOR_BLACK, (x, 0), (x, self.I_HEIGHT), self.I_LINE_WIDTH)
def _draw_snake(self):
for i, _t_cell in enumerate(self.list_snake):
x0 = _t_cell[0]*self.I_STEP + self.I_LINE_WIDTH
y0 = _t_cell[1]*self.I_STEP + self.I_LINE_WIDTH
x1 = self.I_STEP - self.I_LINE_WIDTH
y1 = self.I_STEP - self.I_LINE_WIDTH
_t_color = self.T_COLOR_RED if i==0 else self.T_COLOR_DARK
pygame.draw.rect(
self.o_surface,
_t_color,
(x0, y0, x1, y1),
0,
)
def _draw_food(self):
x0 = self.list_food[0]*self.I_STEP
y0 = self.list_food[1]*self.I_STEP
x1 = self.I_STEP
y1 = self.I_STEP
pygame.draw.rect(
self.o_surface,
self.T_COLOR_LIGHT,
(x0, y0, x1, y1),
0,
)
def _update_snake_and_food(self):
#time.sleep(1)
_t_cell_next = (
self.list_snake[0][0]+self.list_direction[0],
self.list_snake[0][1]+self.list_direction[1],
)
_b_hit_snake = self._is_hit_snake(_t_cell_next)
_b_hit_edge = self._is_hit_edge(_t_cell_next)
_b_eat_food = self._is_eat_food(_t_cell_next)
if _b_hit_snake or _b_hit_edge:
self.s_game_state = 'over'
elif _b_eat_food:
self.list_snake.insert(0, _t_cell_next)
self.list_food = self._gen_new_food()
self.i_score += 1
self.i_level = self.i_score//10
self.i_level = self.i_score//2
self.f_move_time_delta = self._gen_move_time_delta()
pygame.display.set_caption(f'Snake, score:{self.i_score}, level:{self.i_level}')
else:
self.list_snake.insert(0, _t_cell_next)
self.list_snake.pop()
pass
def _gen_new_list_snake_on_move_time(self):
_list = copy.copy(self.list_snake)
_t_cell_next = (
_list[0][0]+self.list_direction[0],
_list[0][1]+self.list_direction[1],
)
_b_hit_snake = self._is_hit_snake(_t_cell_next)
_b_hit_edge = self._is_hit_edge(_t_cell_next)
_b_eat_food = self._is_eat_food(_t_cell_next)
if _b_hit_snake or _b_hit_edge:
pass
elif _b_eat_food:
print('eat food, snake grow big')
_list.insert(0, _t_cell_next)
else:
_list.insert(0, _t_cell_next)
_list.pop()
return _list
def _gen_new_food(self):
_list_for_random = list()
for i in range(0, self.I_MAX_X+1):
for j in range(0, self.I_MAX_Y+1):
if (i, j) not in self.list_snake:
_list_for_random.append((i, j))
_t_food_next = random.choice(_list_for_random)
return _t_food_next
def _update_window(self):
self.o_surface.fill(self.T_COLOR_BG)
self._draw_nets()
self._draw_snake()
self._draw_food()
if self.s_game_state == 'waiting':
self._display_info('Press Enter to Start')
elif self.s_game_state == 'over':
self._display_info('GAME OVER\nPress Enter to Start')
else:
pass
pygame.display.flip()
def _is_eat_food(self, t_cell_next):
_b = False
print(f'{t_cell_next} {self.list_food}')
if t_cell_next[0]==self.list_food[0] and t_cell_next[1]==self.list_food[1]:
_b = True
return _b
def _is_hit_snake(self, t_cell_next):
_b = False
if t_cell_next in self.list_snake:
_b = True
return _b
def _is_hit_edge(self, t_cell_next):
_b = False
_b_hit_x = t_cell_next[0] not in range(0, self.I_MAX_X+1)
_b_hit_y = t_cell_next[1] not in range(0, self.I_MAX_Y+1)
#print(f'{t_cell_next}, {_b_hit_x}, {_b_hit_y}')
if _b_hit_x or _b_hit_y:
_b = True
return _b
def _gen_move_time_delta(self):
return self.F_MOVE_TIME_DELTA_ORG * pow(0.9, self.i_level)
def _display_info(self, s_info):
basicFont = pygame.font.SysFont('arial', 40)
text = basicFont.render(s_info, True, (255, 255, 0), (0, 0, 255))
textRect = text.get_rect()
textRect.centerx = self.o_surface.get_rect().centerx
textRect.centery = self.o_surface.get_rect().centery
#textRect.center = (200, 200) #设置显示对象居中
self.o_surface.blit(text, textRect)
def _gen_new_list_snake_on_key_down(self, event_key):
_list = list()
if event_key == locals.K_RETURN and self.s_game_state in ['waiting', 'over']:
_list = self._init_snake()
else:
_list = copy.copy(self.list_snake)
return _list
def _gen_new_list_direction_on_key_down(self, event_key):
_list = list()
if event_key == locals.K_RETURN and self.s_game_state in ['waiting', 'over']:
_list = self._init_direction()
else:
_list = copy.copy(self.list_direction)
return _list
def _gen_new_list_direction_tmp_on_key_down(self, event_key):
_list = list()
if event_key in (locals.K_w, locals.K_UP): # w键, 向上键
_list = [0, -1]
elif event_key in (locals.K_s, locals.K_DOWN): # s键, 向下键
_list = [0, 1]
elif event_key in (locals.K_a, locals.K_LEFT): # a键, 向左键
_list = [-1, 0]
elif event_key in (locals.K_d, locals.K_RIGHT): # d键, 向右键
_list = [1, 0]
else:
_list = copy.copy(self.list_direction_tmp)
return _list
def _gen_new_game_state_on_key_down(self, event_key):
_s_game_state_new = self.s_game_state
if event_key == locals.K_RETURN: # Enter键
if self.s_game_state in ['waiting', 'over']:
_s_game_state_new = 'running'
elif event_key == locals.K_SPACE:
if self.s_game_state == 'over' : _s_game_state_new = 'over'
elif self.s_game_state == 'waiting': _s_game_state_new = 'waiting'
elif self.s_game_state == 'running': _s_game_state_new = 'pause'
elif self.s_game_state == 'pause' : _s_game_state_new = 'running'
else : _s_game_state_new = 'pause'
else:
pass
return _s_game_state_new
if __name__ == '__main__':
o_snake = CSnake()