[pygame] pygame设计联机对战桌游(4-1)
本系列总目录:https://blog.csdn.net/wxlxy316/article/details/104246724
内容概要
四、分析桌游需求,制作类图,开始开发桌游(1)
昨日问题
在学习了一定的知识后——实际上是看了太久繁杂的英文教程,感到了倦怠和恶心——我决心为自己做一份甜点休憩一下:从设计简单的卡片展示器着手,先制作出一个简单的雏形来,验证自己的学习成果,再继续我的学习路径
先提几个昨日遇到的问题
python 获取某个对象的引用地址
https://blog.csdn.net/cpongo6/article/details/89249293
出现UnboundLocalError: local variable ‘a’ referenced before assignment异常的情况与解决方法
https://blog.csdn.net/DansonC/article/details/88860885
pygame.event类别汇总
https://blog.csdn.net/qq_41556318/article/details/86303039
这些问题使我感到了深深的沮丧和挫败,并且让我发现我对python对象的有关概念的理解实在是烂透了,因此我打开了菜鸟教程恶补了几天python class的知识:https://www.runoob.com/python3/python3-class.html
,关于学习这些内容时的笔记和感悟我放在文章后部了,现在,我们先讨论一下目前的工作吧!
卡牌展示器
0. 成果总结
1. 卡牌显示器
最终我厘清了一些思路,制作了一份简单的卡牌显示器,它具有如下特性:
- 定义了两个类:卡堆
CardHeap
、卡牌Card
- 卡牌若干,分布在卡堆中,卡牌和卡堆一一对应
- 卡牌拥有正反两面,可以实现单击翻面特性
- 卡牌在卡堆中一字排开,存在次序,紧邻排布(未完成)
- 可以通过鼠标调整卡牌在卡堆中的顺序,也可以调整卡牌移动到不同的卡堆中
代码和素材移步github地址:https://github.com/bridgeL/card_show
2. 精灵类及其容器
学习了pygame.sprite.Sprite
类,pygame.sprite.Group
类,pygame.sprite.OrderedUpdates
类,简单来说,
后两个类是第一个类的容器,且较前者为无序容器,较后者为有序容器,一般来说有序容器较慢,应根据实际情形使用不同的容器打包pygame.sprite.Sprite
对象
3. 事件循环
深化了对于Event循环的理解:
- clock模块,提供适当延时,以保证阵列稳定为预设值
- 处理event队列,将每一帧间积攒的多个操作,依次处理
- 获取上一帧中的精灵对象的矩阵坐标,用底图的对应部分覆盖
screen.blit(background,sprite.rect)
,对于对于组内的精灵可用group.clear(screen,background)
,会自动迭代处理每一个精灵 - 运行游戏逻辑,计算这一帧精灵对象的矩阵坐标
sprite.update()
,对于组内的精灵可用group.update()
,会自动迭代处理每一个精灵 - 绘制组内精灵对象到这一帧
group.draw(screen)
- 应用更改到显示器
pygame.display.flip()
1. 游戏对象类
1.1. 卡牌Card
2020/2/11
今日实在太匆忙,代码只做了一个雏形,也来不及写完第三期的官方教程学习笔记,这一期也漏了一些很坑的问题,我明天再来补充
卡牌类继承自pygame.sprite.Sprite类,新增属性imgh
,imgb
,id
,label
,headup
,movepos
提供方法overturn
,isclick
,move
,重写了方法update
,最值得一提的是,我在卡牌类中封装一个公共属性imgb
总所周知,一套卡牌的正面图案各不相同,但是背面图是一致的,如果我们为每个卡牌都加载两份图片(正反两面)的内存空间,那么至少有一半的内存空间是无意义消耗的,因此我为卡牌封装了一个公共属性imgb
,存放反面图片,同时设计了属性self.headup
和方法Card.overturn(self)
这个方法将在翻转卡牌时起作用,它负责将属性self.headup
翻转,同时修改self.image
指向另一面,self.imgh
或imgb
class Card(pygame.sprite.Sprite):
imgb = 0
def __init__(self, id, lable):
super(Card, self).__init__()
self.imgh, self.rect = load_img(lable+'.jpg')
self.image = self.imgh
self.id = id
self.lable = lable
self.headup = True
self.movepos = [0, 0]
def update(self):
if self.movepos[0] != 0 or self.movepos[1] != 0:
self.rect.move_ip(self.movepos)
self.movepos = [0, 0]
def overturn(self):
self.headup = not self.headup
if self.headup:
self.image = self.imgh
else:
self.image = Card.imgb
def isclick(self, pos):
return self.rect.collidepoint(pos)
def move(self, rel):
self.movepos[0] += rel[0]
self.movepos[1] += rel[1]
比较坑的一点在于,我在摸索这一模式时,经常遇到了
UnboundLocalError: local variable '<module_name>' referenced before assignment
类似这种错误,这是为什么呢?
原代码如下:
class Card(pygame.sprite.Sprite):
imgb = pygame.image.load('data/back.jpg')
def __init__(self, id, lable):
super(Card, self).__init__()
self.imgh, self.rect = load_img(lable+'.jpg')
self.image = self.imgh
...
...
原来,这份代码在编译class Card类时——尽管此时还没有任何一个card对象实例化——调用了还没有初始化的pygame.image模块的函数,而pygame的初始化函数在main函数里,
经修改如下:
class Card(pygame.sprite.Sprite):
imgb = 0
def __init__(self, id, lable):
super(Card, self).__init__()
self.imgh, self.rect = load_img(lable+'.jpg')
self.image = self.imgh
...
...
def cardinit():
Card.imgb = pygame.image.load('data/back.jpg')