前面写过一个单人贪吃蛇游戏,作为拓展,我用Python3.7写了一个可以多人一起玩的贪吃蛇大作战,限定游戏时间为60s,根据最后得分进行排名。
from tkinter import *
import random
import asyncio
import time
root = Tk()
win = Canvas(root, width=500, height=500)
win.create_rectangle(10, 10, 400, 400, fill="white")
class Snake: #定义蛇类
num=0
def __new__(cls, *args, **kwargs):
cls.num+=1
return super(cls,Snake).__new__(cls)
def __init__(self,color):
self.color = color
self.id = self.num
self.x_v = 15
self.y_v = 0
self.handx = 55 #记录蛇头位置
self.handy = 25
self.coords = [
(10,25),(25,25),(40,25),(55,25) #蛇每一节的位置
]
self.sel = [ #在画布上创建蛇
win.create_rectangle(11,26,24,39,fill=color),
win.create_rectangle(26,26,39,39,fill=color),
win.create_rectangle(41,26,54,39,fill=color),
win.create_rectangle(56,26,69,39,fill=color),
]
def __contains__(self, item):
return item in self.coords
def __getitem__(self, item):
return self.coords[item]
def __delitem__(self, key):
del self.coords[key]
def move(self): #蛇的移动,通过去尾加头实现
del self[0]
self.coords.append((self.handx+self.x_v,self.handy+self.y_v))
win.delete(self.sel[0])
new = win.create_rectangle(
self.handx+self.x_v+1,
self.handy+self.y_v+1,self.handx+self.x_v+14,
self.handy+self.y_v+14,
fill = self.color
)
del self.sel[0]
self.sel.append(new)
self.handx += self.x_v
self.handy += self.y_v
def right(self,event): #蛇的转向,通过速度正交变换实现
self.x_v,self.y_v = -self.y_v,self.x_v
def left(self,event):
self.x_v, self.y_v = self.y_v, -self.x_v
def eat(self,food): #蛇的生长,通过加头不去尾实现
self.coords.append((self.handx+self.x_v,self.handy+self.y_v))
new = win.create_rectangle(
self.handx + self.x_v+1,
self.handy + self.y_v+1, self.handx + self.x_v + 14,
self.handy + self.y_v + 14,
fill = self.color
)
self.sel.append(new)
self.handx += self.x_v
self.handy += self.y_v
win.delete(food)
def die(self):
[win.delete(item) for item in self.sel]
class Food:
def __new__(cls):
coord_x = random.randint(1, 22) * 15 + 10
coord_y = random.randint(1, 22) * 15 + 10
cls.coords = coord_x, coord_y
x_left = coord_x + 1
x_right = coord_x + 14
y_left = coord_y + 1
y_right = coord_y + 14
return win.create_oval(x_left,y_left,x_right,y_right,fill='grey')
class Score: #计分器
def __init__(self,snak):
self.score=0
self.snak=snak
self.id = snak.id
self.update_score()
def update_score(self):
self.sco = win.create_text(
450, 15 + 40 * self.id,
text=f"Score{self.id}:{self.score}",
fill='green'
)
def __repr__(self):
return str(self.score)
def __next__(self):
self.score += 20
win.delete(self.sco)
self.update_score()
class Time:
def __init__(self):
self.time_now = time.perf_counter()
self.time_end = self.time_now + 60
self.update_time()
def update_time(self):
self.ti = win.create_text(
450, 200,
text=f"{self.time_end-self.time_now:0.2f}s",
fill="green"
)
def __next__(self):
if self.time_now < self.time_end:
win.delete(self.ti)
self.update_time()
self.time_now = time.perf_counter()
else:
win.delete(self.ti)
self.time_now = self.time_end
self.update_time()
raise StopIteration
class Process:
time = Time()
snake = []
score = []
def add_snake(self,snake):
self.snake.append(snake)
self.score.append(Score(snake))
@classmethod
def condition(cls,snak):
cond1 = snak[-1] not in snak[:-1]
cond2 = snak[-1][0] < 385 and snak[-1][0] > 10
cond3 = snak[-1][1] < 385 and snak[-1][1] > 10
return cond1 and cond2 and cond3
async def process(self,snake,score):
while Process.condition(snake):
if Food.coords in snake:
snake.eat(self.food),next(score)
self.food = Food()
else:
snake.move()
try:
next(self.time)
except:
break
await asyncio.sleep(0.1)
root.update()
snake.die()
async def start(self):
self.food = Food()
tasks = [asyncio.Task(self.process(sn,sc)) for sn,sc in zip(self.snake,self.score)]
await asyncio.gather(*tasks)
score = list(map(int,map(str , self.score)))
import pandas as pd
df = pd.DataFrame({"id":list(range(len(score))),"score":score})
print(df.sort_values(by="score",ascending=False))
if __name__=='__main__':
proc = Process()
snake1 = Snake("blue")
snake2 = Snake("red")
snake3 = Snake("green")
proc.add_snake(snake1)
proc.add_snake(snake2)
proc.add_snake(snake3)
win.bind("" , lambda x: asyncio.run(proc.start()) )
win.bind("" , snake1.left)
win.bind("" , snake1.right)
win.bind("" , snake2.left)
win.bind("" , snake2.right)
win.bind("" ,snake3.left)
win.bind("" ,snake3.right)
win.focus_set()
win.pack()
root.mainloop()
注:这里以3人游戏为例,如果是多于或者少于3人,只需修改程序入口处代码即可
id score
0 0 100
2 2 20
1 1 0