五、翻牌子的逻辑
接下来,实现翻牌子的具体逻辑。
首先必须要清楚,翻牌子游戏的重点是每个牌子都是可以点击的,pygame在处理点击事件的时候,是通过捕捉游戏主角在屏幕上面的坐标实现的,也就是说需要知道鼠标点击的位置是否在一张牌之内,可以通过鼠标去点击每一张牌的左上,右上,左下,右下来确定这张牌所占的空间位置。如下图所示。
如图中所示的方法点击其中的1、2、3、4等位置,就可以记录对应的坐标值。
鼠标操作可以通过pygame.event.get()语句中获取的事件类型event.type来判断是否是鼠标发生了交互,然后再通过event.pos方法获取对应鼠标对应的点。代码如下。
if event.type==pygame.MOUSEBUTTONDOWN:
mosx,mosy=event.pos
print(mosx,mosy)
在前面完成的程序死循环循环体中判断事件是否退出的后面添加上述代码,运行后,点击屏幕上的坐标点,就会有对应的坐标点进行输出。输出结果如图所示。
也可以通过这些牌子的坐标点规律来进行判断也是可以的。
通过前面的代码会知道y轴的第一排起始为5,第二排起始为250。x轴的规律是被5除得的余数乘以200后再加上偏移量100,这是由前面的代码x=i%5*200+100,如果想要算出一横排中每张牌子的索引值,实际就是把x轴数据减去100然后再除以200。即索引值i=(x-100)/200。
通过坐标点中x和y的位置判断具体点击哪张牌的代码逻辑如下。
if mosy>=5 and mosy<500:
index=int((mosx-100)/200)
elif mosy>=500:
index=int((mosx-100)/200)+5
print("索引值:"+str(index))
这段代码就紧随mosx,mosy=event.pos后面就可以。
当然,index不能无中生有,在使用前需要在游戏程序死循环体的外面加上inde=0这一句代码,来进行对index的初值进行赋值。
运行这段代码后,图形界面中点击每一张牌,就会在控制台输出对应的索引值。如下图所示。
通过这种判断x与y坐标的方法就会获得用户点击的到底是哪张牌,然后就需要显示这张牌的正面效果是哪一个佳丽的图片了。
为了能够达到图片中重复的图片会出现而且只会出现2次,需要定义一个这样的列表变量,存放每一幅图片的图片名称即可。可以在程序体死循环的外面声明这个变量。
cards=["images/hongong1.jpg","images/hongong2.jpg","images/hongong3.jpg","images/hongong4.jpg","images/hongong5.jpg","images/hongong1.jpg","images/hongong2.jpg","images/hongong3.jpg","images/hongong4.jpg","images/hongong5.jpg"]
上面这个列表变量按顺序分别放置了5张图片名称,然后又放置了相同的5张图片名称。
但是,这种顺序很容易把游戏变得无聊,5张图片有规律的放置也使游戏变得简单了,这就需要把上面有顺序的图片进行打乱,相当于现实生活中的洗牌操作。洗牌操作的实质就是在列表中随机选择任意两个位置,然后选择的这两个位置上面的图像名称进行交换,这样一直随机选择位置,一直把位置上的图像进行交换,如此往复多次,就可以完成洗牌的操作。代码中迭代往复1000次,具体如下。
for j in range(1000):
m=random.randint(0,len(cards)-1)
n=random.randint(0,len(cards)-1)
cards[m],cards[n]=cards[n],cards[m]
这段代码中一开始用for循环进行迭代次数,也就是循环洗牌的次数。在循环体中首先从cards列表长度索引值中随机选择一个值,然后再从cards列表长度索引值中随机选择另一个值,用a,b=b,a这种python特有的两值交换的方式进行列表中任意位置的两张牌进行交换。
如果运行这段代码后,打印出来cards里面的内容,就会发现里面的图片名称位置与原来cards列表中的位置发生了改变。
如下图的对比所示
洗完牌之后,按顺序排好的位置发生了变化。不管怎么样变化,也不会超过预先设定的10张牌的图片名称。前面也计算出来了点击牌子后对应的索引值的变化,把这个索引值对应于这个打乱顺序的列表索引值,就实现了点击后背面的牌会显示出列表中正面的佳丽的图片。代码如下。
img2 = pygame.image.load(cards[index])
if index<5:
x=index*200+100
else:
x=(index-5)*200+100
if mosy>=500:
y=500
else:
y=255
screen.blit(img2, (x, y))
这段代码中为了把程序说明白,把x,y两个值重新计算了一遍,x是利用前面算过的index来进行逆运算,就是index200+100,不过要注意,index只有小于5的时候,也就是第一行的时候,才会index200+100,当点击的是第二行的时候,需要把算出来的索引值index基础上再减去5。y值也需要判断图片显示的具体位置,是第一行就y=255,是第二行的就是y=500。运行后,出现牌子的背面图案,点击背面图案后,所有的牌子都可以进行翻牌。
如下图所示。
这里把所有的牌子都翻了过来,从翻出来的牌子来看,是同样的图片出现且只出现了2张,不过我们的真实需求是第二张牌子翻开的时候,第一张牌子不同需要翻过去,同时只能显示一张牌子。完成这个需求可以设置一个记录点击第一次的变量,这个变量初始值为空,如果有了翻面的牌,这个变量就保存翻面牌的索引值,再点击第二张牌的时候,会出现两种情况。
(1)如果索引值相同,就证明点击了同一张牌,这个显示出图像的牌再恢复到背面,这种操作可以这样处理。
(2)如果索引值不相同,就证明点击了不同牌,如果索引值对应的列表值相同就认为选择了两张同样图片的牌面,两张牌可以先用两张牌相同来表示一下,这样看得清楚,如果不是两张同样的牌面,就证明没有选择同样的牌,这时第一张牌就翻面了,第二张牌就显示到了正面。
具体代码如下。
if mosy>=5 and mosy<500:
index=int((mosx-100)/200)
elif mosy>=500:
index=int((mosx-100)/200)+5
if curx==-1:
curx=index
cury=mosy
img2 = pygame.image.load(cards[index])
else:
if curx==index:
img2=pygame.image.load("images/back.png")
curx=-1
cury=-1
else:
oldx=curx
oldy=cury
if cards[curx]!=cards[index]:
img2=pygame.image.load(cards[index])
img3 = pygame.image.load("images/back.png")
curx = index
cury = mosy
elif cards[curx]==cards[index]:
img2=pygame.image.load("images/same.png")
img3 = pygame.image.load("images/same.png")
curx = -1
cury = -1
if oldx< 5:
x1 = oldx*200 + 100
else:
x1 = (oldx - 5) * 200 + 100
if oldy >= 500:
y1 = 500
else:
y1 = 255
screen.blit(img3, (x1, y1))
if index<5:
x=index*200+100
else:
x=(index-5)*200+100
if mosy>=500:
y=500
else:
y=255
screen.blit(img2, (x, y))
在这段代码中,这里从mosx,mosy开始谈起,首先代码需要计算对应的点击index值,根据mosy处于不同的坐标来判断index的值,接着判断存储第一张牌点击记录的索引值curx,这个索引值在循环外初始化时为-1。
如果判断curx这个值为-1,就证明还是初始化时的状态,需要把索引值记录到循环外的变量curx中,把y的坐标记录到循环外的变量cury中,curx和cury共同作用便于识别出点击的牌在界面中的具体位置。同时把当前点击的牌的正面图像保存在img2变量中,程序最后是需要screen.blit(img2,(x,y))语句在适当的位置画出对应的图像。
反之,如果判断curx这个值不为-1,也就是证明点击过第一张牌,且这张牌已翻面显示图像。那么就继续判断curx记录的索引值与当前点击的索引值index是否相等,如果相等,就证明点击的是同一张牌,就把curx和cury全部置为-1,把当前点击这张牌图案翻面,显示背面。也就是当前唯一一张已翻面的牌子又翻过去了,没有被翻面的牌子。与之相反的就是,如果curx记录的索引值与当前点击的索引index不相等,这时就要判断这两张牌是不是同一张牌,但是,不管是不是同一张牌,都需要两张牌进行动作,相等,两张牌同时换成图案相等的图像,不相等,前一张牌换成背面图案,后一张牌显示正面人物图案。两张牌都需要在游戏窗口中重新绘制,需要前一张牌的坐标值和当前点击牌的坐标值。由于程序处理过程中,两张牌相等,会把记录索引值的curx置为-1,表示现在没有翻面的牌了。两张牌不相等,又要把记录索引值的curx改为当前点击牌的索引值。由于curx值会在程序处理过程中随时改变,因此,首先用oldx,oldy去存储一下程序中发生改变的curx,cury,这样可以保存前一张牌的坐标位置,便于重绘牌面。保存了这个先前位置的坐标值后,就要判断牌面列表当前值和先前值的索引位置对应的图像是否相等,如果不相等,把列表中当前索引对应的图像名称赋给当前牌的变量img2,同时将记录索引值的变量curx,cury保存当前牌的位置,如果相等,两张牌同时赋给same的图案帮助理解,同时把记录索引值的变量curx,cury全部置为-1.
接下来程序的逻辑就比较简单了,根据保存的前后两张牌的索引值,分别计算出对应的前后两张牌的x和y坐标,在对应的坐标位置画出前后两张牌不同和相同的图像变化。
整个程序的完整代码如下。
import pygame
import random
pygame.init()
screen=pygame.display.set_mode((1450,736))
bk=pygame.image.load("images/hougong.jpg")
screen.blit(bk,(0,0))
y=5
index=0
cards=["images/hongong1.jpg","images/hongong2.jpg","images/hongong3.jpg","images/hongong4.jpg","images/hongong5.jpg","images/hongong1.jpg","images/hongong2.jpg","images/hongong3.jpg","images/hongong4.jpg","images/hongong5.jpg"]
print("原来的:")
print(cards)
for j in range(1000):
m=random.randint(0,len(cards)-1)
n=random.randint(0,len(cards)-1)
cards[m],cards[n]=cards[n],cards[m]
print("洗牌之后的:")
print(cards)
curx=-1
cury=-1
for i in range(10):
if i%5==0 and y!=0:
y+=250
img1=pygame.image.load("images/back.png")
x=i%5*200+100
screen.blit(img1,(x,y))
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
if event.type==pygame.MOUSEBUTTONDOWN:
mosx,mosy=event.pos
if mosy>=5 and mosy<500:
index=int((mosx-100)/200)
elif mosy>=500:
index=int((mosx-100)/200)+5
if curx==-1:
curx=index
cury=mosy
img2 = pygame.image.load(cards[index])
else:
if curx==index:
img2=pygame.image.load("images/back.png")
curx=-1
cury=-1
else:
print(cards[curx])
print(cards[index])
print("----------------")
oldx=curx
oldy=cury
if cards[curx]!=cards[index]:
img2=pygame.image.load(cards[index])
img3 = pygame.image.load("images/back.png")
curx = index
cury = mosy
elif cards[curx]==cards[index]:
img2=pygame.image.load("images/same.png")
img3 = pygame.image.load("images/same.png")
curx = -1
cury = -1
if oldx< 5:
x1 = oldx*200 + 100
else:
x1 = (oldx - 5) * 200 + 100
if oldy >= 500:
y1 = 500
else:
y1 = 255
print("****************")
print(oldx)
print(x1)
print(y1)
print(img3)
print("*****************")
screen.blit(img3, (x1, y1))
if index<5:
x=index*200+100
else:
x=(index-5)*200+100
if mosy>=500:
y=500
else:
y=255
screen.blit(img2, (x, y))
pygame.display.update()
程序运行后,全部点击成功后的结果如图所示。
代码的github地址:https://github.com/wawacode/turn_over_card