1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
from gi.repository import Gtk
import cairo
from gi.repository import Rsvg
from sugar3.graphics import style
class Sprite(object):
def __init__(self, svg_file, cel_width, cel_height, animation_data):
self.svg_file = svg_file
self.cel_width, self.cel_height = cel_width, cel_height
self.current_animation = None
self.direction = 1
self._animation_data = animation_data
self._current_data = None
self._animation_index = None
self.load_svg()
def load_svg(self):
self._svg = Rsvg.Handle.new_from_file(self.svg_file)
self._svg_width = self._svg.props.width
# create a cache with the image rendered
self.cache = cairo.ImageSurface(cairo.FORMAT_ARGB32,
self._svg.props.width, self._svg.props.height)
self.cache_context = cairo.Context(self.cache)
self._svg.render_cairo(self.cache_context)
self.cache.flush()
# and another with a flipped render
self.cache_inv = cairo.ImageSurface(cairo.FORMAT_ARGB32,
self._svg.props.width, self._svg.props.height)
self.cache_inv_context = cairo.Context(self.cache_inv)
self.cache_inv_context.scale(-1, 1)
self.cache_inv_context.translate(-self._svg.props.width, 0)
self._svg.render_cairo(self.cache_inv_context)
self.cache_inv.flush()
def change_animation(self, animation_name, direction=1):
self.current_animation = animation_name
self._current_data = self._animation_data[animation_name]
self._animation_index = 0
if self.direction == -1:
self._current_data = list(reversed(self._current_data))
def next_frame(self):
if self._animation_index + 1 == len(self._current_data):
self._animation_index = 0
else:
self._animation_index += 1
def draw(self, context, dx, dy):
cel_x, cel_y = self._current_data[self._animation_index]
# another context to draw only one cell
self.one_cell = cairo.ImageSurface(cairo.FORMAT_ARGB32,
self.cel_width, self._svg.props.height)
self.one_cell_context = cairo.Context(self.one_cell)
if self.direction == 1:
self.one_cell_context.set_source_surface(self.cache,
-cel_x * self.cel_width, 0)
else:
self.one_cell_context.set_source_surface(self.cache_inv,
-cel_x * self.cel_width, 0)
self.one_cell_context.paint()
context.translate(dx, dy)
context.set_source_surface(self.one_cell)
context.rectangle(0, 0, self.cel_width, self.cel_height)
context.clip()
context.paint()
class Character(object):
def __init__(self, drawing_area):
super(Character, self).__init__()
self._drawing_area = drawing_area
self.speed = 10
animation_data = {
'stand': [(0, 0)],
'walk': [(1, 0), (2, 0), (3, 0), (4, 0),
(5, 0), (6, 0), (7, 0), (8, 0)],
}
self.sprite = Sprite("images/char_walking.svg",
100, 160, animation_data)
self.sprite.change_animation('walk')
self.pos = [0, 0]
self.direction = 1 # -1 for left, 1 for right
def update(self):
self.sprite.direction = self.direction
self.sprite.next_frame()
self.pos[0] += self.speed * self.direction
return (self.pos[0],
self.pos[1] - self.sprite.cel_height + 10,
self.sprite.cel_width, self.sprite.cel_height)
def draw(self, context):
# draw char
dx, dy = self.pos[0], self.pos[1] - self.sprite.cel_height + 10
context.save()
# for debug write a rectangle around
"""
context.rectangle(dx, dy, self.sprite.cel_width,
self.sprite.cel_height)
stroke = (0, 0, 0)
context.set_source_rgb(*stroke)
context.stroke()
"""
self.sprite.draw(context, dx, dy)
context.restore()
def draw(dr, ctx, character):
character.draw(ctx)
def main():
def _destroy_cb(widget, data=None):
Gtk.main_quit()
window = Gtk.Window()
window.resize(600, 160)
window.connect("destroy", _destroy_cb)
dr = Gtk.DrawingArea()
character = Character(dr)
character.pos = [style.GRID_CELL_SIZE, 140]
dr.connect('draw', draw, character)
window.add(dr)
window.show_all()
Gtk.main()
if __name__ == "__main__":
main()
|