动画实现蛇年当然贪吃蛇 PyQt版贪吃蛇引子 动画实现

每日一贴,今天的内容关键字为动画实现

    蛇年到,贪吃蛇还是要出马下的,不准备写整完的程序,就让蛇跑起来,尾巴的长起来吧,蛇头有点动画得了。

    

 

    先讲讲一些道理,蛇的袋脑应用键盘制控,因此写重他的keyPressEvent是势在必行的;

    蛇身可以长增,动运,本来我划计是蛇身的每一块的坐标都市动移,可看见一个老哥说每次只要把尾巴动移的蛇袋脑那里,蛇袋脑再往前跑跑,蛇就动了,想想也是。蛇身是一块块构成的,很对的块成形一个组,酿成蛇的身子,每次蛇要长长,只要在这个组里加增新的块可即。

    因为应用了大批的图形,因此应用PyQt里头的带Graphics的那一堆类,写重QGraphicsItem的类或者子类,成完特定的能功,作为基本的元素;应用QGraphicsScene加增元素;QGraphicsView表现。

    想应用动画Animation,看了看里头要需QObject来初始化,而QGraphicsItem居然不是继承自QObject的。因此我择选了QGraphicsObject作为类基来完善求需,他继承自QGraphicsItemQObject,可以应用动画的西东。

    面下是整完的代码,先贴上:

View Code
  1 import sys
  2 import random
  3 from Queue import deque
  4 from PyQt4.QtCore import (QObject,QRectF,QRect,QPointF,
  5                           QTimer,SIGNAL,Qt,pyqtProperty,
  6                           QPropertyAnimation,QEasingCurve )
  7 from PyQt4.QtGui import (QMainWindow,QGraphicsScene,QGraphicsView,
  8                          QGraphicsPixmapItem,QGraphicsItem,
  9                          QFont,QPainter,QPixmap,
 10                          QPainter,QGraphicsItemGroup,
 11                          QApplication,QGraphicsObject)
 12 import qrc_resources
 13 
 14 class Segment(QGraphicsObject):
 15     width = 50
 16     def __init__(self,pos,parent=None):
 17         super(Segment,self).__init__(parent)
 18         self.setPixmap(QPixmap(":/img/book.jpg"))
 19         self.setFlags(QGraphicsItem.ItemIsSelectable|
 20                       QGraphicsItem.ItemIsMovable)
 21         self.setPos(pos)
 22 #    def setPos(self,pos):
 23 #        super(Segment,self).setPos(pos)
 24     def pixmap(self):
 25         return self.pix
 26     def setPixmap(self,pix):
 27         self.pix = pix
 28     def paint(self,painter,option,widget):
 29         painter.drawPixmap(QRect(0,0,self.width,self.width),
 30                            self.pixmap())        
 31     def boundingRect (self):
 32         return QRectF(0,0,self.width,self.width)
 33 class Head(Segment):
 34     speed = Segment.width    
 35     UP = 0
 36     DOWN = 1
 37     LEFT = 2
 38     RIGHT = 3
 39     TimeGap = 500
 40     CURVE_TYPES = [(n, c) for n, c in QEasingCurve.__dict__.items()
 41                 if isinstance(c, QEasingCurve.Type) and c != QEasingCurve.Custom]
 42     def _set_pos(self,pos):
 43         self.setPos(pos)
 44     def _get_pos(self):
 45         return self.pos()
 46     
 47     position = pyqtProperty(QPointF,fset = _set_pos,
 48                                      fget = _get_pos)
 49     def __init__(self,pos,parent=None):
 50         super(Head,self).__init__(pos,parent)
 51         self.setPixmap(QPixmap(":/img/person.jpg"))
 52         self.setFlags(QGraphicsItem.ItemIsSelectable|
 53                       QGraphicsItem.ItemIsMovable|
 54                       QGraphicsItem.ItemIsFocusable)
 55         self.curveType = QEasingCurve.OutBounce
 56         self.setPos(pos)
 57         self.setFocus(Qt.OtherFocusReason)
 58         self.direction = self.RIGHT
 59         self.timer = QTimer()
 60         self.timer.start(self.TimeGap)
 61         QObject.connect(self.timer, SIGNAL("timeout()"),
 62                      self.move)
 63     def move(self):
 64         pos = self.pos()
 65         # add animation,i dont know why must do this
 66         # else it wont be move
 67         if self.direction == self.LEFT:
 68             position = pos + QPointF(-self.speed,0)
 69         elif self.direction == self.RIGHT:
 70             position = pos + QPointF(self.speed,0)
 71         elif self.direction == self.UP:
 72             position = pos + QPointF(0,-self.speed)
 73         elif self.direction == self.DOWN:
 74             position = pos + QPointF(0,self.speed)
 75         
 76         pre = pos = position
 77         
 78         rect = QRectF(self.boundingRect())
 79         if self.direction == self.LEFT:
 80             self.setPos(pos+QPointF(-self.speed,0))
 81         elif self.direction == self.RIGHT:
 82             self.setPos(pos+QPointF(self.speed,0))
 83         elif self.direction == self.UP:
 84             self.setPos(pos+QPointF(0,-self.speed))
 85         elif self.direction == self.DOWN:
 86             self.setPos(pos+QPointF(0,self.speed))
 87         current = self.pos()
 88         self.animationChanged(pre, current)
 89 
 90     def animationChanged(self,pre,current):    
 91         self.anim= QPropertyAnimation(self,'position')
 92         self.anim.setStartValue(pre)
 93         self.anim.setEndValue(current)
 94         
 95         self.anim.setEasingCurve(self.curveType)
 96         self.anim.setDirection(self.TimeGap-200)
 97         self.anim.start()
 98     def keyPressEvent (self,event):
 99         key = event.key()
