前言
惭愧啊,三个月没更新下篇,问哥想起了西岳奇童。。。按你胃,最近确实忙得不可开交,忙着忙着,就忘记了在CSDN上继续游戏梦想了。另一方面,好像这个游戏比较冷门,所以阅读量也比较低,而热门的游戏也有比较成熟的代码,问哥又不想去复制粘贴。不管怎么样,烂尾总是不对,对不起大家!
其实这个游戏在上篇已经介绍的差不多了,唯一的“悬念”是如何实现棋子的动作。其实细究起来,倒也不算悬念。所谓的动作,就是连续的画面展示,在之前介绍的骰子、计时器里都有介绍过。而棋子的运动也较为类似。
上篇 —— 游戏界面搭建与基本逻辑
下篇 —— 移动棋子的动画实现与算法
蛇棋
1. 玩法简介
游戏截图:
2. 实现棋子移动
在上篇里,我们引入了棋子的自定义“类”(Piece),这样把棋子定义为有“方法”的类的实例,就像有生命一样。
class Piece:
def __init__(self,name,cv,co,bg):
self.name = name
self.cv = cv
self.id = cv.create_image(co,image = bg)
self.pos = 0
def choose_piece(img):
global players
P1 = Piece("Player", cv, (30,650),player_img[img])
P2 = Piece("電腦", cv, (50,655),player_img[1-img])
players=[P1,P2]
那么包括移动在内的棋子的方法,自然也应该定义在棋子这个类里。在我看来,棋子这个类应该包括至少两个方法:移动和判断。而前者就可以继续分为两个方法:横向跳跃和纵向跨域。判断就是指棋子移动到新的地点后,根据该地点的状况(梯子还是蛇头)来决定是否执行进一步的移动(升级或是后退)。
下面把完整的类定义内容贴出来:
class Piece:
def __init__(self,name,cv,co,bg):
self.name = name
self.cv = cv
self.id = cv.create_image(co,image = bg)
self.pos = 0
def jump(self,n,acc=-10,reverse=1):
if self.pos==100:reverse = -1
self.d = -reverse if (self.pos//10)%2 or self.pos==100 else reverse
if 0<self.pos<100 and self.pos%10==0:
self.d *= -1
self.shift(self.pos+1)
if n>1:
self.cv.after(50,lambda :self.jump(n-1))
else: self.judge()
else:
self.cv.move(self.id,5.8*self.d,acc)
if acc <10:
self.cv.after(50,lambda :self.jump(n,acc+2,reverse))
else:
self.pos = self.pos+1 if reverse>0 else self.pos-1
if n>1:
self.cv.after(50,lambda :self.jump(n-1,-10,reverse))
else:
self.judge()
def shift(self,tar):
self.d = -1 if (self.pos//10)%2 else 1
dist_level = (tar-1)//10-(self.pos-1)//10
if dist_level == 0:
# self.jump(abs(tar-self.pos),-10,-1)
dist_x = ((tar-1)%10-(self.pos-1)%10)*63.8
for i in range(int(abs(dist_x))):
self.cv.move(self.id,1,0)
time.sleep(0.005)
self.cv.update()
self.pos = tar
else:
if dist_level%2:
dist_x = (11-(tar-1)%10-(self.pos-1)%10-2)*63.8
else:
dist_x = ((tar-1)%10-(self.pos-1)%10)*63.8
dist_y = dist_level*63
angle = dist_x/abs(dist_y)
d=1 if dist_y<0 else -1
for i in range(abs(dist_y)):
self.cv.move(self.id,angle*self.d,d)
time.sleep(0.005)
self.cv.update()
self.pos = tar
def judge(self):
if self.pos in LADDER.keys():
info_update(f'{self.name} 运气真好,遇到梯子!')
info_update(f'{self.name} 前进到 {LADDER[self.pos]} ^O^')
tar = LADDER[self.pos]
self.shift(tar)
if self.pos==100:
win_next(self.name)
return
elif self.pos in SNAKE.keys():
info_update(f'{self.name} 遭遇蛇吻!')
info_update(f'{self.name} 退回到 {SNAKE[self.pos]} T_T')
tar = SNAKE[self.pos]
self.shift(tar)
elif self.pos==100:
win_next(self.name)
return
else:
info_update(f"{self.name} 移动到 {self.pos}")
players.reverse()
if players[0].name=='電腦':
info_update("電腦 开始掷骰子")
roll(0)
else:
info_update("等待玩家掷骰子")
btn['state']=NORMAL
而同样的,我们希望棋子在转动骰子后,根据骰子的点数自动开始移动,就需要把骰子运动的函数与棋子的移动方法链接起来:
def move(step):
info_update(f"{players[0].name} 掷出了 {step} 点")
players[0].jump(step)
def roll(i):
btn['state']=DISABLED
if i<13:
cv.itemconfig(image1,image=dice_rotate[i])
root.after(50,lambda :roll(i+1))
else:
res = random.randint(0,5)
cv.itemconfig(image1,image=dice[res])
move(res+1)
这样一样,我们只要点击“掷骰子”的按钮,转出数字,棋子就会自动开始移动了。
匆忙贴出了代码,大家如果感兴趣,可以自行尝试,下次问哥不再轻易尝试这么冷门的游戏了。😄