100         if key == Qt.Key_Left:
101             self.direction = self.LEFT
102             return
103         if key == Qt.Key_Right:
104             self.direction = self.RIGHT
105             return
106         if key == Qt.Key_Up:
107             self.direction = self.UP
108             return
109         if key == Qt.Key_Down:
110             self.direction = self.DOWN
111             return
112 class SegmentGroup(QObject):
113     def __init__(self,scene,parent = None):
114         super(SegmentGroup,self).__init__(parent)
115         self.scene = scene
116         self.items = deque()
117         
118     def addSegment(self,segment):
119         self.scene.addItem(segment)
120         self.items.append(segment)
121         
122     def move(self,headPos):
123         if not self.items:return 
124         tail = self.items.pop()
125         tail.setPos(headPos)
126         self.items.appendleft(tail)
127     
128     def tail(self):
129         if not self.items:return
130         return self.items[-1]
131 
132 class SnackScene(QGraphicsScene):
133     def __init__(self,parent=None):
134         super(SnackScene,self).__init__(parent)
135         self.setSceneRect(0,0,400,300)
136         self.segmentGroup = SegmentGroup(self)
137         self.segmentGroup.addSegment(Segment(QPointF(0,0)))
138         
139         self.head = Head(QPointF(Segment.width,0))
140         self.addItem(self.head)
141         
142         self.setFocusItem(self.head)
143         self.timer = QTimer()
144         self.timer.start(Head.TimeGap)
145         
146         self.connect(self.timer, SIGNAL("timeout()"),
147                      self.segmentMove)
148     def segmentMove(self):
149         self.segmentGroup.move(self.head.pos())
150     def mousePressEvent (self, event):
151         if event.button() == Qt.LeftButton:
152             tail = self.segmentGroup.tail()
153             self.segmentGroup.addSegment(
154                                          Segment(tail.pos())
155                                          )
156         elif event.button() == Qt.RightButton:
157             curveType = random.choice(Head.CURVE_TYPES)
158             self.head.curveType = QEasingCurve(curveType[1])
159 
160 class Form(QMainWindow):
161     def __init__(self,parent=None):
162         super(Form,self).__init__(parent)
163         self.fileMenu = self.menuBar().addMenu("&File")
164         self.statusBar().showMessage("Ready", 5000)
165         self.scene = SnackScene()
166         
167         self.view = QGraphicsView(self.scene)
168         self.view.setRenderHint(QPainter.SmoothPixmapTransform)
169         self.view.setDragMode(QGraphicsView.RubberBandDrag)
170         self.setCentralWidget(self.view)
171     
172 app = QApplication(sys.argv)
173 
174 form = Form()
175 form.show()
176 app.exec_()

 

    资源文件:

View Code
1 <RCC>
2     <qresource prefix="/">
3         <file>img/book.jpg</file>
4         <file>img/person.jpg</file>
5         <file>img/cat.jpg</file>
6     </qresource>
7 </RCC>

 

    

开始讲授:

    

蛇的体身:

 1 class Segment(QGraphicsObject):
 2     width = 50
 3     def __init__(self,pos,parent=None):
 4         super(Segment,self).__init__(parent)
 5         self.setPixmap(QPixmap(":/img/book.jpg"))
 6         self.setFlags(QGraphicsItem.ItemIsSelectable|
 7                       QGraphicsItem.ItemIsMovable)
 8         self.setPos(pos)
 9 #    def setPos(self,pos):
10 #        super(Segment,self).setPos(pos)
11     def pixmap(self):
12         return self.pix
13     def setPixmap(self,pix):
14         self.pix = pix
15     def paint(self,painter,option,widget):
16         painter.drawPixmap(QRect(0,0,self.width,self.width),
17                            self.pixmap())        
18     def boundingRect (self):
19         return QRectF(0,0,self.width,self.width)

 

    boundingRect是指明这个对象所占的矩形空间巨细,因为有的时候你可以用鼠标择选图片,那么到底哪个区域呢,就是这个区域。

    为了让蛇身蛇头的巨细分歧,设置了一个width作为蛇身的静态成员变量,并且在paint法方中重绘了图片,这样,不管图片多么大,画出来都市酿成指定的巨细,保障了蛇身蛇头雷同的巨细。

    

蛇头

 1 class Head(Segment):
 2     speed = Segment.width    
 3     UP = 0
 4     DOWN = 1
 5     LEFT = 2
 6     RIGHT = 3
 7     TimeGap = 500
 8     CURVE_TYPES = [(n, c) for n, c in QEasingCurve.__dict__.items()
 9                 if isinstance(c, QEasingCurve.Type) and c != QEasingCurve.Custom]
10     def _set_pos(self,pos):
11         self.setPos(pos)
12     def _get_pos(self):
13         return self.pos()
14     
15     position = pyqtProperty(QPointF,fset = _set_pos,
16                                      fget = _get_pos)
17     def __init__(self,pos,parent=None):
18         super(Head,self).__init__(pos,parent)
19         self.setPixmap(QPixmap(":/img/person.jpg"))
20         self.setFlags(QGraphicsItem.ItemIsSelectable|
21                       QGraphicsItem.ItemIsMovable|
22                       QGraphicsItem.ItemIsFocusable)
23         self.curveType = QEasingCurve.OutBounce
24         self.setPos(pos)
25         self.setFocus(Qt.OtherFocusReason)
26         self.direction = self.RIGHT
27         self.timer = QTimer()
28         self.timer.start(self.TimeGap)
29         QObject.connect(self.timer, SIGNAL("timeout()"),
30                      self.move)
31     def move(self):
32         pos = self.pos()
33         # add animation,i dont know why must do this
34         # else it wont be move
35         if self.direction == self.LEFT:
36             position = pos + QPointF(-self.speed,0)
37         elif self.direction == self.RIGHT:
38             position = pos + QPointF(self.speed,0)
39         elif self.direction == self.UP:
40             position = pos + QPointF(0,-self.speed)
41         elif self.direction == self.DOWN:
42             position = pos + QPointF(0,self.speed)
43         
44         pre = pos = position
45         
46         rect = QRectF(self.boundingRect())
47         if self.direction == self.LEFT:
48             self.setPos(pos+QPointF(-self.speed,0))
49         elif self.direction == self.RIGHT:
50             self.setPos(pos+QPointF(self.speed,0))
51         elif self.direction == self.UP:
52             self.setPos(pos+QPointF(0,-self.speed))
53         elif self.direction == self.DOWN:
54             self.setPos(pos+QPointF(0,self.speed))
55         current = self.pos()
56         self.animationChanged(pre, current)
57 
58     def animationChanged(self,pre,current):    
59         self.anim= QPropertyAnimation(self,'position')
60         self.anim.setStartValue(pre)
61         self.anim.setEndValue(current)
62         
63         self.anim.setEasingCurve(self.curveType)
64         self.anim.setDirection(self.TimeGap-200)
65         self.anim.start()
66     def keyPressEvent (self,event):
67         key = event.key()
68         if key == Qt.Key_Left:
69             self.direction = self.LEFT
70             return
71         if key == Qt.Key_Right:
72             self.direction = self.RIGHT
73             return
74         if key == Qt.Key_Up:
75             self.direction = self.UP
76             return
77         if key == Qt.Key_Down:
78             self.direction = self.DOWN
79             return

 

    设置了四个向方,并且写重了keyPressEvent法方,键盘按下的时候,转变self.direction的向方。

    CURVE_TYPES是动画的全部可能取值,有40多种,可查阅QEasingCurve的文档。

    蛇头的动运,是在move法方中实现的,如果不加添动画的话,第一段if else语句并不要需加,程序运行常正,可加添动画后,不知道为什么,每次运行到这里,pos的值与上一次运行move的值雷同,不得已加了一段if else使得程序能常正运行。

    animationChanged法方实现了蛇头的动画,self.anim.setEasingCurve(self.curveType)设置动画效果,为了让动画效果可以转变,因此保留了一个self.curveType变量。另外在造构时self.anim= QPropertyAnimation(self,'position'),第一个数参要需是QObject对象,而第二个数参要需时Qt的属性,因此在上面我命生了一个position属性,代码如下:

1     def _set_pos(self,pos):
2         self.setPos(pos)
3     def _get_pos(self):
4         return self.pos()
5     
6     position = pyqtProperty(QPointF,fset = _set_pos,
7                                      fget = _get_pos)

 

    造构法方的定时器让蛇身连续动移,这个在我之前的博客中有分析,不在啰嗦。

    

蛇身Group

 1 class SegmentGroup(QObject):
 2     def __init__(self,scene,parent = None):
 3         super(SegmentGroup,self).__init__(parent)
 4         self.scene = scene
 5         self.items = deque()
 6         
 7     def addSegment(self,segment):
 8         self.scene.addItem(segment)
 9         self.items.append(segment)
10         
11     def move(self,headPos):
12         if not self.items:return 
13         tail = self.items.pop()
14         tail.setPos(headPos)
15         self.items.appendleft(tail)
16     
17     def tail(self):
18         if not self.items:return
19         return self.items[-1]

 

    这是为了便利理管,将蛇头和整段体身分离而做的一个器容,因为重要在实第一节蛇身和蛇尾之间行进插入删除操纵,所以应用python的deque()来实现这个器容,并且这个器容直接将蛇身加添到scene中去。代码木有神马别特要需明说的。

    

Scene

 1 class SnackScene(QGraphicsScene):
 2     def __init__(self,parent=None):
 3         super(SnackScene,self).__init__(parent)
 4         self.setSceneRect(0,0,400,300)
 5         self.segmentGroup = SegmentGroup(self)
 6         self.segmentGroup.addSegment(Segment(QPointF(0,0)))
 7         
 8         self.head = Head(QPointF(Segment.width,0))
 9         self.addItem(self.head)
10         
11         self.setFocusItem(self.head)
12         self.timer = QTimer()
13         self.timer.start(Head.TimeGap)
14         
15         self.connect(self.timer, SIGNAL("timeout()"),
16                      self.segmentMove)
17     def segmentMove(self):
18         self.segmentGroup.move(self.head.pos())
19     def mousePressEvent (self, event):
20         if event.button() == Qt.LeftButton:
21             tail = self.segmentGroup.tail()
22             self.segmentGroup.addSegment(
23                                          Segment(tail.pos())
24                                          )
25         elif event.button() == Qt.RightButton:
26             curveType = random.choice(Head.CURVE_TYPES)
27             self.head.curveType = QEasingCurve(curveType[1])

 

    在这个类中加添据数,蛇头,蛇身理管器,设置了简略的长增蛇身的事件——按下鼠标左键;而按下键右则是改更蛇头的动画效果。将蛇身的动移与蛇头的动移对应起来,用一个与蛇头定时器间时雷同的定时器来实现。

    最后的form则是应用mainwindow在实现的应用程序。

 1 class Form(QMainWindow):
 2     def __init__(self,parent=None):
 3         super(Form,self).__init__(parent)
 4         self.fileMenu = self.menuBar().addMenu("&File")
 5         self.statusBar().showMessage("Ready", 5000)
 6         self.scene = SnackScene()
 7         
 8         self.view = QGraphicsView(self.scene)
 9         self.view.setRenderHint(QPainter.SmoothPixmapTransform)
10         self.view.setDragMode(QGraphicsView.RubberBandDrag)
11         self.setCentralWidget(self.view)

 

    跋文:做这个然依是为了练熟qt,本来是想用图形界面做设计模式的,但是有些模式想不好写神马好,就像装饰者模式,用神马例子捏?

文章结束给大家分享下程序员的一些笑话语录: AdobeFlash拖垮Windows拖垮IE!又拖垮Linux拖垮Ubuntu拖垮FirxEox!还拖垮BSD拖垮MacOS拖垮Safri!简直无所不拖!AdobeFlash滚出网路世界!不要以为市占有率高就可以持续出烂货产品!以后替代品多得是!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值