├── .gitignore ├── README.md ├── pyguts ├── MANIFEST.in ├── examples │ ├── data │ │ ├── dragon.atlas │ │ ├── dragon.json │ │ ├── dragon.png │ │ ├── dragon2.png │ │ ├── goblins.atlas │ │ ├── goblins.json │ │ ├── goblins.png │ │ ├── goblins2.png │ │ ├── powerup.atlas │ │ ├── powerup.json │ │ ├── powerup.png │ │ ├── spineboy.atlas │ │ ├── spineboy.json │ │ ├── spineboy.png │ │ ├── spineboy2.atlas │ │ ├── spineboy2.png │ │ ├── spinosaurus.atlas │ │ ├── spinosaurus.json │ │ └── spinosaurus.png │ ├── dragon_pygame.py │ ├── goblins_pygame.py │ ├── mix_pygame.py │ ├── powerup_pygame.py │ ├── spine_pygame.py │ └── spinosaurus_pygame.py ├── setup.py └── src │ ├── Atlas.py │ ├── AtlasAttachmentLoader.py │ ├── RegionAttachment.py │ ├── Skeleton.py │ └── __init__.py └── spine-python ├── setup.py └── src ├── Animation ├── Timeline.py └── __init__.py ├── Atlas ├── AtlasPage.py ├── AtlasRegion.py └── __init__.py ├── Attachment.py ├── AttachmentLoader.py ├── Bone.py ├── BoneData.py ├── Enum.py ├── RegionAttachment.py ├── Skeleton.py ├── SkeletonData.py ├── SkeletonJson.py ├── Skin.py ├── Slot.py ├── SlotData.py └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | 4 | *.pyc 5 | 6 | *.py~ 7 | 8 | *.py# 9 | 10 | pycallgraph.png 11 | 12 | *.atlas~ 13 | 14 | *.json~ 15 | 16 | pyguts/spine/#Bone# 17 | 18 | sword_pygame.py 19 | 20 | pyguts/ImageAttachmentLoader.py 21 | 22 | data/sword-skeleton.json 23 | 24 | data/sword-animation.json 25 | 26 | data/Star.png 27 | 28 | data/Hilt.png 29 | 30 | data/Blade.png 31 | 32 | data/sword-stars.json 33 | 34 | data/sword.atlas 35 | 36 | data/sword.png 37 | 38 | data/sword/Blade.png 39 | 40 | data/sword/Hilt.png 41 | 42 | data/sword/Star.png 43 | 44 | spine_and_sword.py 45 | 46 | build/pip-delete-this-directory.txt 47 | 48 | pyguts/examples/data/sword-skeleton.json 49 | 50 | pyguts/examples/data/sword-stars.json 51 | 52 | pyguts/examples/data/sword.atlas 53 | 54 | pyguts/examples/data/sword.png 55 | 56 | pyguts/examples/data/sword/Blade.png 57 | 58 | pyguts/examples/data/sword/Hilt.png 59 | 60 | pyguts/examples/data/sword/Star.png 61 | 62 | *.md~ 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | spine-python 2 | ============ 3 | 4 | A Pure Python implementation of the Esoteric Software Spine runtime for pygame. 5 | 6 | Check the pyguts/examples directory for instructions on using the API. -------------------------------------------------------------------------------- /pyguts/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include examples * 2 | -------------------------------------------------------------------------------- /pyguts/examples/data/dragon.atlas: -------------------------------------------------------------------------------- 1 | 2 | data/dragon.png 3 | format: RGBA8888 4 | filter: Nearest,Nearest 5 | repeat: none 6 | template 7 | rotate: false 8 | xy: 1, 575 9 | size: 671, 443 10 | orig: 671, 443 11 | offset: 0, 0 12 | index: -1 13 | logo 14 | rotate: false 15 | xy: 1, 481 16 | size: 897, 92 17 | orig: 897, 92 18 | offset: 0, 0 19 | index: -1 20 | R_wing06 21 | rotate: false 22 | xy: 1, 113 23 | size: 200, 366 24 | orig: 200, 366 25 | offset: 0, 0 26 | index: -1 27 | head 28 | rotate: false 29 | xy: 674, 758 30 | size: 296, 260 31 | orig: 296, 260 32 | offset: 0, 0 33 | index: -1 34 | R_wing01 35 | rotate: false 36 | xy: 203, 169 37 | size: 219, 310 38 | orig: 219, 310 39 | offset: 0, 0 40 | index: -1 41 | R_wing03 42 | rotate: false 43 | xy: 424, 232 44 | size: 272, 247 45 | orig: 272, 247 46 | offset: 0, 0 47 | index: -1 48 | L_wing08 49 | rotate: false 50 | xy: 674, 575 51 | size: 164, 181 52 | orig: 164, 181 53 | offset: 0, 0 54 | index: -1 55 | R_wing02 56 | rotate: false 57 | xy: 698, 174 58 | size: 203, 305 59 | orig: 203, 305 60 | offset: 0, 0 61 | index: -1 62 | R_wing05 63 | rotate: false 64 | xy: 424, 1 65 | size: 251, 229 66 | orig: 251, 229 67 | offset: 0, 0 68 | index: -1 69 | L_wing09 70 | rotate: false 71 | xy: 677, 5 72 | size: 204, 167 73 | orig: 204, 167 74 | offset: 0, 0 75 | index: -1 76 | tail01 77 | rotate: false 78 | xy: 840, 603 79 | size: 120, 153 80 | orig: 120, 153 81 | offset: 0, 0 82 | index: -1 83 | chin 84 | rotate: false 85 | xy: 203, 21 86 | size: 214, 146 87 | orig: 214, 146 88 | offset: 0, 0 89 | index: -1 90 | R_front_thigh 91 | rotate: false 92 | xy: 1, 3 93 | size: 108, 108 94 | orig: 108, 108 95 | offset: 0, 0 96 | index: -1 97 | L_rear_thigh 98 | rotate: false 99 | xy: 883, 23 100 | size: 91, 149 101 | orig: 91, 149 102 | offset: 0, 0 103 | index: -1 104 | tail03 105 | rotate: false 106 | xy: 111, 19 107 | size: 73, 92 108 | orig: 73, 92 109 | offset: 0, 0 110 | index: -1 111 | tail02 112 | rotate: false 113 | xy: 900, 481 114 | size: 95, 120 115 | orig: 95, 120 116 | offset: 0, 0 117 | index: -1 118 | R_rear_thigh 119 | rotate: false 120 | xy: 903, 330 121 | size: 91, 149 122 | orig: 91, 149 123 | offset: 0, 0 124 | index: -1 125 | R_rear_leg 126 | rotate: false 127 | xy: 903, 228 128 | size: 116, 100 129 | orig: 116, 100 130 | offset: 0, 0 131 | index: -1 132 | front_toeA 133 | rotate: false 134 | xy: 972, 968 135 | size: 29, 50 136 | orig: 29, 50 137 | offset: 0, 0 138 | index: -1 139 | tail04 140 | rotate: false 141 | xy: 962, 685 142 | size: 56, 71 143 | orig: 56, 71 144 | offset: 0, 0 145 | index: -1 146 | front_toeB 147 | rotate: false 148 | xy: 962, 626 149 | size: 56, 57 150 | orig: 56, 57 151 | offset: 0, 0 152 | index: -1 153 | 154 | data/dragon2.png 155 | format: RGBA8888 156 | filter: Nearest,Nearest 157 | repeat: none 158 | L_wing06 159 | rotate: false 160 | xy: 1, 674 161 | size: 192, 331 162 | orig: 192, 331 163 | offset: 0, 0 164 | index: -1 165 | R_wing08 166 | rotate: false 167 | xy: 195, 751 168 | size: 234, 254 169 | orig: 234, 254 170 | offset: 0, 0 171 | index: -1 172 | R_wing07 173 | rotate: false 174 | xy: 1, 409 175 | size: 200, 263 176 | orig: 200, 263 177 | offset: 0, 0 178 | index: -1 179 | R_wing09 180 | rotate: false 181 | xy: 431, 801 182 | size: 248, 204 183 | orig: 248, 204 184 | offset: 0, 0 185 | index: -1 186 | L_wing02 187 | rotate: false 188 | xy: 1, 138 189 | size: 179, 269 190 | orig: 179, 269 191 | offset: 0, 0 192 | index: -1 193 | R_wing04 194 | rotate: false 195 | xy: 681, 861 196 | size: 279, 144 197 | orig: 279, 144 198 | offset: 0, 0 199 | index: -1 200 | L_wing01 201 | rotate: false 202 | xy: 203, 493 203 | size: 191, 256 204 | orig: 191, 256 205 | offset: 0, 0 206 | index: -1 207 | L_wing04 208 | rotate: false 209 | xy: 1, 1 210 | size: 188, 135 211 | orig: 188, 135 212 | offset: 0, 0 213 | index: -1 214 | L_wing07 215 | rotate: false 216 | xy: 396, 494 217 | size: 159, 255 218 | orig: 159, 255 219 | offset: 0, 0 220 | index: -1 221 | L_wing05 222 | rotate: false 223 | xy: 557, 586 224 | size: 218, 213 225 | orig: 218, 213 226 | offset: 0, 0 227 | index: -1 228 | L_wing03 229 | rotate: false 230 | xy: 777, 652 231 | size: 186, 207 232 | orig: 186, 207 233 | offset: 0, 0 234 | index: -1 235 | L_rear_leg 236 | rotate: false 237 | xy: 557, 407 238 | size: 206, 177 239 | orig: 206, 177 240 | offset: 0, 0 241 | index: -1 242 | back 243 | rotate: false 244 | xy: 203, 306 245 | size: 190, 185 246 | orig: 190, 185 247 | offset: 0, 0 248 | index: -1 249 | chest 250 | rotate: false 251 | xy: 182, 182 252 | size: 136, 122 253 | orig: 136, 122 254 | offset: 0, 0 255 | index: -1 256 | rear-toe 257 | rotate: false 258 | xy: 777, 573 259 | size: 109, 77 260 | orig: 109, 77 261 | offset: 0, 0 262 | index: -1 263 | R_front_leg 264 | rotate: false 265 | xy: 765, 482 266 | size: 101, 89 267 | orig: 101, 89 268 | offset: 0, 0 269 | index: -1 270 | tail06 271 | rotate: false 272 | xy: 765, 412 273 | size: 95, 68 274 | orig: 95, 68 275 | offset: 0, 0 276 | index: -1 277 | L_front_thigh 278 | rotate: false 279 | xy: 888, 578 280 | size: 84, 72 281 | orig: 84, 72 282 | offset: 0, 0 283 | index: -1 284 | L_front_leg 285 | rotate: false 286 | xy: 681, 802 287 | size: 84, 57 288 | orig: 84, 57 289 | offset: 0, 0 290 | index: -1 291 | tail05 292 | rotate: false 293 | xy: 962, 946 294 | size: 52, 59 295 | orig: 52, 59 296 | offset: 0, 0 297 | index: -1 298 | -------------------------------------------------------------------------------- /pyguts/examples/data/dragon.json: -------------------------------------------------------------------------------- 1 | { 2 | "bones": [ 3 | { "name": "root", "y": -176.12 }, 4 | { "name": "COG", "parent": "root", "y": 176.12 }, 5 | { "name": "neck", "parent": "COG", "length": 41.36, "x": 64.75, "y": 11.98, "rotation": 39.05 }, 6 | { "name": "back", "parent": "COG", "length": 115.37, "x": 16.03, "y": 27.94, "rotation": 151.83 }, 7 | { "name": "chest", "parent": "COG", "length": 31.24, "x": 52.52, "y": 15.34, "rotation": 161.7 }, 8 | { "name": "head", "parent": "neck", "length": 188.83, "x": 69.96, "y": 2.49, "rotation": 8.06 }, 9 | { "name": "chin", "parent": "neck", "length": 153.15, "x": 64.62, "y": -6.99, "rotation": -69.07 }, 10 | { "name": "R_wing", "parent": "head", "length": 359.5, "x": -74.68, "y": 20.9, "rotation": 83.21 }, 11 | { "name": "tail1", "parent": "back", "length": 65.65, "x": 115.37, "y": -0.19, "rotation": 44.31 }, 12 | { "name": "R_rear_thigh", "parent": "back", "length": 123.46, "x": 65.31, "y": 59.89, "rotation": 104.87 }, 13 | { "name": "tail2", "parent": "tail1", "length": 54.5, "x": 65.65, "y": 0.22, "rotation": 12 }, 14 | { "name": "tail3", "parent": "tail2", "length": 41.78, "x": 54.5, "y": 0.37, "rotation": 1.8 }, 15 | { "name": "tail4", "parent": "tail3", "length": 34.19, "x": 41.78, "y": 0.16, "rotation": -1.8 }, 16 | { "name": "tail5", "parent": "tail4", "length": 32.32, "x": 34.19, "y": -0.19, "rotation": -3.15 }, 17 | { "name": "tail6", "parent": "tail5", "length": 80.08, "x": 32.32, "y": -0.23, "rotation": -29.55 }, 18 | { "name": "L_rear_thigh", "parent": "R_rear_thigh", "length": 88.05, "x": -8.59, "y": 30.18, "rotation": 28.35 }, 19 | { "name": "R_rear_leg", "parent": "R_rear_thigh", "length": 91.06, "x": 123.46, "y": -0.26, "rotation": -129.04 }, 20 | { "name": "L_rear_leg", "parent": "L_rear_thigh", "length": 103.74, "x": 96.04, "y": -0.97, "rotation": -122.41 }, 21 | { "name": "R_rear_toe3", "parent": "R_rear_leg", "length": 103.45, "x": 91.06, "y": -0.35, "rotation": 112.26 }, 22 | { "name": "R_rear_toe2", "parent": "R_rear_leg", "length": 99.29, "x": 89.6, "y": 1.52, "rotation": 125.32 }, 23 | { "name": "R_rear_toe1", "parent": "R_rear_leg", "length": 94.99, "x": 90.06, "y": 2.12, "rotation": 141.98 }, 24 | { "name": "L_wing", "parent": "chest", "length": 301.12, "x": -7.24, "y": -24.65, "rotation": -75.51 }, 25 | { "name": "L_front_thigh", "parent": "chest", "length": 67.42, "x": -45.58, "y": 7.92, "rotation": 138.94 }, 26 | { "name": "R_front_thigh", "parent": "chest", "length": 81.63, "x": -10.89, "y": 28.25, "rotation": 67.96 }, 27 | { "name": "L_front_leg", "parent": "L_front_thigh", "length": 51.57, "x": 67.42, "y": 0.02, "rotation": 43.36 }, 28 | { "name": "L_front_toe1", "parent": "L_front_leg", "length": 51.44, "x": 45.53, "y": 2.43, "rotation": -98 }, 29 | { "name": "L_front_toe2", "parent": "L_front_leg", "length": 61.97, "x": 51.57, "y": -0.12, "rotation": -55.26 }, 30 | { "name": "L_front_toe4", "parent": "L_front_leg", "length": 53.47, "x": 50.6, "y": 7.08, "scaleX": 1.134, "rotation": 19.42 }, 31 | { "name": "L_front_toe3", "parent": "L_front_leg", "length": 45.65, "x": 54.19, "y": 0.6, "scaleX": 1.134, "rotation": -11.13 }, 32 | { "name": "R_front_leg", "parent": "R_front_thigh", "length": 66.52, "x": 83.04, "y": -0.3, "rotation": 92.7 }, 33 | { "name": "R_front_toe1", "parent": "R_front_leg", "length": 46.65, "x": 70.03, "y": 5.31, "rotation": 8.59 }, 34 | { "name": "R_front_toe2", "parent": "R_front_leg", "length": 53.66, "x": 66.52, "y": 0.33, "rotation": -35.02 }, 35 | { "name": "R_front_toe3", "parent": "R_front_leg", "length": 58.38, "x": 62.1, "y": -0.79, "rotation": -74.67 } 36 | ], 37 | "slots": [ 38 | { "name": "L_rear_leg", "bone": "L_rear_leg", "attachment": "L_rear_leg" }, 39 | { "name": "L_rear_thigh", "bone": "L_rear_thigh", "attachment": "L_rear_thigh" }, 40 | { "name": "L_wing", "bone": "L_wing", "attachment": "L_wing01" }, 41 | { "name": "tail6", "bone": "tail6", "attachment": "tail06" }, 42 | { "name": "tail5", "bone": "tail5", "attachment": "tail05" }, 43 | { "name": "tail4", "bone": "tail4", "attachment": "tail04" }, 44 | { "name": "tail3", "bone": "tail3", "attachment": "tail03" }, 45 | { "name": "tail2", "bone": "tail2", "attachment": "tail02" }, 46 | { "name": "tail1", "bone": "tail1", "attachment": "tail01" }, 47 | { "name": "back", "bone": "back", "attachment": "back" }, 48 | { "name": "L_front_thigh", "bone": "L_front_thigh", "attachment": "L_front_thigh" }, 49 | { "name": "L_front_leg", "bone": "L_front_leg", "attachment": "L_front_leg" }, 50 | { "name": "L_front_toe1", "bone": "L_front_toe1", "attachment": "front_toeA" }, 51 | { "name": "L_front_toe4", "bone": "L_front_toe4", "attachment": "front_toeB" }, 52 | { "name": "L_front_toe3", "bone": "L_front_toe3", "attachment": "front_toeB" }, 53 | { "name": "L_front_toe2", "bone": "L_front_toe2", "attachment": "front_toeB" }, 54 | { "name": "chest", "bone": "chest", "attachment": "chest" }, 55 | { "name": "R_rear_toe1", "bone": "R_rear_toe1", "attachment": "rear-toe" }, 56 | { "name": "R_rear_toe2", "bone": "R_rear_toe2", "attachment": "rear-toe" }, 57 | { "name": "R_rear_toe3", "bone": "R_rear_toe3", "attachment": "rear-toe" }, 58 | { "name": "R_rear_leg", "bone": "R_rear_leg", "attachment": "R_rear_leg" }, 59 | { "name": "R_rear_thigh", "bone": "R_rear_thigh", "attachment": "R_rear_thigh" }, 60 | { "name": "R_front_toe1", "bone": "R_front_toe1", "attachment": "front_toeB" }, 61 | { "name": "R_front_thigh", "bone": "R_front_thigh", "attachment": "R_front_thigh" }, 62 | { "name": "R_front_leg", "bone": "R_front_leg", "attachment": "R_front_leg" }, 63 | { "name": "R_front_toe2", "bone": "R_front_toe2", "attachment": "front_toeB" }, 64 | { "name": "R_front_toe3", "bone": "R_front_toe3", "attachment": "front_toeB" }, 65 | { "name": "chin", "bone": "chin", "attachment": "chin" }, 66 | { "name": "R_wing", "bone": "R_wing", "attachment": "R_wing01" }, 67 | { "name": "head", "bone": "head", "attachment": "head" }, 68 | { "name": "logo", "bone": "root", "attachment": "logo" } 69 | ], 70 | "skins": { 71 | "default": { 72 | "L_rear_leg": { 73 | "L_rear_leg": { "x": 67.29, "y": 12.62, "rotation": -162.65, "width": 206, "height": 177 } 74 | }, 75 | "L_rear_thigh": { 76 | "L_rear_thigh": { "x": 56.03, "y": 27.38, "rotation": 74.93, "width": 91, "height": 149 } 77 | }, 78 | "L_wing": { 79 | "L_wing01": { "x": 129.21, "y": -45.49, "rotation": -83.7, "width": 191, "height": 256 }, 80 | "L_wing02": { "x": 126.37, "y": -31.69, "rotation": -86.18, "width": 179, "height": 269 }, 81 | "L_wing03": { "x": 110.26, "y": -90.89, "rotation": -86.18, "width": 186, "height": 207 }, 82 | "L_wing04": { "x": -61.61, "y": -83.26, "rotation": -86.18, "width": 188, "height": 135 }, 83 | "L_wing05": { "x": -90.01, "y": -78.14, "rotation": -86.18, "width": 218, "height": 213 }, 84 | "L_wing06": { "x": -143.76, "y": -83.71, "rotation": -86.18, "width": 192, "height": 331 }, 85 | "L_wing07": { "x": -133.04, "y": -33.89, "rotation": -86.18, "width": 159, "height": 255 }, 86 | "L_wing08": { "x": 50.15, "y": -15.71, "rotation": -86.18, "width": 164, "height": 181 }, 87 | "L_wing09": { "x": 85.94, "y": -11.32, "rotation": -86.18, "width": 204, "height": 167 } 88 | }, 89 | "tail6": { 90 | "tail06": { "x": 28.02, "y": -16.83, "rotation": -175.44, "width": 95, "height": 68 } 91 | }, 92 | "tail5": { 93 | "tail05": { "x": 15.05, "y": -3.57, "rotation": 155, "width": 52, "height": 59 } 94 | }, 95 | "tail4": { 96 | "tail04": { "x": 15.34, "y": -2.17, "rotation": 151.84, "width": 56, "height": 71 } 97 | }, 98 | "tail3": { 99 | "tail03": { "x": 16.94, "y": -2, "rotation": 150.04, "width": 73, "height": 92 } 100 | }, 101 | "tail2": { 102 | "tail02": { "x": 18.11, "y": -1.75, "rotation": 151.84, "width": 95, "height": 120 } 103 | }, 104 | "tail1": { 105 | "tail01": { "x": 22.59, "y": -4.5, "rotation": 163.85, "width": 120, "height": 153 } 106 | }, 107 | "back": { 108 | "back": { "x": 35.84, "y": 19.99, "rotation": -151.83, "width": 190, "height": 185 } 109 | }, 110 | "L_front_thigh": { 111 | "L_front_thigh": { "x": 27.66, "y": -11.58, "rotation": 58.66, "width": 84, "height": 72 } 112 | }, 113 | "L_front_leg": { 114 | "L_front_leg": { "x": 14.68, "y": 0.48, "rotation": 15.99, "width": 84, "height": 57 } 115 | }, 116 | "L_front_toe1": { 117 | "front_toeA": { "x": 31.92, "y": 0.61, "rotation": 109.55, "width": 29, "height": 50 } 118 | }, 119 | "L_front_toe4": { 120 | "front_toeB": { "x": 23.21, "y": -11.68, "scaleX": 0.881, "rotation": 79.89, "width": 56, "height": 57 } 121 | }, 122 | "L_front_toe3": { 123 | "front_toeB": { "x": 18.21, "y": -7.21, "scaleX": 0.881, "scaleY": 0.94, "rotation": 99.71, "width": 56, "height": 57 } 124 | }, 125 | "L_front_toe2": { 126 | "front_toeB": { "x": 26.83, "y": -4.94, "rotation": 109.51, "width": 56, "height": 57 } 127 | }, 128 | "chest": { 129 | "chest": { "x": -14.6, "y": 24.78, "rotation": -161.7, "width": 136, "height": 122 } 130 | }, 131 | "R_rear_toe1": { 132 | "rear-toe": { "x": 54.75, "y": -5.72, "rotation": 134.79, "width": 109, "height": 77 } 133 | }, 134 | "R_rear_toe2": { 135 | "rear-toe": { "x": 57.02, "y": -7.22, "rotation": 134.42, "width": 109, "height": 77 } 136 | }, 137 | "R_rear_toe3": { 138 | "rear-toe": { "x": 47.46, "y": -7.64, "rotation": 134.34, "width": 109, "height": 77 } 139 | }, 140 | "R_rear_leg": { 141 | "R_rear_leg": { "x": 60.87, "y": -5.72, "rotation": -127.66, "width": 116, "height": 100 } 142 | }, 143 | "R_rear_thigh": { 144 | "R_rear_thigh": { "x": 53.25, "y": 12.58, "rotation": 103.29, "width": 91, "height": 149 } 145 | }, 146 | "R_front_toe1": { 147 | "front_toeB": { "x": 24.49, "y": -2.61, "rotation": 104.18, "width": 56, "height": 57 } 148 | }, 149 | "R_front_thigh": { 150 | "R_front_thigh": { "x": 35.28, "y": 2.11, "rotation": 130.33, "width": 108, "height": 108 } 151 | }, 152 | "R_front_leg": { 153 | "R_front_leg": { "x": 17.79, "y": 4.22, "rotation": 37.62, "width": 101, "height": 89 } 154 | }, 155 | "R_front_toe2": { 156 | "front_toeB": { "x": 26.39, "y": 1.16, "rotation": 104.57, "width": 56, "height": 57 } 157 | }, 158 | "R_front_toe3": { 159 | "front_toeB": { "x": 30.66, "y": -0.06, "rotation": 112.29, "width": 56, "height": 57 } 160 | }, 161 | "chin": { 162 | "chin": { "x": 66.55, "y": 7.32, "rotation": 30.01, "width": 214, "height": 146 } 163 | }, 164 | "R_wing": { 165 | "R_wing01": { "x": 170.08, "y": -23.67, "rotation": -130.33, "width": 219, "height": 310 }, 166 | "R_wing02": { "x": 171.14, "y": -19.33, "rotation": -130.33, "width": 203, "height": 305 }, 167 | "R_wing03": { "x": 166.46, "y": 29.23, "rotation": -130.33, "width": 272, "height": 247 }, 168 | "R_wing04": { "x": 42.94, "y": 134.05, "rotation": -130.33, "width": 279, "height": 144 }, 169 | "R_wing05": { "x": -8.83, "y": 142.59, "rotation": -130.33, "width": 251, "height": 229 }, 170 | "R_wing06": { "x": -123.33, "y": 111.22, "rotation": -130.33, "width": 200, "height": 366 }, 171 | "R_wing07": { "x": -40.17, "y": 118.03, "rotation": -130.33, "width": 200, "height": 263 }, 172 | "R_wing08": { "x": 48.01, "y": 28.76, "rotation": -130.33, "width": 234, "height": 254 }, 173 | "R_wing09": { "x": 128.1, "y": 21.12, "rotation": -130.33, "width": 248, "height": 204 } 174 | }, 175 | "head": { 176 | "head": { "x": 76.68, "y": 32.21, "rotation": -47.12, "width": 296, "height": 260 } 177 | }, 178 | "logo": { 179 | "logo": { "y": -176.72, "width": 897, "height": 92 } 180 | } 181 | } 182 | }, 183 | "animations": { 184 | "flying": { 185 | "bones": { 186 | "back": { 187 | "rotate": [ 188 | { "time": 0, "angle": 0 }, 189 | { "time": 0.1666, "angle": 17.39 }, 190 | { "time": 0.5, "angle": 0 }, 191 | { "time": 0.8333, "angle": 7 }, 192 | { "time": 1, "angle": 0 } 193 | ], 194 | "translate": [ 195 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 196 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 197 | { "time": 1, "x": 0, "y": 0 } 198 | ], 199 | "scale": [ 200 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 201 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 202 | { "time": 1, "x": 1, "y": 1 } 203 | ] 204 | }, 205 | "neck": { 206 | "rotate": [ 207 | { "time": 0, "angle": 0 }, 208 | { "time": 0.1666, "angle": -8.18 }, 209 | { "time": 0.3333, "angle": -23.16 }, 210 | { "time": 0.5, "angle": -18.01 }, 211 | { "time": 1, "angle": 0 } 212 | ], 213 | "translate": [ 214 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 215 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 216 | { "time": 1, "x": 0, "y": 0 } 217 | ], 218 | "scale": [ 219 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 220 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 221 | { "time": 1, "x": 1, "y": 1 } 222 | ] 223 | }, 224 | "chest": { 225 | "rotate": [ 226 | { "time": 0, "angle": 0, "curve": "stepped" }, 227 | { "time": 0.5, "angle": 0, "curve": "stepped" }, 228 | { "time": 1, "angle": 0 } 229 | ], 230 | "translate": [ 231 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 232 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 233 | { "time": 1, "x": 0, "y": 0 } 234 | ], 235 | "scale": [ 236 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 237 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 238 | { "time": 1, "x": 1, "y": 1 } 239 | ] 240 | }, 241 | "tail1": { 242 | "rotate": [ 243 | { "time": 0, "angle": 0 }, 244 | { "time": 0.1666, "angle": -2.42 }, 245 | { "time": 0.3333, "angle": -26.2 }, 246 | { "time": 0.5, "angle": -29.65 }, 247 | { "time": 0.6666, "angle": -23.15 }, 248 | { "time": 0.8333, "angle": -55.46 }, 249 | { "time": 1, "angle": 0 } 250 | ], 251 | "translate": [ 252 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 253 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 254 | { "time": 1, "x": 0, "y": 0 } 255 | ], 256 | "scale": [ 257 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 258 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 259 | { "time": 1, "x": 1, "y": 1 } 260 | ] 261 | }, 262 | "R_rear_thigh": { 263 | "rotate": [ 264 | { "time": 0, "angle": 0, "curve": "stepped" }, 265 | { "time": 0.5, "angle": 0, "curve": "stepped" }, 266 | { "time": 1, "angle": 0 } 267 | ], 268 | "translate": [ 269 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 270 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 271 | { "time": 1, "x": 0, "y": 0 } 272 | ], 273 | "scale": [ 274 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 275 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 276 | { "time": 1, "x": 1, "y": 1 } 277 | ] 278 | }, 279 | "tail2": { 280 | "rotate": [ 281 | { "time": 0, "angle": 0 }, 282 | { "time": 0.1666, "angle": -1.12 }, 283 | { "time": 0.3333, "angle": 10.48 }, 284 | { "time": 0.5, "angle": 7.89 }, 285 | { "time": 0.8333, "angle": -10.38 }, 286 | { "time": 1, "angle": 0 } 287 | ], 288 | "translate": [ 289 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 290 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 291 | { "time": 1, "x": 0, "y": 0 } 292 | ], 293 | "scale": [ 294 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 295 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 296 | { "time": 1, "x": 1, "y": 1 } 297 | ] 298 | }, 299 | "tail3": { 300 | "rotate": [ 301 | { "time": 0, "angle": 0 }, 302 | { "time": 0.1666, "angle": 8.24 }, 303 | { "time": 0.3333, "angle": 15.21 }, 304 | { "time": 0.5, "angle": 14.84 }, 305 | { "time": 0.8333, "angle": -18.9 }, 306 | { "time": 1, "angle": 0 } 307 | ], 308 | "translate": [ 309 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 310 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 311 | { "time": 1, "x": 0, "y": 0 } 312 | ], 313 | "scale": [ 314 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 315 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 316 | { "time": 1, "x": 1, "y": 1 } 317 | ] 318 | }, 319 | "tail4": { 320 | "rotate": [ 321 | { "time": 0, "angle": 0 }, 322 | { "time": 0.1666, "angle": 17.46 }, 323 | { "time": 0.3333, "angle": 22.15 }, 324 | { "time": 0.5, "angle": 22.76 }, 325 | { "time": 0.8333, "angle": -4.37 }, 326 | { "time": 1, "angle": 0 } 327 | ], 328 | "translate": [ 329 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 330 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 331 | { "time": 1, "x": 0, "y": 0 } 332 | ], 333 | "scale": [ 334 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 335 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 336 | { "time": 1, "x": 1, "y": 1 } 337 | ] 338 | }, 339 | "tail5": { 340 | "rotate": [ 341 | { "time": 0, "angle": 0 }, 342 | { "time": 0.1666, "angle": 7.4 }, 343 | { "time": 0.3333, "angle": 28.5 }, 344 | { "time": 0.5, "angle": 21.33 }, 345 | { "time": 0.8333, "angle": -1.27 }, 346 | { "time": 1, "angle": 0 } 347 | ], 348 | "translate": [ 349 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 350 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 351 | { "time": 1, "x": 0, "y": 0 } 352 | ], 353 | "scale": [ 354 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 355 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 356 | { "time": 1, "x": 1, "y": 1 } 357 | ] 358 | }, 359 | "tail6": { 360 | "rotate": [ 361 | { "time": 0, "angle": 0 }, 362 | { "time": 0.1666, "angle": 45.99 }, 363 | { "time": 0.4, "angle": 43.53 }, 364 | { "time": 0.5, "angle": 61.79 }, 365 | { "time": 0.8333, "angle": 13.28 }, 366 | { "time": 1, "angle": 0 } 367 | ], 368 | "translate": [ 369 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 370 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 371 | { "time": 1, "x": 0, "y": 0 } 372 | ], 373 | "scale": [ 374 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 375 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 376 | { "time": 1, "x": 1, "y": 1 } 377 | ] 378 | }, 379 | "R_rear_leg": { 380 | "rotate": [ 381 | { "time": 0, "angle": 0 }, 382 | { "time": 0.1666, "angle": -14.21 }, 383 | { "time": 0.5, "angle": 47.17 }, 384 | { "time": 1, "angle": 0 } 385 | ], 386 | "translate": [ 387 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 388 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 389 | { "time": 1, "x": 0, "y": 0 } 390 | ], 391 | "scale": [ 392 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 393 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 394 | { "time": 1, "x": 1, "y": 1 } 395 | ] 396 | }, 397 | "R_rear_toe3": { 398 | "rotate": [ 399 | { "time": 0, "angle": 0 }, 400 | { "time": 0.5, "angle": -36.06 }, 401 | { "time": 1, "angle": 0 } 402 | ], 403 | "translate": [ 404 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 405 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 406 | { "time": 1, "x": 0, "y": 0 } 407 | ], 408 | "scale": [ 409 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 410 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 411 | { "time": 1, "x": 1, "y": 1 } 412 | ] 413 | }, 414 | "R_rear_toe2": { 415 | "rotate": [ 416 | { "time": 0, "angle": 0 }, 417 | { "time": 0.5, "angle": -20.32 }, 418 | { "time": 1, "angle": 0 } 419 | ], 420 | "translate": [ 421 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 422 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 423 | { "time": 1, "x": 0, "y": 0 } 424 | ], 425 | "scale": [ 426 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 427 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 428 | { "time": 1, "x": 1, "y": 1 } 429 | ] 430 | }, 431 | "R_rear_toe1": { 432 | "rotate": [ 433 | { "time": 0, "angle": 0 }, 434 | { "time": 0.5, "angle": -18.71 }, 435 | { "time": 1, "angle": 0 } 436 | ], 437 | "translate": [ 438 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 439 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 440 | { "time": 1, "x": 0, "y": 0 } 441 | ], 442 | "scale": [ 443 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 444 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 445 | { "time": 1, "x": 1, "y": 1 } 446 | ] 447 | }, 448 | "head": { 449 | "rotate": [ 450 | { 451 | "time": 0, 452 | "angle": 0, 453 | "curve": [ 0.408, 1.36, 0.675, 1.43 ] 454 | }, 455 | { "time": 0.5, "angle": 1.03 }, 456 | { "time": 1, "angle": 0 } 457 | ], 458 | "translate": [ 459 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 460 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 461 | { "time": 1, "x": 0, "y": 0 } 462 | ], 463 | "scale": [ 464 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 465 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 466 | { "time": 1, "x": 1, "y": 1 } 467 | ] 468 | }, 469 | "chin": { 470 | "rotate": [ 471 | { 472 | "time": 0, 473 | "angle": 0, 474 | "curve": [ 0.416, 1.15, 0.494, 1.27 ] 475 | }, 476 | { "time": 0.3333, "angle": -5.15 }, 477 | { "time": 0.5, "angle": 9.79 }, 478 | { "time": 0.6666, "angle": 18.94 }, 479 | { "time": 1, "angle": 0 } 480 | ], 481 | "translate": [ 482 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 483 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 484 | { "time": 1, "x": 0, "y": 0 } 485 | ], 486 | "scale": [ 487 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 488 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 489 | { "time": 1, "x": 1, "y": 1 } 490 | ] 491 | }, 492 | "L_front_thigh": { 493 | "rotate": [ 494 | { "time": 0, "angle": 0 }, 495 | { "time": 0.1666, "angle": -19.18 }, 496 | { "time": 0.3333, "angle": -32.02 }, 497 | { "time": 0.5, "angle": -19.62 }, 498 | { "time": 1, "angle": 0 } 499 | ], 500 | "translate": [ 501 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 502 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 503 | { "time": 1, "x": 0, "y": 0 } 504 | ], 505 | "scale": [ 506 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 507 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 508 | { "time": 1, "x": 1, "y": 1 } 509 | ] 510 | }, 511 | "R_front_thigh": { 512 | "rotate": [ 513 | { "time": 0, "angle": 0 }, 514 | { "time": 0.1666, "angle": -12.96 }, 515 | { "time": 0.5, "angle": 16.2 }, 516 | { "time": 1, "angle": 0 } 517 | ], 518 | "translate": [ 519 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 520 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 521 | { "time": 1, "x": 0, "y": 0 } 522 | ], 523 | "scale": [ 524 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 525 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 526 | { "time": 1, "x": 1, "y": 1 } 527 | ] 528 | }, 529 | "L_front_leg": { 530 | "rotate": [ 531 | { "time": 0, "angle": 0 }, 532 | { "time": 0.1666, "angle": 37.77 }, 533 | { "time": 0.5, "angle": 0, "curve": "stepped" }, 534 | { "time": 1, "angle": 0 } 535 | ], 536 | "translate": [ 537 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 538 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 539 | { "time": 1, "x": 0, "y": 0 } 540 | ], 541 | "scale": [ 542 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 543 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 544 | { "time": 1, "x": 1, "y": 1 } 545 | ] 546 | }, 547 | "L_front_toe1": { 548 | "rotate": [ 549 | { "time": 0, "angle": 0 }, 550 | { "time": 0.1666, "angle": -16.08 }, 551 | { "time": 0.5, "angle": 0, "curve": "stepped" }, 552 | { "time": 1, "angle": 0 } 553 | ], 554 | "translate": [ 555 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 556 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 557 | { "time": 1, "x": 0, "y": 0 } 558 | ], 559 | "scale": [ 560 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 561 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 562 | { "time": 1, "x": 1, "y": 1 } 563 | ] 564 | }, 565 | "L_front_toe2": { 566 | "rotate": [ 567 | { "time": 0, "angle": 0, "curve": "stepped" }, 568 | { "time": 0.5, "angle": 0, "curve": "stepped" }, 569 | { "time": 1, "angle": 0 } 570 | ], 571 | "translate": [ 572 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 573 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 574 | { "time": 1, "x": 0, "y": 0 } 575 | ], 576 | "scale": [ 577 | { "time": 0, "x": 1, "y": 1 }, 578 | { "time": 0.5, "x": 1.33, "y": 1.029 }, 579 | { "time": 1, "x": 1, "y": 1 } 580 | ] 581 | }, 582 | "L_front_toe4": { 583 | "rotate": [ 584 | { "time": 0, "angle": 0 }, 585 | { "time": 0.5, "angle": 26.51 }, 586 | { "time": 1, "angle": 0 } 587 | ], 588 | "translate": [ 589 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 590 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 591 | { "time": 1, "x": 0, "y": 0 } 592 | ], 593 | "scale": [ 594 | { "time": 0, "x": 1, "y": 1 }, 595 | { "time": 0.5, "x": 1.239, "y": 0.993 }, 596 | { "time": 1, "x": 1, "y": 1 } 597 | ] 598 | }, 599 | "L_front_toe3": { 600 | "rotate": [ 601 | { "time": 0, "angle": 0 }, 602 | { "time": 0.5, "angle": 16.99 }, 603 | { "time": 1, "angle": 0 } 604 | ], 605 | "translate": [ 606 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 607 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 608 | { "time": 1, "x": 0, "y": 0 } 609 | ], 610 | "scale": [ 611 | { "time": 0, "x": 1, "y": 1 }, 612 | { "time": 0.5, "x": 1.402, "y": 1.007 }, 613 | { "time": 1, "x": 1, "y": 1 } 614 | ] 615 | }, 616 | "R_front_leg": { 617 | "rotate": [ 618 | { "time": 0, "angle": 0 }, 619 | { "time": 0.1666, "angle": 26.07 }, 620 | { "time": 0.5, "angle": -21.6 }, 621 | { "time": 1, "angle": 0 } 622 | ], 623 | "translate": [ 624 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 625 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 626 | { "time": 1, "x": 0, "y": 0 } 627 | ], 628 | "scale": [ 629 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 630 | { "time": 0.5, "x": 1, "y": 1, "curve": "stepped" }, 631 | { "time": 1, "x": 1, "y": 1 } 632 | ] 633 | }, 634 | "R_front_toe1": { 635 | "rotate": [ 636 | { "time": 0, "angle": 0 }, 637 | { "time": 0.1666, "angle": 29.23 }, 638 | { "time": 0.5, "angle": 34.83 }, 639 | { "time": 1, "angle": 0 } 640 | ], 641 | "translate": [ 642 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 643 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 644 | { "time": 1, "x": 0, "y": 0 } 645 | ], 646 | "scale": [ 647 | { "time": 0, "x": 1, "y": 1 }, 648 | { "time": 0.5, "x": 1.412, "y": 1 }, 649 | { "time": 1, "x": 1, "y": 1 } 650 | ] 651 | }, 652 | "R_front_toe2": { 653 | "rotate": [ 654 | { "time": 0, "angle": 0 }, 655 | { "time": 0.1666, "angle": 24.89 }, 656 | { "time": 0.5, "angle": 23.16 }, 657 | { "time": 1, "angle": 0 } 658 | ], 659 | "translate": [ 660 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 661 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 662 | { "time": 1, "x": 0, "y": 0 } 663 | ], 664 | "scale": [ 665 | { "time": 0, "x": 1, "y": 1 }, 666 | { "time": 0.5, "x": 1.407, "y": 1.057 }, 667 | { "time": 1, "x": 1, "y": 1 } 668 | ] 669 | }, 670 | "R_front_toe3": { 671 | "rotate": [ 672 | { "time": 0, "angle": 0 }, 673 | { "time": 0.1666, "angle": 11.01 }, 674 | { "time": 0.5, "angle": 0, "curve": "stepped" }, 675 | { "time": 1, "angle": 0 } 676 | ], 677 | "translate": [ 678 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 679 | { "time": 0.5, "x": 0, "y": 0, "curve": "stepped" }, 680 | { "time": 1, "x": 0, "y": 0 } 681 | ], 682 | "scale": [ 683 | { "time": 0, "x": 1, "y": 1 }, 684 | { "time": 0.5, "x": 1.329, "y": 1.181 }, 685 | { "time": 1, "x": 1, "y": 1 } 686 | ] 687 | }, 688 | "L_rear_leg": { 689 | "rotate": [ 690 | { "time": 0, "angle": 0 }, 691 | { "time": 0.3666, "angle": 25.19 }, 692 | { "time": 0.6666, "angle": -15.65 }, 693 | { "time": 1, "angle": 0 } 694 | ], 695 | "translate": [ 696 | { "time": 0, "x": 0, "y": 0 } 697 | ], 698 | "scale": [ 699 | { "time": 0, "x": 1, "y": 1 } 700 | ] 701 | }, 702 | "COG": { 703 | "rotate": [ 704 | { 705 | "time": 0, 706 | "angle": 0, 707 | "curve": [ 0.456, 0.2, 0.422, 1.06 ] 708 | }, 709 | { "time": 0.3333, "angle": 23.93 }, 710 | { 711 | "time": 0.6666, 712 | "angle": 337.8, 713 | "curve": [ 0.41, 0, 0.887, 0.75 ] 714 | }, 715 | { "time": 1, "angle": 0 } 716 | ], 717 | "translate": [ 718 | { 719 | "time": 0, 720 | "x": 0, 721 | "y": 0, 722 | "curve": [ 0.33, 1, 0.816, 1.33 ] 723 | }, 724 | { 725 | "time": 0.5, 726 | "x": 0, 727 | "y": 113.01, 728 | "curve": [ 0.396, 0, 0.709, 2.03 ] 729 | }, 730 | { "time": 1, "x": 0, "y": 0 } 731 | ] 732 | } 733 | }, 734 | "slots": { 735 | "R_wing": { 736 | "attachment": [ 737 | { "time": 0, "name": "R_wing01" }, 738 | { "time": 0.0666, "name": "R_wing02" }, 739 | { "time": 0.1333, "name": "R_wing03" }, 740 | { "time": 0.2, "name": "R_wing04" }, 741 | { "time": 0.2666, "name": "R_wing05" }, 742 | { "time": 0.3333, "name": "R_wing06" }, 743 | { "time": 0.4, "name": "R_wing07" }, 744 | { "time": 0.4666, "name": "R_wing08" }, 745 | { "time": 0.5333, "name": "R_wing09" }, 746 | { "time": 0.6, "name": "R_wing01" }, 747 | { "time": 0.7333, "name": "R_wing02" }, 748 | { "time": 0.7666, "name": "R_wing02" }, 749 | { "time": 0.8, "name": "R_wing03" }, 750 | { "time": 0.8333, "name": "R_wing04" }, 751 | { "time": 0.8666, "name": "R_wing05" }, 752 | { "time": 0.9, "name": "R_wing06" }, 753 | { "time": 0.9333, "name": "R_wing07" }, 754 | { "time": 0.9666, "name": "R_wing08" }, 755 | { "time": 1, "name": "R_wing09" } 756 | ] 757 | }, 758 | "L_wing": { 759 | "attachment": [ 760 | { "time": 0, "name": "L_wing01" }, 761 | { "time": 0.0666, "name": "L_wing02" }, 762 | { "time": 0.1333, "name": "L_wing03" }, 763 | { "time": 0.2, "name": "L_wing04" }, 764 | { "time": 0.2666, "name": "L_wing05" }, 765 | { "time": 0.3333, "name": "L_wing06" }, 766 | { "time": 0.4, "name": "L_wing07" }, 767 | { "time": 0.4666, "name": "L_wing08" }, 768 | { "time": 0.5333, "name": "L_wing09" }, 769 | { "time": 0.6, "name": "L_wing01" }, 770 | { "time": 0.7333, "name": "L_wing02" }, 771 | { "time": 0.8, "name": "L_wing03" }, 772 | { "time": 0.8333, "name": "L_wing04" }, 773 | { "time": 0.8666, "name": "L_wing05" }, 774 | { "time": 0.9, "name": "L_wing06" }, 775 | { "time": 0.9333, "name": "L_wing07" }, 776 | { "time": 0.9666, "name": "L_wing08" }, 777 | { "time": 1, "name": "L_wing09" } 778 | ] 779 | } 780 | } 781 | } 782 | } 783 | } -------------------------------------------------------------------------------- /pyguts/examples/data/dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/dragon.png -------------------------------------------------------------------------------- /pyguts/examples/data/dragon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/dragon2.png -------------------------------------------------------------------------------- /pyguts/examples/data/goblins.atlas: -------------------------------------------------------------------------------- 1 | 2 | data/goblins.png 3 | format: RGBA8888 4 | filter: Nearest,Nearest 5 | repeat: none 6 | goblin/spear 7 | rotate: false 8 | xy: 1, 123 9 | size: 22, 368 10 | orig: 22, 368 11 | offset: 0, 0 12 | index: -1 13 | goblin/head 14 | rotate: false 15 | xy: 25, 425 16 | size: 103, 66 17 | orig: 103, 66 18 | offset: 0, 0 19 | index: -1 20 | goblin/torso 21 | rotate: false 22 | xy: 25, 327 23 | size: 68, 96 24 | orig: 68, 96 25 | offset: 0, 0 26 | index: -1 27 | goblin/shield 28 | rotate: false 29 | xy: 25, 253 30 | size: 70, 72 31 | orig: 70, 72 32 | offset: 0, 0 33 | index: -1 34 | goblin/right-lower-leg 35 | rotate: false 36 | xy: 25, 175 37 | size: 36, 76 38 | orig: 36, 76 39 | offset: 0, 0 40 | index: -1 41 | goblin/left-upper-leg 42 | rotate: false 43 | xy: 95, 350 44 | size: 33, 73 45 | orig: 33, 73 46 | offset: 0, 0 47 | index: -1 48 | goblin/pelvis 49 | rotate: false 50 | xy: 130, 448 51 | size: 62, 43 52 | orig: 62, 43 53 | offset: 0, 0 54 | index: -1 55 | goblin/left-lower-leg 56 | rotate: false 57 | xy: 130, 376 58 | size: 33, 70 59 | orig: 33, 70 60 | offset: 0, 0 61 | index: -1 62 | goblin/right-upper-leg 63 | rotate: false 64 | xy: 63, 188 65 | size: 34, 63 66 | orig: 34, 63 67 | offset: 0, 0 68 | index: -1 69 | goblin/right-shoulder 70 | rotate: false 71 | xy: 194, 446 72 | size: 39, 45 73 | orig: 39, 45 74 | offset: 0, 0 75 | index: -1 76 | goblin/left-hand 77 | rotate: false 78 | xy: 25, 132 79 | size: 36, 41 80 | orig: 36, 41 81 | offset: 0, 0 82 | index: -1 83 | goblin/neck 84 | rotate: false 85 | xy: 63, 145 86 | size: 36, 41 87 | orig: 36, 41 88 | offset: 0, 0 89 | index: -1 90 | goblin/right-arm 91 | rotate: false 92 | xy: 165, 396 93 | size: 23, 50 94 | orig: 23, 50 95 | offset: 0, 0 96 | index: -1 97 | goblin/left-foot 98 | rotate: false 99 | xy: 190, 413 100 | size: 65, 31 101 | orig: 65, 31 102 | offset: 0, 0 103 | index: -1 104 | goblin/right-foot 105 | rotate: false 106 | xy: 190, 378 107 | size: 63, 33 108 | orig: 63, 33 109 | offset: 0, 0 110 | index: -1 111 | goblin/left-shoulder 112 | rotate: false 113 | xy: 1, 77 114 | size: 29, 44 115 | orig: 29, 44 116 | offset: 0, 0 117 | index: -1 118 | goblin/right-hand 119 | rotate: false 120 | xy: 1, 38 121 | size: 36, 37 122 | orig: 36, 37 123 | offset: 0, 0 124 | index: -1 125 | goblin/left-arm 126 | rotate: false 127 | xy: 1, 1 128 | size: 37, 35 129 | orig: 37, 35 130 | offset: 0, 0 131 | index: -1 132 | goblin/undies 133 | rotate: false 134 | xy: 130, 345 135 | size: 36, 29 136 | orig: 36, 29 137 | offset: 0, 0 138 | index: -1 139 | goblin/undie-straps 140 | rotate: false 141 | xy: 168, 357 142 | size: 55, 19 143 | orig: 55, 19 144 | offset: 0, 0 145 | index: -1 146 | 147 | data/goblins2.png 148 | format: RGBA8888 149 | filter: Nearest,Nearest 150 | repeat: none 151 | goblingirl/goblingirl 152 | rotate: false 153 | xy: 1, 217 154 | size: 148, 294 155 | orig: 148, 294 156 | offset: 0, 0 157 | index: -1 158 | goblingirl/head 159 | rotate: false 160 | xy: 1, 134 161 | size: 103, 81 162 | orig: 103, 81 163 | offset: 0, 0 164 | index: -1 165 | goblingirl/torso 166 | rotate: false 167 | xy: 151, 415 168 | size: 68, 96 169 | orig: 68, 96 170 | offset: 0, 0 171 | index: -1 172 | goblingirl/right-upper-leg 173 | rotate: false 174 | xy: 221, 448 175 | size: 34, 63 176 | orig: 34, 63 177 | offset: 0, 0 178 | index: -1 179 | goblingirl/dagger 180 | rotate: false 181 | xy: 1, 24 182 | size: 26, 108 183 | orig: 26, 108 184 | offset: 0, 0 185 | index: -1 186 | goblingirl/right-lower-leg 187 | rotate: false 188 | xy: 106, 139 189 | size: 36, 76 190 | orig: 36, 76 191 | offset: 0, 0 192 | index: -1 193 | goblingirl/pelvis 194 | rotate: false 195 | xy: 151, 370 196 | size: 62, 43 197 | orig: 62, 43 198 | offset: 0, 0 199 | index: -1 200 | goblingirl/left-lower-leg 201 | rotate: false 202 | xy: 29, 62 203 | size: 33, 70 204 | orig: 33, 70 205 | offset: 0, 0 206 | index: -1 207 | goblingirl/left-upper-leg 208 | rotate: false 209 | xy: 151, 298 210 | size: 33, 70 211 | orig: 33, 70 212 | offset: 0, 0 213 | index: -1 214 | goblingirl/right-shoulder 215 | rotate: false 216 | xy: 64, 87 217 | size: 39, 45 218 | orig: 39, 45 219 | offset: 0, 0 220 | index: -1 221 | goblingirl/right-arm 222 | rotate: false 223 | xy: 151, 246 224 | size: 28, 50 225 | orig: 28, 50 226 | offset: 0, 0 227 | index: -1 228 | goblingirl/left-shoulder 229 | rotate: false 230 | xy: 186, 322 231 | size: 28, 46 232 | orig: 28, 46 233 | offset: 0, 0 234 | index: -1 235 | goblingirl/left-hand 236 | rotate: false 237 | xy: 29, 20 238 | size: 35, 40 239 | orig: 35, 40 240 | offset: 0, 0 241 | index: -1 242 | goblingirl/undie-straps 243 | rotate: false 244 | xy: 64, 66 245 | size: 55, 19 246 | orig: 55, 19 247 | offset: 0, 0 248 | index: -1 249 | goblingirl/right-foot 250 | rotate: false 251 | xy: 66, 31 252 | size: 63, 33 253 | orig: 63, 33 254 | offset: 0, 0 255 | index: -1 256 | goblingirl/left-arm 257 | rotate: false 258 | xy: 151, 209 259 | size: 37, 35 260 | orig: 37, 35 261 | offset: 0, 0 262 | index: -1 263 | goblingirl/neck 264 | rotate: false 265 | xy: 144, 166 266 | size: 35, 41 267 | orig: 35, 41 268 | offset: 0, 0 269 | index: -1 270 | goblingirl/left-foot 271 | rotate: false 272 | xy: 144, 133 273 | size: 65, 31 274 | orig: 65, 31 275 | offset: 0, 0 276 | index: -1 277 | goblingirl/right-hand 278 | rotate: false 279 | xy: 186, 283 280 | size: 36, 37 281 | orig: 36, 37 282 | offset: 0, 0 283 | index: -1 284 | goblingirl/undies 285 | rotate: false 286 | xy: 181, 252 287 | size: 36, 29 288 | orig: 36, 29 289 | offset: 0, 0 290 | index: -1 291 | goblingirl/dagger-tip 292 | rotate: false 293 | xy: 1, 1 294 | size: 17, 17 295 | orig: 17, 17 296 | offset: 0, 0 297 | index: -1 298 | -------------------------------------------------------------------------------- /pyguts/examples/data/goblins.json: -------------------------------------------------------------------------------- 1 | { 2 | "bones": [ 3 | { "name": "root" }, 4 | { "name": "hip", "parent": "root", "x": 0.64, "y": 114.41 }, 5 | { "name": "left upper leg", "parent": "hip", "length": 50.39, "x": 14.45, "y": 2.81, "rotation": -89.09 }, 6 | { "name": "left lower leg", "parent": "left upper leg", "length": 49.89, "x": 56.34, "y": 0.98, "rotation": -16.65 }, 7 | { "name": "left foot", "parent": "left lower leg", "length": 46.5, "x": 58.94, "y": -7.61, "rotation": 102.43 }, 8 | { "name": "right upper leg", "parent": "hip", "length": 42.45, "x": -20.07, "y": -6.83, "rotation": -97.49 }, 9 | { "name": "right lower leg", "parent": "right upper leg", "length": 58.52, "x": 42.99, "y": -0.61, "rotation": -14.34 }, 10 | { "name": "right foot", "parent": "right lower leg", "length": 45.45, "x": 64.88, "y": 0.04, "rotation": 110.3 }, 11 | { "name": "torso", "parent": "hip", "length": 85.82, "x": -6.42, "y": 1.97, "rotation": 93.92 }, 12 | { "name": "neck", "parent": "torso", "length": 18.38, "x": 81.67, "y": -6.34, "rotation": -1.51 }, 13 | { "name": "head", "parent": "neck", "length": 68.28, "x": 20.93, "y": 11.59, "rotation": -13.92 }, 14 | { "name": "right shoulder", "parent": "torso", "length": 37.24, "x": 76.02, "y": 18.14, "rotation": 133.88 }, 15 | { "name": "right arm", "parent": "right shoulder", "length": 36.74, "x": 37.6, "y": 0.31, "rotation": 36.32 }, 16 | { "name": "right hand", "parent": "right arm", "length": 15.32, "x": 36.9, "y": 0.34, "rotation": 2.35 }, 17 | { "name": "left shoulder", "parent": "torso", "length": 35.43, "x": 74.04, "y": -20.38, "rotation": -156.96 }, 18 | { "name": "left arm", "parent": "left shoulder", "length": 35.62, "x": 37.85, "y": -2.34, "rotation": 28.16 }, 19 | { "name": "left hand", "parent": "left arm", "length": 11.52, "x": 35.62, "y": 0.07, "rotation": 2.7 }, 20 | { "name": "pelvis", "parent": "hip", "x": 1.41, "y": -6.57 } 21 | ], 22 | "slots": [ 23 | { "name": "left shoulder", "bone": "left shoulder", "attachment": "left shoulder" }, 24 | { "name": "left arm", "bone": "left arm", "attachment": "left arm" }, 25 | { "name": "left hand item", "bone": "left hand", "attachment": "left hand item" }, 26 | { "name": "left hand", "bone": "left hand", "attachment": "left hand" }, 27 | { "name": "left foot", "bone": "left foot", "attachment": "left foot" }, 28 | { "name": "left lower leg", "bone": "left lower leg", "attachment": "left lower leg" }, 29 | { "name": "left upper leg", "bone": "left upper leg", "attachment": "left upper leg" }, 30 | { "name": "neck", "bone": "neck", "attachment": "neck" }, 31 | { "name": "torso", "bone": "torso", "attachment": "torso" }, 32 | { "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" }, 33 | { "name": "right foot", "bone": "right foot", "attachment": "right foot" }, 34 | { "name": "right lower leg", "bone": "right lower leg", "attachment": "right lower leg" }, 35 | { "name": "undie straps", "bone": "pelvis", "attachment": "undie straps" }, 36 | { "name": "undies", "bone": "pelvis", "attachment": "undies" }, 37 | { "name": "right upper leg", "bone": "right upper leg", "attachment": "right upper leg" }, 38 | { "name": "head", "bone": "head", "attachment": "head" }, 39 | { "name": "eyes", "bone": "head", "attachment": "eyes open" }, 40 | { "name": "right shoulder", "bone": "right shoulder", "attachment": "right shoulder" }, 41 | { "name": "right arm", "bone": "right arm", "attachment": "right arm" }, 42 | { "name": "right hand item 2", "bone": "right hand", "attachment": "right hand item 2" }, 43 | { "name": "right hand", "bone": "right hand", "attachment": "right hand" }, 44 | { "name": "right hand item", "bone": "right hand", "attachment": "right hand item" } 45 | ], 46 | "skins": { 47 | "goblin": { 48 | "neck": { 49 | "neck": { "name": "goblin/neck", "x": 10.1, "y": 0.42, "rotation": -93.69, "width": 36, "height": 41 } 50 | }, 51 | "undies": { 52 | "undies": { "name": "goblin/undies", "x": 6.3, "y": 0.12, "rotation": 0.91, "width": 36, "height": 29 } 53 | }, 54 | "right hand": { 55 | "right hand": { "name": "goblin/right-hand", "x": 7.88, "y": 2.78, "rotation": 91.96, "width": 36, "height": 37 } 56 | }, 57 | "right arm": { 58 | "right arm": { "name": "goblin/right-arm", "x": 16.44, "y": -1.04, "rotation": 94.32, "width": 23, "height": 50 } 59 | }, 60 | "head": { 61 | "head": { "name": "goblin/head", "x": 25.73, "y": 2.33, "rotation": -92.29, "width": 103, "height": 66 } 62 | }, 63 | "left shoulder": { 64 | "left shoulder": { "name": "goblin/left-shoulder", "x": 15.56, "y": -2.26, "rotation": 62.01, "width": 29, "height": 44 } 65 | }, 66 | "left arm": { 67 | "left arm": { 68 | "name": "goblin/left-arm", 69 | "x": 16.7, 70 | "y": -1.69, 71 | "scaleX": 1.057, 72 | "scaleY": 1.057, 73 | "rotation": 33.84, 74 | "width": 37, 75 | "height": 35 76 | } 77 | }, 78 | "left hand": { 79 | "left hand": { 80 | "name": "goblin/left-hand", 81 | "x": 3.47, 82 | "y": 3.41, 83 | "scaleX": 0.892, 84 | "scaleY": 0.892, 85 | "rotation": 31.14, 86 | "width": 36, 87 | "height": 41 88 | } 89 | }, 90 | "right lower leg": { 91 | "right lower leg": { "name": "goblin/right-lower-leg", "x": 25.68, "y": -3.15, "rotation": 111.83, "width": 36, "height": 76 } 92 | }, 93 | "right upper leg": { 94 | "right upper leg": { "name": "goblin/right-upper-leg", "x": 20.35, "y": 1.47, "rotation": 97.49, "width": 34, "height": 63 } 95 | }, 96 | "pelvis": { 97 | "pelvis": { "name": "goblin/pelvis", "x": -5.61, "y": 0.76, "width": 62, "height": 43 } 98 | }, 99 | "left lower leg": { 100 | "left lower leg": { "name": "goblin/left-lower-leg", "x": 23.58, "y": -2.06, "rotation": 105.75, "width": 33, "height": 70 } 101 | }, 102 | "left upper leg": { 103 | "left upper leg": { "name": "goblin/left-upper-leg", "x": 29.68, "y": -3.87, "rotation": 89.09, "width": 33, "height": 73 } 104 | }, 105 | "torso": { 106 | "torso": { "name": "goblin/torso", "x": 38.09, "y": -3.87, "rotation": -94.95, "width": 68, "height": 96 } 107 | }, 108 | "right shoulder": { 109 | "right shoulder": { "name": "goblin/right-shoulder", "x": 15.68, "y": -1.03, "rotation": 130.65, "width": 39, "height": 45 } 110 | }, 111 | "right foot": { 112 | "right foot": { "name": "goblin/right-foot", "x": 23.56, "y": 9.8, "rotation": 1.52, "width": 63, "height": 33 } 113 | }, 114 | "left foot": { 115 | "left foot": { "name": "goblin/left-foot", "x": 24.85, "y": 8.74, "rotation": 3.32, "width": 65, "height": 31 } 116 | }, 117 | "right hand item": { 118 | "right hand item": { "name": "goblin/shield", "x": -0.47, "y": 1.1, "rotation": 91.16, "width": 70, "height": 72 } 119 | }, 120 | "left hand item": { 121 | "left hand item": { "name": "goblin/spear", "x": -4.55, "y": 39.2, "rotation": 13.04, "width": 22, "height": 368 } 122 | }, 123 | "undie straps": { 124 | "undie straps": { "name": "goblin/undie-straps", "x": -3.87, "y": 13.1, "scaleX": 1.089, "width": 55, "height": 19 } 125 | } 126 | }, 127 | "goblingirl": { 128 | "left upper leg": { 129 | "left upper leg": { "name": "goblingirl/left-upper-leg", "x": 30.21, "y": -2.95, "rotation": 89.09, "width": 33, "height": 70 } 130 | }, 131 | "left lower leg": { 132 | "left lower leg": { "name": "goblingirl/left-lower-leg", "x": 25.02, "y": -0.6, "rotation": 105.75, "width": 33, "height": 70 } 133 | }, 134 | "left foot": { 135 | "left foot": { "name": "goblingirl/left-foot", "x": 25.17, "y": 7.92, "rotation": 3.32, "width": 65, "height": 31 } 136 | }, 137 | "right upper leg": { 138 | "right upper leg": { "name": "goblingirl/right-upper-leg", "x": 19.69, "y": 2.13, "rotation": 97.49, "width": 34, "height": 63 } 139 | }, 140 | "right lower leg": { 141 | "right lower leg": { "name": "goblingirl/right-lower-leg", "x": 26.15, "y": -3.27, "rotation": 111.83, "width": 36, "height": 76 } 142 | }, 143 | "right foot": { 144 | "right foot": { "name": "goblingirl/right-foot", "x": 23.46, "y": 9.66, "rotation": 1.52, "width": 63, "height": 33 } 145 | }, 146 | "torso": { 147 | "torso": { "name": "goblingirl/torso", "x": 36.28, "y": -5.14, "rotation": -95.74, "width": 68, "height": 96 } 148 | }, 149 | "left shoulder": { 150 | "left shoulder": { "name": "goblingirl/left-shoulder", "x": 19.8, "y": -0.42, "rotation": 61.21, "width": 28, "height": 46 } 151 | }, 152 | "left arm": { 153 | "left arm": { "name": "goblingirl/left-arm", "x": 19.64, "y": -2.42, "rotation": 33.05, "width": 37, "height": 35 } 154 | }, 155 | "left hand": { 156 | "left hand": { 157 | "name": "goblingirl/left-hand", 158 | "x": 4.34, 159 | "y": 2.39, 160 | "scaleX": 0.896, 161 | "scaleY": 0.896, 162 | "rotation": 30.34, 163 | "width": 35, 164 | "height": 40 165 | } 166 | }, 167 | "neck": { 168 | "neck": { "name": "goblingirl/neck", "x": 6.16, "y": -3.14, "rotation": -98.86, "width": 35, "height": 41 } 169 | }, 170 | "head": { 171 | "head": { "name": "goblingirl/head", "x": 27.71, "y": -4.32, "rotation": -85.58, "width": 103, "height": 81 } 172 | }, 173 | "right shoulder": { 174 | "right shoulder": { "name": "goblingirl/right-shoulder", "x": 14.46, "y": 0.45, "rotation": 129.85, "width": 39, "height": 45 } 175 | }, 176 | "right arm": { 177 | "right arm": { "name": "goblingirl/right-arm", "x": 16.85, "y": -0.66, "rotation": 93.52, "width": 28, "height": 50 } 178 | }, 179 | "right hand": { 180 | "right hand": { "name": "goblingirl/right-hand", "x": 7.21, "y": 3.43, "rotation": 91.16, "width": 36, "height": 37 } 181 | }, 182 | "pelvis": { 183 | "pelvis": { "name": "goblingirl/pelvis", "x": -3.87, "y": 3.18, "width": 62, "height": 43 } 184 | }, 185 | "undie straps": { 186 | "undie straps": { "name": "goblingirl/undie-straps", "x": -1.51, "y": 14.18, "width": 55, "height": 19 } 187 | }, 188 | "undies": { 189 | "undies": { "name": "goblingirl/undies", "x": 5.4, "y": 1.7, "width": 36, "height": 29 } 190 | }, 191 | "left hand item": { 192 | "left hand item": { "name": "goblingirl/dagger", "x": 7.88, "y": -23.45, "rotation": 10.47, "width": 26, "height": 108 } 193 | }, 194 | "right hand item 2": { 195 | "right hand item 2": { "name": "goblingirl/dagger", "x": 7.17, "y": -22.38, "rotation": -5.27, "width": 26, "height": 108 } 196 | }, 197 | "right hand item": { 198 | "right hand item": { "name": "goblingirl/dagger-tip", "x": 13.45, "y": 22.07, "rotation": -3.23, "width": 17, "height": 17 } 199 | } 200 | } 201 | }, 202 | "animations": { 203 | "walk": { 204 | "bones": { 205 | "left upper leg": { 206 | "rotate": [ 207 | { "time": 0, "angle": -26.55 }, 208 | { "time": 0.1333, "angle": -8.78 }, 209 | { "time": 0.2666, "angle": 9.51 }, 210 | { "time": 0.4, "angle": 30.74 }, 211 | { "time": 0.5333, "angle": 25.33 }, 212 | { "time": 0.6666, "angle": 26.11 }, 213 | { "time": 0.8, "angle": -7.7 }, 214 | { "time": 0.9333, "angle": -21.19 }, 215 | { "time": 1.0666, "angle": -26.55 } 216 | ], 217 | "translate": [ 218 | { "time": 0, "x": -1.32, "y": 1.7 }, 219 | { "time": 0.4, "x": -0.06, "y": 2.42 }, 220 | { "time": 1.0666, "x": -1.32, "y": 1.7 } 221 | ] 222 | }, 223 | "right upper leg": { 224 | "rotate": [ 225 | { "time": 0, "angle": 42.45 }, 226 | { "time": 0.1333, "angle": 52.1 }, 227 | { "time": 0.2666, "angle": 8.53 }, 228 | { "time": 0.5333, "angle": -16.93 }, 229 | { "time": 0.6666, "angle": 1.89 }, 230 | { 231 | "time": 0.8, 232 | "angle": 28.06, 233 | "curve": [ 0.462, 0.11, 1, 1 ] 234 | }, 235 | { 236 | "time": 0.9333, 237 | "angle": 58.68, 238 | "curve": [ 0.5, 0.02, 1, 1 ] 239 | }, 240 | { "time": 1.0666, "angle": 42.45 } 241 | ], 242 | "translate": [ 243 | { "time": 0, "x": 6.23, "y": 0 }, 244 | { "time": 0.2666, "x": 2.14, "y": 2.4 }, 245 | { "time": 0.5333, "x": 2.44, "y": 4.8 }, 246 | { "time": 1.0666, "x": 6.23, "y": 0 } 247 | ] 248 | }, 249 | "left lower leg": { 250 | "rotate": [ 251 | { "time": 0, "angle": -22.98 }, 252 | { "time": 0.1333, "angle": -63.5 }, 253 | { "time": 0.2666, "angle": -73.76 }, 254 | { "time": 0.5333, "angle": 5.11 }, 255 | { "time": 0.6666, "angle": -28.29 }, 256 | { "time": 0.8, "angle": 4.08 }, 257 | { "time": 0.9333, "angle": 3.53 }, 258 | { "time": 1.0666, "angle": -22.98 } 259 | ], 260 | "translate": [ 261 | { "time": 0, "x": 0, "y": 0 }, 262 | { "time": 0.2666, "x": 2.55, "y": -0.47 }, 263 | { "time": 0.5333, "x": 0, "y": 0, "curve": "stepped" }, 264 | { "time": 1.0666, "x": 0, "y": 0 } 265 | ] 266 | }, 267 | "left foot": { 268 | "rotate": [ 269 | { "time": 0, "angle": -3.69 }, 270 | { "time": 0.1333, "angle": -10.42 }, 271 | { "time": 0.2666, "angle": -5.01 }, 272 | { "time": 0.4, "angle": 3.87 }, 273 | { "time": 0.5333, "angle": -3.87 }, 274 | { "time": 0.6666, "angle": 2.78 }, 275 | { "time": 0.8, "angle": 1.68 }, 276 | { "time": 0.9333, "angle": -8.54 }, 277 | { "time": 1.0666, "angle": -3.69 } 278 | ] 279 | }, 280 | "right shoulder": { 281 | "rotate": [ 282 | { 283 | "time": 0, 284 | "angle": 5.29, 285 | "curve": [ 0.264, 0, 0.75, 1 ] 286 | }, 287 | { "time": 0.6666, "angle": 6.65 }, 288 | { "time": 1.0666, "angle": 5.29 } 289 | ] 290 | }, 291 | "right arm": { 292 | "rotate": [ 293 | { 294 | "time": 0, 295 | "angle": -4.02, 296 | "curve": [ 0.267, 0, 0.804, 0.99 ] 297 | }, 298 | { 299 | "time": 0.6666, 300 | "angle": 19.78, 301 | "curve": [ 0.307, 0, 0.787, 0.99 ] 302 | }, 303 | { "time": 1.0666, "angle": -4.02 } 304 | ] 305 | }, 306 | "right hand": { 307 | "rotate": [ 308 | { "time": 0, "angle": 8.98 }, 309 | { "time": 0.6666, "angle": 0.51 }, 310 | { "time": 1.0666, "angle": 8.98 } 311 | ] 312 | }, 313 | "left shoulder": { 314 | "rotate": [ 315 | { 316 | "time": 0, 317 | "angle": 6.25, 318 | "curve": [ 0.339, 0, 0.683, 1 ] 319 | }, 320 | { 321 | "time": 0.5333, 322 | "angle": -11.78, 323 | "curve": [ 0.281, 0, 0.686, 0.99 ] 324 | }, 325 | { "time": 1.0666, "angle": 6.25 } 326 | ], 327 | "translate": [ 328 | { "time": 0, "x": 1.15, "y": 0.23 } 329 | ] 330 | }, 331 | "left hand": { 332 | "rotate": [ 333 | { 334 | "time": 0, 335 | "angle": -21.23, 336 | "curve": [ 0.295, 0, 0.755, 0.98 ] 337 | }, 338 | { 339 | "time": 0.5333, 340 | "angle": -27.28, 341 | "curve": [ 0.241, 0, 0.75, 0.97 ] 342 | }, 343 | { "time": 1.0666, "angle": -21.23 } 344 | ] 345 | }, 346 | "left arm": { 347 | "rotate": [ 348 | { 349 | "time": 0, 350 | "angle": 28.37, 351 | "curve": [ 0.339, 0, 0.683, 1 ] 352 | }, 353 | { 354 | "time": 0.5333, 355 | "angle": 60.09, 356 | "curve": [ 0.281, 0, 0.686, 0.99 ] 357 | }, 358 | { "time": 1.0666, "angle": 28.37 } 359 | ] 360 | }, 361 | "torso": { 362 | "rotate": [ 363 | { "time": 0, "angle": -10.28 }, 364 | { 365 | "time": 0.1333, 366 | "angle": -15.38, 367 | "curve": [ 0.545, 0, 0.818, 1 ] 368 | }, 369 | { 370 | "time": 0.4, 371 | "angle": -9.78, 372 | "curve": [ 0.58, 0.17, 0.669, 0.99 ] 373 | }, 374 | { 375 | "time": 0.6666, 376 | "angle": -15.75, 377 | "curve": [ 0.235, 0.01, 0.795, 1 ] 378 | }, 379 | { 380 | "time": 0.9333, 381 | "angle": -7.06, 382 | "curve": [ 0.209, 0, 0.816, 0.98 ] 383 | }, 384 | { "time": 1.0666, "angle": -10.28 } 385 | ], 386 | "translate": [ 387 | { "time": 0, "x": -1.29, "y": 1.68 } 388 | ] 389 | }, 390 | "right foot": { 391 | "rotate": [ 392 | { "time": 0, "angle": -5.25 }, 393 | { "time": 0.2666, "angle": -1.91 }, 394 | { "time": 0.4, "angle": -6.45 }, 395 | { "time": 0.5333, "angle": -5.39 }, 396 | { "time": 0.8, "angle": -11.68 }, 397 | { "time": 0.9333, "angle": 0.46 }, 398 | { "time": 1.0666, "angle": -5.25 } 399 | ] 400 | }, 401 | "right lower leg": { 402 | "rotate": [ 403 | { 404 | "time": 0, 405 | "angle": -3.39, 406 | "curve": [ 0.316, 0.01, 0.741, 0.98 ] 407 | }, 408 | { 409 | "time": 0.1333, 410 | "angle": -45.53, 411 | "curve": [ 0.229, 0, 0.738, 0.97 ] 412 | }, 413 | { "time": 0.2666, "angle": -4.83 }, 414 | { "time": 0.5333, "angle": -19.53 }, 415 | { "time": 0.6666, "angle": -64.8 }, 416 | { 417 | "time": 0.8, 418 | "angle": -82.56, 419 | "curve": [ 0.557, 0.18, 1, 1 ] 420 | }, 421 | { "time": 1.0666, "angle": -3.39 } 422 | ], 423 | "translate": [ 424 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 425 | { "time": 0.5333, "x": 0, "y": 0 }, 426 | { "time": 0.6666, "x": 2.18, "y": 0.21 }, 427 | { "time": 1.0666, "x": 0, "y": 0 } 428 | ] 429 | }, 430 | "hip": { 431 | "rotate": [ 432 | { "time": 0, "angle": 0, "curve": "stepped" }, 433 | { "time": 1.0666, "angle": 0 } 434 | ], 435 | "translate": [ 436 | { "time": 0, "x": 0, "y": -4.16 }, 437 | { 438 | "time": 0.1333, 439 | "x": 0, 440 | "y": -7.05, 441 | "curve": [ 0.359, 0.47, 0.646, 0.74 ] 442 | }, 443 | { "time": 0.4, "x": 0, "y": 6.78 }, 444 | { "time": 0.5333, "x": 0, "y": -6.13 }, 445 | { 446 | "time": 0.6666, 447 | "x": 0, 448 | "y": -7.05, 449 | "curve": [ 0.359, 0.47, 0.646, 0.74 ] 450 | }, 451 | { "time": 0.9333, "x": 0, "y": 6.78 }, 452 | { "time": 1.0666, "x": 0, "y": -4.16 } 453 | ] 454 | }, 455 | "neck": { 456 | "rotate": [ 457 | { "time": 0, "angle": 3.6 }, 458 | { "time": 0.1333, "angle": 17.49 }, 459 | { "time": 0.2666, "angle": 6.1 }, 460 | { "time": 0.4, "angle": 3.45 }, 461 | { "time": 0.5333, "angle": 5.17 }, 462 | { "time": 0.6666, "angle": 18.36 }, 463 | { "time": 0.8, "angle": 6.09 }, 464 | { "time": 0.9333, "angle": 2.28 }, 465 | { "time": 1.0666, "angle": 3.6 } 466 | ] 467 | }, 468 | "head": { 469 | "rotate": [ 470 | { 471 | "time": 0, 472 | "angle": 3.6, 473 | "curve": [ 0, 0, 0.704, 1.17 ] 474 | }, 475 | { "time": 0.1333, "angle": -0.2 }, 476 | { "time": 0.2666, "angle": 6.1 }, 477 | { "time": 0.4, "angle": 3.45 }, 478 | { 479 | "time": 0.5333, 480 | "angle": 5.17, 481 | "curve": [ 0, 0, 0.704, 1.61 ] 482 | }, 483 | { "time": 0.7, "angle": 1.1 }, 484 | { "time": 0.8, "angle": 6.09 }, 485 | { "time": 0.9333, "angle": 2.28 }, 486 | { "time": 1.0666, "angle": 3.6 } 487 | ] 488 | } 489 | } 490 | } 491 | } 492 | } -------------------------------------------------------------------------------- /pyguts/examples/data/goblins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/goblins.png -------------------------------------------------------------------------------- /pyguts/examples/data/goblins2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/goblins2.png -------------------------------------------------------------------------------- /pyguts/examples/data/powerup.atlas: -------------------------------------------------------------------------------- 1 | 2 | data/powerup.png 3 | format: RGBA8888 4 | filter: Nearest,Nearest 5 | repeat: none 6 | wing 7 | rotate: false 8 | xy: 1, 75 9 | size: 137, 150 10 | orig: 137, 150 11 | offset: 0, 0 12 | index: -1 13 | token 14 | rotate: false 15 | xy: 140, 103 16 | size: 123, 122 17 | orig: 123, 122 18 | offset: 0, 0 19 | index: -1 20 | star 21 | rotate: false 22 | xy: 1, 1 23 | size: 76, 72 24 | orig: 76, 72 25 | offset: 0, 0 26 | index: -1 27 | -------------------------------------------------------------------------------- /pyguts/examples/data/powerup.json: -------------------------------------------------------------------------------- 1 | { 2 | "bones": [ 3 | { "name": "root" }, 4 | { "name": "powerup", "parent": "root", "x": 1.48, "y": 134.02 }, 5 | { "name": "stars", "parent": "root", "x": 1.22, "y": 191.25 }, 6 | { "name": "tokenRoot", "parent": "powerup", "x": -0.47, "y": 56.13 }, 7 | { "name": "right wing", "parent": "tokenRoot", "x": 86.82, "y": 7.12 }, 8 | { "name": "left wing", "parent": "tokenRoot", "x": -91.06, "y": 7.8 }, 9 | { "name": "token", "parent": "tokenRoot", "x": -1.18, "y": -1.81, "scaleX": 0.771, "scaleY": 0.771 }, 10 | { "name": "star7", "parent": "stars", "x": -5.85, "y": -35.84 }, 11 | { "name": "star5", "parent": "stars", "x": 11.5, "y": -12.28 }, 12 | { "name": "star4", "parent": "stars", "x": 10.08, "y": 14.52 }, 13 | { "name": "star3", "parent": "stars", "x": -0.84, "y": -3.78 }, 14 | { "name": "star2", "parent": "stars", "x": -1.36, "y": -4.16 }, 15 | { "name": "star", "parent": "stars", "x": 2.84, "y": 4.76 }, 16 | { "name": "star1", "parent": "stars", "x": -2.19, "y": -2.04 }, 17 | { "name": "star6", "parent": "stars", "x": -20.73, "y": -23.44 }, 18 | { "name": "star8", "parent": "stars", "x": 8.41, "y": -10.05 }, 19 | { "name": "star9", "parent": "stars", "x": -1.62, "y": -7.34 } 20 | ], 21 | "slots": [ 22 | { "name": "right wing", "bone": "right wing", "attachment": "wing" }, 23 | { "name": "left wing", "bone": "left wing", "attachment": "wing" }, 24 | { "name": "star", "bone": "star", "color": "ffffff00", "attachment": "star" }, 25 | { "name": "star1", "bone": "star1", "color": "ffa5a500", "attachment": "star" }, 26 | { "name": "star2", "bone": "star2", "color": "ffffff00", "attachment": "star" }, 27 | { "name": "star3", "bone": "star3", "color": "ffffff00", "attachment": "star" }, 28 | { "name": "star4", "bone": "star4", "color": "ffffff00", "attachment": "star" }, 29 | { "name": "star5", "bone": "star5", "color": "ffffff00", "attachment": "star" }, 30 | { "name": "star6", "bone": "star6", "color": "ffffff00", "attachment": "star" }, 31 | { "name": "star7", "bone": "star7", "color": "ffffff00", "attachment": "star" }, 32 | { "name": "star8", "bone": "star8", "color": "ffffff00", "attachment": "star" }, 33 | { "name": "star9", "bone": "star9", "color": "ffffff00", "attachment": "star" }, 34 | { "name": "token", "bone": "token", "attachment": "token" } 35 | ], 36 | "skins": { 37 | "default": { 38 | "right wing": { 39 | "wing": { "x": 49.55, "y": 42.32, "width": 137, "height": 150 } 40 | }, 41 | "left wing": { 42 | "wing": { "x": -48.74, "y": 42.16, "scaleX": -1, "width": 137, "height": 150 } 43 | }, 44 | "star": { 45 | "star": { "width": 76, "height": 72 } 46 | }, 47 | "star1": { 48 | "star": { "width": 76, "height": 72 } 49 | }, 50 | "star2": { 51 | "star": { "width": 76, "height": 72 } 52 | }, 53 | "star3": { 54 | "star": { "width": 76, "height": 72 } 55 | }, 56 | "star4": { 57 | "star": { "width": 76, "height": 72 } 58 | }, 59 | "star5": { 60 | "star": { "width": 76, "height": 72 } 61 | }, 62 | "star6": { 63 | "star": { "width": 76, "height": 72 } 64 | }, 65 | "star7": { 66 | "star": { "width": 76, "height": 72 } 67 | }, 68 | "star8": { 69 | "star": { "width": 76, "height": 72 } 70 | }, 71 | "star9": { 72 | "star": { "width": 76, "height": 72 } 73 | }, 74 | "token": { 75 | "token": { "x": 1.18, "y": 1.81, "width": 123, "height": 122 } 76 | } 77 | } 78 | }, 79 | "animations": { 80 | "animation": { 81 | "bones": { 82 | "powerup": { 83 | "translate": [ 84 | { 85 | "time": 0, 86 | "x": -18.55, 87 | "y": 0, 88 | "curve": [ 0.385, 0, 0.689, 0.95 ] 89 | }, 90 | { 91 | "time": 0.3333, 92 | "x": 0, 93 | "y": -34.69, 94 | "curve": [ 0.235, 0.66, 1, 1 ] 95 | }, 96 | { "time": 0.6666, "x": 22.04, "y": 0 }, 97 | { 98 | "time": 1, 99 | "x": 0, 100 | "y": -34.69, 101 | "curve": [ 0.235, 0.66, 1, 1 ] 102 | }, 103 | { "time": 1.3333, "x": -18.55, "y": 0 } 104 | ] 105 | }, 106 | "left wing": { 107 | "rotate": [ 108 | { 109 | "time": 0, 110 | "angle": 45.23, 111 | "curve": [ 0.393, 0, 0.629, 1 ] 112 | }, 113 | { 114 | "time": 0.1666, 115 | "angle": -38.74, 116 | "curve": [ 0.163, 0.91, 1, 1 ] 117 | }, 118 | { 119 | "time": 0.3333, 120 | "angle": 45.23, 121 | "curve": [ 0.393, 0, 0.629, 1 ] 122 | }, 123 | { 124 | "time": 0.5, 125 | "angle": -38.74, 126 | "curve": [ 0.163, 0.91, 1, 1 ] 127 | }, 128 | { 129 | "time": 0.6666, 130 | "angle": 45.23, 131 | "curve": [ 0.393, 0, 0.629, 1 ] 132 | }, 133 | { 134 | "time": 0.8333, 135 | "angle": -38.74, 136 | "curve": [ 0.163, 0.91, 1, 1 ] 137 | }, 138 | { 139 | "time": 1, 140 | "angle": 45.23, 141 | "curve": [ 0.393, 0, 0.629, 1 ] 142 | }, 143 | { 144 | "time": 1.1666, 145 | "angle": -38.74, 146 | "curve": [ 0.163, 0.91, 1, 1 ] 147 | }, 148 | { "time": 1.3333, "angle": 45.23 } 149 | ], 150 | "scale": [ 151 | { "time": 0, "x": 1.098, "y": 1 }, 152 | { "time": 0.1666, "x": 1, "y": 0.826 }, 153 | { "time": 0.3333, "x": 1.098, "y": 1 }, 154 | { "time": 0.5, "x": 1, "y": 0.826 }, 155 | { "time": 0.6666, "x": 1.098, "y": 1 }, 156 | { "time": 0.8333, "x": 1, "y": 0.826 }, 157 | { "time": 1, "x": 1.098, "y": 1 }, 158 | { "time": 1.1666, "x": 1, "y": 0.826 }, 159 | { "time": 1.3333, "x": 1.098, "y": 1 } 160 | ] 161 | }, 162 | "right wing": { 163 | "rotate": [ 164 | { 165 | "time": 0, 166 | "angle": -39.45, 167 | "curve": [ 0.327, 0, 0.637, 1 ] 168 | }, 169 | { 170 | "time": 0.1666, 171 | "angle": 37.67, 172 | "curve": [ 0.163, 0.91, 1, 1 ] 173 | }, 174 | { 175 | "time": 0.3333, 176 | "angle": -39.45, 177 | "curve": [ 0.327, 0, 0.637, 1 ] 178 | }, 179 | { 180 | "time": 0.5, 181 | "angle": 37.67, 182 | "curve": [ 0.163, 0.91, 1, 1 ] 183 | }, 184 | { 185 | "time": 0.6666, 186 | "angle": -39.45, 187 | "curve": [ 0.327, 0, 0.637, 1 ] 188 | }, 189 | { 190 | "time": 0.8333, 191 | "angle": 37.67, 192 | "curve": [ 0.163, 0.91, 1, 1 ] 193 | }, 194 | { 195 | "time": 1, 196 | "angle": -39.45, 197 | "curve": [ 0.327, 0, 0.637, 1 ] 198 | }, 199 | { 200 | "time": 1.1666, 201 | "angle": 37.67, 202 | "curve": [ 0.163, 0.91, 1, 1 ] 203 | }, 204 | { "time": 1.3333, "angle": -39.45 } 205 | ], 206 | "scale": [ 207 | { "time": 0, "x": 1.09, "y": 1 }, 208 | { "time": 0.1666, "x": 1, "y": 0.819 }, 209 | { "time": 0.3333, "x": 1.09, "y": 1 }, 210 | { "time": 0.5, "x": 1, "y": 0.819 }, 211 | { "time": 0.6666, "x": 1.09, "y": 1 }, 212 | { "time": 0.8333, "x": 1, "y": 0.819 }, 213 | { "time": 1, "x": 1.09, "y": 1 }, 214 | { "time": 1.1666, "x": 1, "y": 0.819 }, 215 | { "time": 1.3333, "x": 1.09, "y": 1 } 216 | ] 217 | }, 218 | "tokenRoot": { 219 | "rotate": [ 220 | { "time": 0, "angle": 11.29 }, 221 | { "time": 0.3333, "angle": 2.5 }, 222 | { "time": 0.6666, "angle": -12.5 }, 223 | { "time": 1, "angle": 0.63 }, 224 | { "time": 1.3333, "angle": 11.29 } 225 | ] 226 | }, 227 | "token": { 228 | "rotate": [ 229 | { "time": 0, "angle": -0.5 }, 230 | { "time": 0.6666, "angle": 5.86 }, 231 | { "time": 1.3333, "angle": -0.5 } 232 | ], 233 | "scale": [ 234 | { "time": 0, "x": 1.139, "y": 1.139 }, 235 | { "time": 0.3333, "x": 1, "y": 1 }, 236 | { "time": 0.6666, "x": 1.139, "y": 1.139 }, 237 | { "time": 1, "x": 1, "y": 1 }, 238 | { "time": 1.3333, "x": 1.139, "y": 1.139 } 239 | ] 240 | }, 241 | "star": { 242 | "rotate": [ 243 | { "time": 0, "angle": 28.25 }, 244 | { "time": 0.6666, "angle": -42.08 } 245 | ], 246 | "translate": [ 247 | { "time": 0, "x": 0, "y": 0 }, 248 | { "time": 0.6666, "x": 86.68, "y": 68.32 } 249 | ], 250 | "scale": [ 251 | { "time": 0, "x": 0.439, "y": 0.439 }, 252 | { "time": 0.6666, "x": 1, "y": 1 } 253 | ] 254 | }, 255 | "star1": { 256 | "rotate": [ 257 | { "time": 0.2666, "angle": 13.37 }, 258 | { "time": 0.9333, "angle": 89.61 } 259 | ], 260 | "translate": [ 261 | { "time": 0.2666, "x": -12.16, "y": -2.27 }, 262 | { "time": 0.9333, "x": -76.4, "y": 67.76 } 263 | ], 264 | "scale": [ 265 | { "time": 0.2666, "x": 0.391, "y": 0.391 }, 266 | { "time": 0.9333, "x": 0.815, "y": 0.815 } 267 | ] 268 | }, 269 | "star2": { 270 | "rotate": [ 271 | { "time": 0.1333, "angle": -42.67 }, 272 | { "time": 0.8, "angle": 88.41 } 273 | ], 274 | "translate": [ 275 | { "time": 0.1333, "x": -18.32, "y": -18.91 }, 276 | { "time": 0.8, "x": -57.85, "y": -97.4 } 277 | ], 278 | "scale": [ 279 | { "time": 0.1333, "x": 0.211, "y": 0.211 }, 280 | { "time": 0.8, "x": 0.652, "y": 0.652 } 281 | ] 282 | }, 283 | "star3": { 284 | "rotate": [ 285 | { "time": 0.4333, "angle": 57.71 }, 286 | { "time": 1.1, "angle": -105.15 } 287 | ], 288 | "translate": [ 289 | { "time": 0.4333, "x": 36.1, "y": -40.52 }, 290 | { "time": 1.1, "x": 69, "y": -78.3 } 291 | ], 292 | "scale": [ 293 | { "time": 0.4333, "x": 0.24, "y": 0.24 }, 294 | { "time": 1.1, "x": 0.776, "y": 0.776 } 295 | ] 296 | }, 297 | "star4": { 298 | "rotate": [ 299 | { "time": 0.6, "angle": 37.65 }, 300 | { "time": 1.2666, "angle": -102.15 } 301 | ], 302 | "translate": [ 303 | { "time": 0.6, "x": 8.65, "y": -12.98 }, 304 | { "time": 1.2666, "x": -0.99, "y": 82.82 } 305 | ], 306 | "scale": [ 307 | { "time": 0.6, "x": 0.275, "y": 0.275 }, 308 | { "time": 1.2666, "x": 1.081, "y": 1.081 } 309 | ] 310 | }, 311 | "star5": { 312 | "rotate": [ 313 | { "time": 0, "angle": 18.27 }, 314 | { "time": 0.3333, "angle": 83.73, "curve": "stepped" }, 315 | { "time": 1, "angle": -47.17 }, 316 | { "time": 1.3333, "angle": 18.27 } 317 | ], 318 | "translate": [ 319 | { "time": 0, "x": -67.74, "y": -7.78 }, 320 | { "time": 0.3333, "x": -102.83, "y": -22.36, "curve": "stepped" }, 321 | { "time": 1, "x": -32.63, "y": 6.8 }, 322 | { "time": 1.3333, "x": -67.74, "y": -7.78 } 323 | ], 324 | "scale": [ 325 | { "time": 0, "x": 0.565, "y": 0.565 }, 326 | { "time": 0.3333, "x": 0.791, "y": 0.791, "curve": "stepped" }, 327 | { "time": 1, "x": 0.34, "y": 0.34 }, 328 | { "time": 1.3333, "x": 0.565, "y": 0.565 } 329 | ] 330 | }, 331 | "star6": { 332 | "rotate": [ 333 | { "time": 0, "angle": 25.23 }, 334 | { "time": 0.5666, "angle": -73.06, "curve": "stepped" }, 335 | { "time": 1.2333, "angle": 42.58 }, 336 | { "time": 1.3333, "angle": 25.23 } 337 | ], 338 | "translate": [ 339 | { "time": 0, "x": 4.55, "y": -14.21 }, 340 | { "time": 0.5666, "x": 30.36, "y": -94.75, "curve": "stepped" }, 341 | { "time": 1.2333, "x": 0, "y": 0 }, 342 | { "time": 1.3333, "x": 4.55, "y": -14.21 } 343 | ], 344 | "scale": [ 345 | { "time": 0, "x": 0.337, "y": 0.337 }, 346 | { "time": 0.5666, "x": 0.955, "y": 0.955, "curve": "stepped" }, 347 | { "time": 1.2333, "x": 0.227, "y": 0.227 }, 348 | { "time": 1.3333, "x": 0.337, "y": 0.337 } 349 | ] 350 | }, 351 | "star7": { 352 | "rotate": [ 353 | { "time": 0.6333, "angle": 41.11 }, 354 | { "time": 1.3, "angle": -89.84 } 355 | ], 356 | "translate": [ 357 | { "time": 0.6333, "x": 20.27, "y": 32.75 }, 358 | { "time": 1.3, "x": -67.79, "y": -68.56 } 359 | ], 360 | "scale": [ 361 | { "time": 0.6333, "x": 0.258, "y": 0.258 }, 362 | { "time": 1.3, "x": 0.999, "y": 0.999 } 363 | ] 364 | }, 365 | "star9": { 366 | "rotate": [ 367 | { "time": 0, "angle": 49.48 }, 368 | { "time": 0.1333, "angle": 71.89, "curve": "stepped" }, 369 | { "time": 0.8, "angle": -40.17 }, 370 | { "time": 1.3333, "angle": 49.48 } 371 | ], 372 | "translate": [ 373 | { "time": 0, "x": -78.75, "y": 77.18 }, 374 | { "time": 0.1333, "x": -98.44, "y": 96.47, "curve": "stepped" }, 375 | { "time": 0.8, "x": 0, "y": 0 }, 376 | { "time": 1.3333, "x": -78.75, "y": 77.18 } 377 | ], 378 | "scale": [ 379 | { "time": 0, "x": 0.772, "y": 0.772 }, 380 | { "time": 0.1333, "x": 0.91, "y": 0.91, "curve": "stepped" }, 381 | { "time": 0.8, "x": 0.221, "y": 0.221 }, 382 | { "time": 1.3333, "x": 0.772, "y": 0.772 } 383 | ] 384 | }, 385 | "star8": { 386 | "rotate": [ 387 | { "time": 0, "angle": -60.17 }, 388 | { "time": 0.2666, "angle": -109.83, "curve": "stepped" }, 389 | { "time": 0.9333, "angle": 14.31 }, 390 | { "time": 1.3333, "angle": -60.17 } 391 | ], 392 | "translate": [ 393 | { "time": 0, "x": 44.63, "y": -41.66 }, 394 | { "time": 0.2666, "x": 74.39, "y": -69.43, "curve": "stepped" }, 395 | { "time": 0.9333, "x": 0, "y": 0 }, 396 | { "time": 1.3333, "x": 44.63, "y": -41.66 } 397 | ], 398 | "scale": [ 399 | { "time": 0, "x": 0.452, "y": 0.452 }, 400 | { "time": 0.2666, "x": 0.672, "y": 0.672, "curve": "stepped" }, 401 | { "time": 0.9333, "x": 0.123, "y": 0.123 }, 402 | { "time": 1.3333, "x": 0.452, "y": 0.452 } 403 | ] 404 | } 405 | }, 406 | "slots": { 407 | "star7": { 408 | "color": [ 409 | { "time": 0.6333, "color": "ffffff00" }, 410 | { "time": 1.1666, "color": "ffffffff" }, 411 | { "time": 1.3, "color": "ffffff00" } 412 | ] 413 | }, 414 | "star1": { 415 | "color": [ 416 | { "time": 0.2666, "color": "fff9f600" }, 417 | { "time": 0.8, "color": "ffffffff" }, 418 | { "time": 0.9333, "color": "fff0f200" } 419 | ] 420 | }, 421 | "star4": { 422 | "color": [ 423 | { "time": 0.6, "color": "ffffff00" }, 424 | { "time": 1.1333, "color": "ffffffff" }, 425 | { "time": 1.2666, "color": "ffffff00" } 426 | ] 427 | }, 428 | "star3": { 429 | "color": [ 430 | { "time": 0.4333, "color": "ffffff00" }, 431 | { "time": 0.9666, "color": "ffffffff" }, 432 | { "time": 1.1, "color": "ffffff00" } 433 | ] 434 | }, 435 | "star8": { 436 | "color": [ 437 | { "time": 0, "color": "ffffffbf" }, 438 | { "time": 0.1333, "color": "ffffffff" }, 439 | { "time": 0.2666, "color": "ffffff00", "curve": "stepped" }, 440 | { "time": 0.9333, "color": "ffffff00" }, 441 | { "time": 1.3333, "color": "ffffffbf" } 442 | ] 443 | }, 444 | "star": { 445 | "color": [ 446 | { "time": 0, "color": "ffffff00" }, 447 | { "time": 0.5333, "color": "ffffffff" }, 448 | { "time": 0.6666, "color": "ffffff00" } 449 | ] 450 | }, 451 | "star9": { 452 | "color": [ 453 | { "time": 0, "color": "ffffffff" }, 454 | { "time": 0.1333, "color": "ffffff00", "curve": "stepped" }, 455 | { "time": 0.8, "color": "ffffff00" }, 456 | { "time": 1.3333, "color": "ffffffff" } 457 | ] 458 | }, 459 | "star2": { 460 | "color": [ 461 | { "time": 0.1333, "color": "ffffff00" }, 462 | { "time": 0.6666, "color": "ffffffff" }, 463 | { "time": 0.8, "color": "ffffff00" } 464 | ] 465 | }, 466 | "star5": { 467 | "color": [ 468 | { "time": 0, "color": "ffffff9f" }, 469 | { "time": 0.2, "color": "ffffffff" }, 470 | { "time": 0.3333, "color": "ffffff00", "curve": "stepped" }, 471 | { "time": 1, "color": "ffffff00" }, 472 | { "time": 1.3333, "color": "ffffff9f" } 473 | ] 474 | }, 475 | "star6": { 476 | "color": [ 477 | { "time": 0, "color": "ffffff2f" }, 478 | { "time": 0.4333, "color": "ffffffff" }, 479 | { "time": 0.5666, "color": "ffffff00", "curve": "stepped" }, 480 | { "time": 1.2333, "color": "ffffff00" }, 481 | { "time": 1.3333, "color": "ffffff2f" } 482 | ] 483 | } 484 | } 485 | } 486 | } 487 | } -------------------------------------------------------------------------------- /pyguts/examples/data/powerup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/powerup.png -------------------------------------------------------------------------------- /pyguts/examples/data/spineboy.atlas: -------------------------------------------------------------------------------- 1 | 2 | data/spineboy.png 3 | format: RGBA8888 4 | filter: Nearest,Nearest 5 | repeat: none 6 | head 7 | rotate: false 8 | xy: 1, 122 9 | size: 121, 132 10 | orig: 121, 132 11 | offset: 0, 0 12 | index: -1 13 | torso 14 | rotate: false 15 | xy: 1, 28 16 | size: 68, 92 17 | orig: 68, 92 18 | offset: 0, 0 19 | index: -1 20 | left-pant-bottom 21 | rotate: false 22 | xy: 1, 4 23 | size: 44, 22 24 | orig: 44, 22 25 | offset: 0, 0 26 | index: -1 27 | right-pant-bottom 28 | rotate: false 29 | xy: 47, 8 30 | size: 46, 18 31 | orig: 46, 18 32 | offset: 0, 0 33 | index: -1 34 | right-upper-leg 35 | rotate: false 36 | xy: 71, 50 37 | size: 44, 70 38 | orig: 44, 70 39 | offset: 0, 0 40 | index: -1 41 | pelvis 42 | rotate: false 43 | xy: 95, 1 44 | size: 63, 47 45 | orig: 63, 47 46 | offset: 0, 0 47 | index: -1 48 | left-upper-leg 49 | rotate: false 50 | xy: 117, 53 51 | size: 33, 67 52 | orig: 33, 67 53 | offset: 0, 0 54 | index: -1 55 | right-foot 56 | rotate: false 57 | xy: 160, 224 58 | size: 67, 30 59 | orig: 67, 30 60 | offset: 0, 0 61 | index: -1 62 | left-shoulder 63 | rotate: false 64 | xy: 124, 201 65 | size: 34, 53 66 | orig: 34, 53 67 | offset: 0, 0 68 | index: -1 69 | left-ankle 70 | rotate: false 71 | xy: 229, 222 72 | size: 25, 32 73 | orig: 25, 32 74 | offset: 0, 0 75 | index: -1 76 | left-foot 77 | rotate: false 78 | xy: 160, 192 79 | size: 65, 30 80 | orig: 65, 30 81 | offset: 0, 0 82 | index: -1 83 | neck 84 | rotate: false 85 | xy: 124, 171 86 | size: 34, 28 87 | orig: 34, 28 88 | offset: 0, 0 89 | index: -1 90 | right-arm 91 | rotate: false 92 | xy: 124, 124 93 | size: 21, 45 94 | orig: 21, 45 95 | offset: 0, 0 96 | index: -1 97 | right-ankle 98 | rotate: false 99 | xy: 227, 190 100 | size: 25, 30 101 | orig: 25, 30 102 | offset: 0, 0 103 | index: -1 104 | left-hand 105 | rotate: false 106 | xy: 147, 131 107 | size: 35, 38 108 | orig: 35, 38 109 | offset: 0, 0 110 | index: -1 111 | left-arm 112 | rotate: false 113 | xy: 184, 161 114 | size: 35, 29 115 | orig: 35, 29 116 | offset: 0, 0 117 | index: -1 118 | eyes-closed 119 | rotate: false 120 | xy: 221, 161 121 | size: 34, 27 122 | orig: 34, 27 123 | offset: 0, 0 124 | index: -1 125 | right-lower-leg 126 | rotate: false 127 | xy: 152, 65 128 | size: 51, 64 129 | orig: 51, 64 130 | offset: 0, 0 131 | index: -1 132 | right-foot-idle 133 | rotate: false 134 | xy: 184, 131 135 | size: 53, 28 136 | orig: 53, 28 137 | offset: 0, 0 138 | index: -1 139 | left-lower-leg 140 | rotate: false 141 | xy: 205, 65 142 | size: 49, 64 143 | orig: 49, 64 144 | offset: 0, 0 145 | index: -1 146 | right-shoulder 147 | rotate: false 148 | xy: 160, 12 149 | size: 52, 51 150 | orig: 52, 51 151 | offset: 0, 0 152 | index: -1 153 | eyes 154 | rotate: false 155 | xy: 214, 36 156 | size: 34, 27 157 | orig: 34, 27 158 | offset: 0, 0 159 | index: -1 160 | right-hand 161 | rotate: false 162 | xy: 214, 2 163 | size: 32, 32 164 | orig: 32, 32 165 | offset: 0, 0 166 | index: -1 167 | -------------------------------------------------------------------------------- /pyguts/examples/data/spineboy.json: -------------------------------------------------------------------------------- 1 | { 2 | "bones": [ 3 | { "name": "root" }, 4 | { "name": "hip", "parent": "root", "x": 0.64, "y": 114.41 }, 5 | { "name": "left upper leg", "parent": "hip", "length": 50.39, "x": 14.45, "y": 2.81, "rotation": -89.09 }, 6 | { "name": "left lower leg", "parent": "left upper leg", "length": 56.45, "x": 51.78, "y": 3.46, "rotation": -16.65 }, 7 | { "name": "left foot", "parent": "left lower leg", "length": 46.5, "x": 64.02, "y": -8.67, "rotation": 102.43 }, 8 | { "name": "right upper leg", "parent": "hip", "length": 45.76, "x": -18.27, "rotation": -101.13 }, 9 | { "name": "right lower leg", "parent": "right upper leg", "length": 58.52, "x": 50.21, "y": 0.6, "rotation": -10.7 }, 10 | { "name": "right foot", "parent": "right lower leg", "length": 45.45, "x": 64.88, "y": 0.04, "rotation": 110.3 }, 11 | { "name": "torso", "parent": "hip", "length": 85.82, "x": -6.42, "y": 1.97, "rotation": 94.95 }, 12 | { "name": "neck", "parent": "torso", "length": 18.38, "x": 83.64, "y": -1.78, "rotation": 0.9 }, 13 | { "name": "head", "parent": "neck", "length": 68.28, "x": 19.09, "y": 6.97, "rotation": -8.94 }, 14 | { "name": "right shoulder", "parent": "torso", "length": 49.95, "x": 81.9, "y": 6.79, "rotation": 130.6 }, 15 | { "name": "right arm", "parent": "right shoulder", "length": 36.74, "x": 49.95, "y": -0.12, "rotation": 40.12 }, 16 | { "name": "right hand", "parent": "right arm", "length": 15.32, "x": 36.9, "y": 0.34, "rotation": 2.35 }, 17 | { "name": "left shoulder", "parent": "torso", "length": 44.19, "x": 78.96, "y": -15.75, "rotation": -156.96 }, 18 | { "name": "left arm", "parent": "left shoulder", "length": 35.62, "x": 44.19, "y": -0.01, "rotation": 28.16 }, 19 | { "name": "left hand", "parent": "left arm", "length": 11.52, "x": 35.62, "y": 0.07, "rotation": 2.7 }, 20 | { "name": "pelvis", "parent": "hip", "x": 1.41, "y": -6.57 } 21 | ], 22 | "slots": [ 23 | { "name": "left shoulder", "bone": "left shoulder", "attachment": "left-shoulder" }, 24 | { "name": "left arm", "bone": "left arm", "attachment": "left-arm" }, 25 | { "name": "left hand", "bone": "left hand", "attachment": "left-hand" }, 26 | { "name": "left foot", "bone": "left foot", "attachment": "left-foot" }, 27 | { "name": "left lower leg", "bone": "left lower leg", "attachment": "left-lower-leg" }, 28 | { "name": "left upper leg", "bone": "left upper leg", "attachment": "left-upper-leg" }, 29 | { "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" }, 30 | { "name": "right foot", "bone": "right foot", "attachment": "right-foot" }, 31 | { "name": "right lower leg", "bone": "right lower leg", "attachment": "right-lower-leg" }, 32 | { "name": "right upper leg", "bone": "right upper leg", "attachment": "right-upper-leg" }, 33 | { "name": "torso", "bone": "torso", "attachment": "torso" }, 34 | { "name": "neck", "bone": "neck", "attachment": "neck" }, 35 | { "name": "head", "bone": "head", "attachment": "head" }, 36 | { "name": "eyes", "bone": "head", "attachment": "eyes" }, 37 | { "name": "right shoulder", "bone": "right shoulder", "attachment": "right-shoulder" }, 38 | { "name": "right arm", "bone": "right arm", "attachment": "right-arm" }, 39 | { "name": "right hand", "bone": "right hand", "attachment": "right-hand" } 40 | ], 41 | "skins": { 42 | "default": { 43 | "left shoulder": { 44 | "left-shoulder": { "x": 23.74, "y": 0.11, "rotation": 62.01, "width": 34, "height": 53 } 45 | }, 46 | "left arm": { 47 | "left-arm": { "x": 15.11, "y": -0.44, "rotation": 33.84, "width": 35, "height": 29 } 48 | }, 49 | "left hand": { 50 | "left-hand": { "x": 0.75, "y": 1.86, "rotation": 31.14, "width": 35, "height": 38 } 51 | }, 52 | "left foot": { 53 | "left-foot": { "x": 24.35, "y": 8.88, "rotation": 3.32, "width": 65, "height": 30 } 54 | }, 55 | "left lower leg": { 56 | "left-lower-leg": { "x": 24.55, "y": -1.92, "rotation": 105.75, "width": 49, "height": 64 } 57 | }, 58 | "left upper leg": { 59 | "left-upper-leg": { "x": 26.12, "y": -1.85, "rotation": 89.09, "width": 33, "height": 67 } 60 | }, 61 | "pelvis": { 62 | "pelvis": { "x": -4.83, "y": 10.62, "width": 63, "height": 47 } 63 | }, 64 | "right foot": { 65 | "right-foot": { "x": 19.02, "y": 8.47, "rotation": 1.52, "width": 67, "height": 30 } 66 | }, 67 | "right lower leg": { 68 | "right-lower-leg": { "x": 23.28, "y": -2.59, "rotation": 111.83, "width": 51, "height": 64 } 69 | }, 70 | "right upper leg": { 71 | "right-upper-leg": { "x": 23.03, "y": 0.25, "rotation": 101.13, "width": 44, "height": 70 } 72 | }, 73 | "torso": { 74 | "torso": { "x": 44.57, "y": -7.08, "rotation": -94.95, "width": 68, "height": 92 } 75 | }, 76 | "neck": { 77 | "neck": { "x": 9.42, "y": -3.66, "rotation": -100.15, "width": 34, "height": 28 } 78 | }, 79 | "head": { 80 | "head": { "x": 53.94, "y": -5.75, "rotation": -86.9, "width": 121, "height": 132 } 81 | }, 82 | "eyes": { 83 | "eyes": { "x": 28.94, "y": -32.92, "rotation": -86.9, "width": 34, "height": 27 }, 84 | "eyes-closed": { "x": 28.77, "y": -32.86, "rotation": -86.9, "width": 34, "height": 27 } 85 | }, 86 | "right shoulder": { 87 | "right-shoulder": { "x": 25.86, "y": 0.03, "rotation": 134.44, "width": 52, "height": 51 } 88 | }, 89 | "right arm": { 90 | "right-arm": { "x": 18.34, "y": -2.64, "rotation": 94.32, "width": 21, "height": 45 } 91 | }, 92 | "right hand": { 93 | "right-hand": { "x": 6.82, "y": 1.25, "rotation": 91.96, "width": 32, "height": 32 } 94 | } 95 | } 96 | }, 97 | "animations": { 98 | "walk": { 99 | "bones": { 100 | "left upper leg": { 101 | "rotate": [ 102 | { "time": 0, "angle": -26.55 }, 103 | { "time": 0.1333, "angle": -8.78 }, 104 | { "time": 0.2666, "angle": 9.51 }, 105 | { "time": 0.4, "angle": 30.74 }, 106 | { "time": 0.5333, "angle": 25.33 }, 107 | { "time": 0.6666, "angle": 26.11 }, 108 | { "time": 0.8, "angle": -7.7 }, 109 | { "time": 0.9333, "angle": -21.19 }, 110 | { "time": 1.0666, "angle": -26.55 } 111 | ], 112 | "translate": [ 113 | { "time": 0, "x": -3, "y": -2.25 }, 114 | { "time": 0.4, "x": -2.18, "y": -2.25 }, 115 | { "time": 1.0666, "x": -3, "y": -2.25 } 116 | ] 117 | }, 118 | "right upper leg": { 119 | "rotate": [ 120 | { "time": 0, "angle": 42.45 }, 121 | { "time": 0.1333, "angle": 52.1 }, 122 | { "time": 0.2666, "angle": 5.96 }, 123 | { "time": 0.5333, "angle": -16.93 }, 124 | { "time": 0.6666, "angle": 1.89 }, 125 | { 126 | "time": 0.8, 127 | "angle": 28.06, 128 | "curve": [ 0.462, 0.11, 1, 1 ] 129 | }, 130 | { 131 | "time": 0.9333, 132 | "angle": 58.68, 133 | "curve": [ 0.5, 0.02, 1, 1 ] 134 | }, 135 | { "time": 1.0666, "angle": 42.45 } 136 | ], 137 | "translate": [ 138 | { "time": 0, "x": 8.11, "y": -2.36 }, 139 | { "time": 0.1333, "x": 10.03, "y": -2.56 }, 140 | { "time": 0.4, "x": 2.76, "y": -2.97 }, 141 | { "time": 0.5333, "x": 2.76, "y": -2.81 }, 142 | { "time": 0.9333, "x": 8.67, "y": -2.54 }, 143 | { "time": 1.0666, "x": 8.11, "y": -2.36 } 144 | ] 145 | }, 146 | "left lower leg": { 147 | "rotate": [ 148 | { "time": 0, "angle": -10.21 }, 149 | { "time": 0.1333, "angle": -55.64 }, 150 | { "time": 0.2666, "angle": -68.12 }, 151 | { "time": 0.5333, "angle": 5.11 }, 152 | { "time": 0.6666, "angle": -28.29 }, 153 | { "time": 0.8, "angle": 4.08 }, 154 | { "time": 0.9333, "angle": 3.53 }, 155 | { "time": 1.0666, "angle": -10.21 } 156 | ] 157 | }, 158 | "left foot": { 159 | "rotate": [ 160 | { "time": 0, "angle": -3.69 }, 161 | { "time": 0.1333, "angle": -10.42 }, 162 | { "time": 0.2666, "angle": -17.14 }, 163 | { "time": 0.4, "angle": -2.83 }, 164 | { "time": 0.5333, "angle": -3.87 }, 165 | { "time": 0.6666, "angle": 2.78 }, 166 | { "time": 0.8, "angle": 1.68 }, 167 | { "time": 0.9333, "angle": -8.54 }, 168 | { "time": 1.0666, "angle": -3.69 } 169 | ] 170 | }, 171 | "right shoulder": { 172 | "rotate": [ 173 | { 174 | "time": 0, 175 | "angle": 20.89, 176 | "curve": [ 0.264, 0, 0.75, 1 ] 177 | }, 178 | { 179 | "time": 0.1333, 180 | "angle": 3.72, 181 | "curve": [ 0.272, 0, 0.841, 1 ] 182 | }, 183 | { "time": 0.6666, "angle": -278.28 }, 184 | { "time": 1.0666, "angle": 20.89 } 185 | ], 186 | "translate": [ 187 | { "time": 0, "x": -7.84, "y": 7.19 }, 188 | { "time": 0.1333, "x": -6.36, "y": 6.42 }, 189 | { "time": 0.6666, "x": -11.07, "y": 5.25 }, 190 | { "time": 1.0666, "x": -7.84, "y": 7.19 } 191 | ] 192 | }, 193 | "right arm": { 194 | "rotate": [ 195 | { 196 | "time": 0, 197 | "angle": -4.02, 198 | "curve": [ 0.267, 0, 0.804, 0.99 ] 199 | }, 200 | { 201 | "time": 0.1333, 202 | "angle": -13.99, 203 | "curve": [ 0.341, 0, 1, 1 ] 204 | }, 205 | { 206 | "time": 0.6666, 207 | "angle": 36.54, 208 | "curve": [ 0.307, 0, 0.787, 0.99 ] 209 | }, 210 | { "time": 1.0666, "angle": -4.02 } 211 | ] 212 | }, 213 | "right hand": { 214 | "rotate": [ 215 | { "time": 0, "angle": 22.92 }, 216 | { "time": 0.4, "angle": -8.97 }, 217 | { "time": 0.6666, "angle": 0.51 }, 218 | { "time": 1.0666, "angle": 22.92 } 219 | ] 220 | }, 221 | "left shoulder": { 222 | "rotate": [ 223 | { "time": 0, "angle": -1.47 }, 224 | { "time": 0.1333, "angle": 13.6 }, 225 | { "time": 0.6666, "angle": 280.74 }, 226 | { "time": 1.0666, "angle": -1.47 } 227 | ], 228 | "translate": [ 229 | { "time": 0, "x": -1.76, "y": 0.56 }, 230 | { "time": 0.6666, "x": -2.47, "y": 8.14 }, 231 | { "time": 1.0666, "x": -1.76, "y": 0.56 } 232 | ] 233 | }, 234 | "left hand": { 235 | "rotate": [ 236 | { 237 | "time": 0, 238 | "angle": 11.58, 239 | "curve": [ 0.169, 0.37, 0.632, 1.55 ] 240 | }, 241 | { 242 | "time": 0.1333, 243 | "angle": 28.13, 244 | "curve": [ 0.692, 0, 0.692, 0.99 ] 245 | }, 246 | { 247 | "time": 0.6666, 248 | "angle": -27.42, 249 | "curve": [ 0.117, 0.41, 0.738, 1.76 ] 250 | }, 251 | { "time": 0.8, "angle": -36.32 }, 252 | { "time": 1.0666, "angle": 11.58 } 253 | ] 254 | }, 255 | "left arm": { 256 | "rotate": [ 257 | { "time": 0, "angle": -8.27 }, 258 | { "time": 0.1333, "angle": 18.43 }, 259 | { "time": 0.6666, "angle": 0.88 }, 260 | { "time": 1.0666, "angle": -8.27 } 261 | ] 262 | }, 263 | "torso": { 264 | "rotate": [ 265 | { "time": 0, "angle": -10.28 }, 266 | { 267 | "time": 0.1333, 268 | "angle": -15.38, 269 | "curve": [ 0.545, 0, 1, 1 ] 270 | }, 271 | { 272 | "time": 0.4, 273 | "angle": -9.78, 274 | "curve": [ 0.58, 0.17, 1, 1 ] 275 | }, 276 | { "time": 0.6666, "angle": -15.75 }, 277 | { "time": 0.9333, "angle": -7.06 }, 278 | { "time": 1.0666, "angle": -10.28 } 279 | ], 280 | "translate": [ 281 | { "time": 0, "x": -3.67, "y": 1.68 }, 282 | { "time": 0.1333, "x": -3.67, "y": 0.68 }, 283 | { "time": 0.4, "x": -3.67, "y": 1.97 }, 284 | { "time": 0.6666, "x": -3.67, "y": -0.14 }, 285 | { "time": 1.0666, "x": -3.67, "y": 1.68 } 286 | ] 287 | }, 288 | "right foot": { 289 | "rotate": [ 290 | { "time": 0, "angle": -5.25 }, 291 | { "time": 0.2666, "angle": -4.08 }, 292 | { "time": 0.4, "angle": -6.45 }, 293 | { "time": 0.5333, "angle": -5.39 }, 294 | { "time": 0.8, "angle": -11.68 }, 295 | { "time": 0.9333, "angle": 0.46 }, 296 | { "time": 1.0666, "angle": -5.25 } 297 | ] 298 | }, 299 | "right lower leg": { 300 | "rotate": [ 301 | { "time": 0, "angle": -3.39 }, 302 | { "time": 0.1333, "angle": -45.53 }, 303 | { "time": 0.2666, "angle": -2.59 }, 304 | { "time": 0.5333, "angle": -19.53 }, 305 | { "time": 0.6666, "angle": -64.8 }, 306 | { 307 | "time": 0.8, 308 | "angle": -82.56, 309 | "curve": [ 0.557, 0.18, 1, 1 ] 310 | }, 311 | { "time": 1.0666, "angle": -3.39 } 312 | ] 313 | }, 314 | "hip": { 315 | "rotate": [ 316 | { "time": 0, "angle": 0, "curve": "stepped" }, 317 | { "time": 1.0666, "angle": 0 } 318 | ], 319 | "translate": [ 320 | { "time": 0, "x": 0, "y": 0 }, 321 | { 322 | "time": 0.1333, 323 | "x": 0, 324 | "y": -7.61, 325 | "curve": [ 0.272, 0.86, 1, 1 ] 326 | }, 327 | { "time": 0.4, "x": 0, "y": 8.7 }, 328 | { "time": 0.5333, "x": 0, "y": -0.41 }, 329 | { 330 | "time": 0.6666, 331 | "x": 0, 332 | "y": -7.05, 333 | "curve": [ 0.235, 0.89, 1, 1 ] 334 | }, 335 | { "time": 0.8, "x": 0, "y": 2.92 }, 336 | { "time": 0.9333, "x": 0, "y": 6.78 }, 337 | { "time": 1.0666, "x": 0, "y": 0 } 338 | ] 339 | }, 340 | "neck": { 341 | "rotate": [ 342 | { "time": 0, "angle": 3.6 }, 343 | { "time": 0.1333, "angle": 17.49 }, 344 | { "time": 0.2666, "angle": 6.1 }, 345 | { "time": 0.4, "angle": 3.45 }, 346 | { "time": 0.5333, "angle": 5.17 }, 347 | { "time": 0.6666, "angle": 18.36 }, 348 | { "time": 0.8, "angle": 6.09 }, 349 | { "time": 0.9333, "angle": 2.28 }, 350 | { "time": 1.0666, "angle": 3.6 } 351 | ] 352 | }, 353 | "head": { 354 | "rotate": [ 355 | { 356 | "time": 0, 357 | "angle": 3.6, 358 | "curve": [ 0, 0, 0.704, 1.61 ] 359 | }, 360 | { "time": 0.1666, "angle": -0.2 }, 361 | { "time": 0.2666, "angle": 6.1 }, 362 | { "time": 0.4, "angle": 3.45 }, 363 | { 364 | "time": 0.5333, 365 | "angle": 5.17, 366 | "curve": [ 0, 0, 0.704, 1.61 ] 367 | }, 368 | { "time": 0.7, "angle": 1.1 }, 369 | { "time": 0.8, "angle": 6.09 }, 370 | { "time": 0.9333, "angle": 2.28 }, 371 | { "time": 1.0666, "angle": 3.6 } 372 | ] 373 | } 374 | } 375 | }, 376 | "jump": { 377 | "bones": { 378 | "hip": { 379 | "rotate": [ 380 | { "time": 0, "angle": 0, "curve": "stepped" }, 381 | { "time": 0.9333, "angle": 0, "curve": "stepped" }, 382 | { "time": 1.3666, "angle": 0 } 383 | ], 384 | "translate": [ 385 | { "time": 0, "x": -11.57, "y": -3 }, 386 | { "time": 0.2333, "x": -16.2, "y": -19.43 }, 387 | { 388 | "time": 0.3333, 389 | "x": 7.66, 390 | "y": -8.48, 391 | "curve": [ 0.057, 0.06, 0.712, 1 ] 392 | }, 393 | { "time": 0.3666, "x": 15.38, "y": 5.01 }, 394 | { "time": 0.4666, "x": -7.84, "y": 57.22 }, 395 | { 396 | "time": 0.6, 397 | "x": -10.81, 398 | "y": 96.34, 399 | "curve": [ 0.241, 0, 1, 1 ] 400 | }, 401 | { "time": 0.7333, "x": -7.01, "y": 54.7 }, 402 | { "time": 0.8, "x": -10.58, "y": 32.2 }, 403 | { "time": 0.9333, "x": -31.99, "y": 0.45 }, 404 | { "time": 1.0666, "x": -12.48, "y": -29.47 }, 405 | { "time": 1.3666, "x": -11.57, "y": -3 } 406 | ], 407 | "scale": [ 408 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 409 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 410 | { "time": 1.3666, "x": 1, "y": 1 } 411 | ] 412 | }, 413 | "left upper leg": { 414 | "rotate": [ 415 | { "time": 0, "angle": 17.13 }, 416 | { "time": 0.2333, "angle": 44.35 }, 417 | { "time": 0.3333, "angle": 16.46 }, 418 | { "time": 0.4, "angle": -9.88 }, 419 | { "time": 0.4666, "angle": -11.42 }, 420 | { "time": 0.5666, "angle": 23.46 }, 421 | { "time": 0.7666, "angle": 71.82 }, 422 | { "time": 0.9333, "angle": 65.53 }, 423 | { "time": 1.0666, "angle": 51.01 }, 424 | { "time": 1.3666, "angle": 17.13 } 425 | ], 426 | "translate": [ 427 | { "time": 0, "x": -3, "y": -2.25, "curve": "stepped" }, 428 | { "time": 0.9333, "x": -3, "y": -2.25, "curve": "stepped" }, 429 | { "time": 1.3666, "x": -3, "y": -2.25 } 430 | ], 431 | "scale": [ 432 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 433 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 434 | { "time": 1.3666, "x": 1, "y": 1 } 435 | ] 436 | }, 437 | "left lower leg": { 438 | "rotate": [ 439 | { "time": 0, "angle": -16.25 }, 440 | { "time": 0.2333, "angle": -52.21 }, 441 | { "time": 0.4, "angle": 15.04 }, 442 | { "time": 0.4666, "angle": -8.95 }, 443 | { "time": 0.5666, "angle": -39.53 }, 444 | { "time": 0.7666, "angle": -27.27 }, 445 | { "time": 0.9333, "angle": -3.52 }, 446 | { "time": 1.0666, "angle": -61.92 }, 447 | { "time": 1.3666, "angle": -16.25 } 448 | ], 449 | "translate": [ 450 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 451 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 452 | { "time": 1.3666, "x": 0, "y": 0 } 453 | ], 454 | "scale": [ 455 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 456 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 457 | { "time": 1.3666, "x": 1, "y": 1 } 458 | ] 459 | }, 460 | "left foot": { 461 | "rotate": [ 462 | { "time": 0, "angle": 0.33 }, 463 | { "time": 0.2333, "angle": 6.2 }, 464 | { "time": 0.3333, "angle": 14.73 }, 465 | { "time": 0.4, "angle": -15.54 }, 466 | { "time": 0.4333, "angle": -21.2 }, 467 | { "time": 0.5666, "angle": -7.55 }, 468 | { "time": 0.7666, "angle": -0.67 }, 469 | { "time": 0.9333, "angle": -0.58 }, 470 | { "time": 1.0666, "angle": 14.64 }, 471 | { "time": 1.3666, "angle": 0.33 } 472 | ], 473 | "translate": [ 474 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 475 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 476 | { "time": 1.3666, "x": 0, "y": 0 } 477 | ], 478 | "scale": [ 479 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 480 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 481 | { "time": 1.3666, "x": 1, "y": 1 } 482 | ] 483 | }, 484 | "right upper leg": { 485 | "rotate": [ 486 | { "time": 0, "angle": 25.97 }, 487 | { "time": 0.2333, "angle": 46.43 }, 488 | { "time": 0.3333, "angle": 22.61 }, 489 | { "time": 0.4, "angle": 2.13 }, 490 | { 491 | "time": 0.4666, 492 | "angle": 0.04, 493 | "curve": [ 0, 0, 0.637, 0.98 ] 494 | }, 495 | { "time": 0.6, "angle": 65.55 }, 496 | { "time": 0.7666, "angle": 64.93 }, 497 | { "time": 0.9333, "angle": 41.08 }, 498 | { "time": 1.0666, "angle": 66.25 }, 499 | { "time": 1.3666, "angle": 25.97 } 500 | ], 501 | "translate": [ 502 | { "time": 0, "x": 5.74, "y": 0.61 }, 503 | { "time": 0.2333, "x": 4.79, "y": 1.79 }, 504 | { "time": 0.3333, "x": 6.05, "y": -4.55 }, 505 | { "time": 0.9333, "x": 4.79, "y": 1.79, "curve": "stepped" }, 506 | { "time": 1.0666, "x": 4.79, "y": 1.79 }, 507 | { "time": 1.3666, "x": 5.74, "y": 0.61 } 508 | ], 509 | "scale": [ 510 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 511 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 512 | { "time": 1.3666, "x": 1, "y": 1 } 513 | ] 514 | }, 515 | "right lower leg": { 516 | "rotate": [ 517 | { "time": 0, "angle": -27.46 }, 518 | { "time": 0.2333, "angle": -64.03 }, 519 | { "time": 0.4, "angle": -48.36 }, 520 | { "time": 0.5666, "angle": -76.86 }, 521 | { "time": 0.7666, "angle": -26.89 }, 522 | { "time": 0.9, "angle": -18.97 }, 523 | { "time": 0.9333, "angle": -14.18 }, 524 | { "time": 1.0666, "angle": -80.45 }, 525 | { "time": 1.3666, "angle": -27.46 } 526 | ], 527 | "translate": [ 528 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 529 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 530 | { "time": 1.3666, "x": 0, "y": 0 } 531 | ], 532 | "scale": [ 533 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 534 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 535 | { "time": 1.3666, "x": 1, "y": 1 } 536 | ] 537 | }, 538 | "right foot": { 539 | "rotate": [ 540 | { "time": 0, "angle": 1.08 }, 541 | { "time": 0.2333, "angle": 16.02 }, 542 | { "time": 0.3, "angle": 12.94 }, 543 | { "time": 0.3333, "angle": 15.16 }, 544 | { "time": 0.4, "angle": -14.7 }, 545 | { "time": 0.4333, "angle": -12.85 }, 546 | { "time": 0.4666, "angle": -19.18 }, 547 | { "time": 0.5666, "angle": -15.82 }, 548 | { "time": 0.6, "angle": -3.59 }, 549 | { "time": 0.7666, "angle": -3.56 }, 550 | { "time": 0.9333, "angle": 1.86 }, 551 | { "time": 1.0666, "angle": 16.02 }, 552 | { "time": 1.3666, "angle": 1.08 } 553 | ], 554 | "translate": [ 555 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 556 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 557 | { "time": 1.3666, "x": 0, "y": 0 } 558 | ], 559 | "scale": [ 560 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 561 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 562 | { "time": 1.3666, "x": 1, "y": 1 } 563 | ] 564 | }, 565 | "torso": { 566 | "rotate": [ 567 | { "time": 0, "angle": -13.35 }, 568 | { "time": 0.2333, "angle": -48.95 }, 569 | { "time": 0.4333, "angle": -35.77 }, 570 | { "time": 0.6, "angle": -4.59 }, 571 | { "time": 0.7666, "angle": 14.61 }, 572 | { "time": 0.9333, "angle": 15.74 }, 573 | { "time": 1.0666, "angle": -32.44 }, 574 | { "time": 1.3666, "angle": -13.35 } 575 | ], 576 | "translate": [ 577 | { "time": 0, "x": -3.67, "y": 1.68, "curve": "stepped" }, 578 | { "time": 0.9333, "x": -3.67, "y": 1.68, "curve": "stepped" }, 579 | { "time": 1.3666, "x": -3.67, "y": 1.68 } 580 | ], 581 | "scale": [ 582 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 583 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 584 | { "time": 1.3666, "x": 1, "y": 1 } 585 | ] 586 | }, 587 | "neck": { 588 | "rotate": [ 589 | { "time": 0, "angle": 12.78 }, 590 | { "time": 0.2333, "angle": 16.46 }, 591 | { "time": 0.4, "angle": 26.49 }, 592 | { "time": 0.6, "angle": 15.51 }, 593 | { "time": 0.7666, "angle": 1.34 }, 594 | { "time": 0.9333, "angle": 2.35 }, 595 | { "time": 1.0666, "angle": 6.08 }, 596 | { "time": 1.3, "angle": 21.23 }, 597 | { "time": 1.3666, "angle": 12.78 } 598 | ], 599 | "translate": [ 600 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 601 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 602 | { "time": 1.3666, "x": 0, "y": 0 } 603 | ], 604 | "scale": [ 605 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 606 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 607 | { "time": 1.3666, "x": 1, "y": 1 } 608 | ] 609 | }, 610 | "head": { 611 | "rotate": [ 612 | { "time": 0, "angle": 5.19 }, 613 | { "time": 0.2333, "angle": 20.27 }, 614 | { "time": 0.4, "angle": 15.27 }, 615 | { "time": 0.6, "angle": -24.69 }, 616 | { "time": 0.7666, "angle": -11.02 }, 617 | { "time": 0.9333, "angle": -24.38 }, 618 | { "time": 1.0666, "angle": 11.99 }, 619 | { "time": 1.3, "angle": 4.86 }, 620 | { "time": 1.3666, "angle": 5.19 } 621 | ], 622 | "translate": [ 623 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 624 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 625 | { "time": 1.3666, "x": 0, "y": 0 } 626 | ], 627 | "scale": [ 628 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 629 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 630 | { "time": 1.3666, "x": 1, "y": 1 } 631 | ] 632 | }, 633 | "left shoulder": { 634 | "rotate": [ 635 | { 636 | "time": 0, 637 | "angle": 0.05, 638 | "curve": [ 0, 0, 0.62, 1 ] 639 | }, 640 | { 641 | "time": 0.2333, 642 | "angle": 279.66, 643 | "curve": [ 0.218, 0.67, 0.66, 0.99 ] 644 | }, 645 | { 646 | "time": 0.5, 647 | "angle": 62.27, 648 | "curve": [ 0.462, 0, 0.764, 0.58 ] 649 | }, 650 | { "time": 0.9333, "angle": 28.91 }, 651 | { "time": 1.0666, "angle": -8.62 }, 652 | { "time": 1.1666, "angle": -18.43 }, 653 | { "time": 1.3666, "angle": 0.05 } 654 | ], 655 | "translate": [ 656 | { "time": 0, "x": -1.76, "y": 0.56, "curve": "stepped" }, 657 | { "time": 0.9333, "x": -1.76, "y": 0.56, "curve": "stepped" }, 658 | { "time": 1.3666, "x": -1.76, "y": 0.56 } 659 | ], 660 | "scale": [ 661 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 662 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 663 | { "time": 1.3666, "x": 1, "y": 1 } 664 | ] 665 | }, 666 | "left hand": { 667 | "rotate": [ 668 | { "time": 0, "angle": 11.58, "curve": "stepped" }, 669 | { "time": 0.9333, "angle": 11.58, "curve": "stepped" }, 670 | { "time": 1.3666, "angle": 11.58 } 671 | ], 672 | "translate": [ 673 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 674 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 675 | { "time": 1.3666, "x": 0, "y": 0 } 676 | ], 677 | "scale": [ 678 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 679 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 680 | { "time": 1.3666, "x": 1, "y": 1 } 681 | ] 682 | }, 683 | "left arm": { 684 | "rotate": [ 685 | { "time": 0, "angle": 0.51 }, 686 | { "time": 0.4333, "angle": 12.82 }, 687 | { "time": 0.6, "angle": 47.55 }, 688 | { "time": 0.9333, "angle": 12.82 }, 689 | { "time": 1.1666, "angle": -6.5 }, 690 | { "time": 1.3666, "angle": 0.51 } 691 | ], 692 | "translate": [ 693 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 694 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 695 | { "time": 1.3666, "x": 0, "y": 0 } 696 | ], 697 | "scale": [ 698 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 699 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 700 | { "time": 1.3666, "x": 1, "y": 1 } 701 | ] 702 | }, 703 | "right shoulder": { 704 | "rotate": [ 705 | { 706 | "time": 0, 707 | "angle": 43.82, 708 | "curve": [ 0, 0, 0.62, 1 ] 709 | }, 710 | { 711 | "time": 0.2333, 712 | "angle": -8.74, 713 | "curve": [ 0.304, 0.58, 0.709, 0.97 ] 714 | }, 715 | { 716 | "time": 0.5333, 717 | "angle": -208.02, 718 | "curve": [ 0.462, 0, 0.764, 0.58 ] 719 | }, 720 | { "time": 0.9333, "angle": -246.72 }, 721 | { "time": 1.0666, "angle": -307.13 }, 722 | { "time": 1.1666, "angle": 37.15 }, 723 | { "time": 1.3666, "angle": 43.82 } 724 | ], 725 | "translate": [ 726 | { "time": 0, "x": -7.84, "y": 7.19, "curve": "stepped" }, 727 | { "time": 0.9333, "x": -7.84, "y": 7.19, "curve": "stepped" }, 728 | { "time": 1.3666, "x": -7.84, "y": 7.19 } 729 | ], 730 | "scale": [ 731 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 732 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 733 | { "time": 1.3666, "x": 1, "y": 1 } 734 | ] 735 | }, 736 | "right arm": { 737 | "rotate": [ 738 | { "time": 0, "angle": -4.02 }, 739 | { "time": 0.6, "angle": 17.5 }, 740 | { "time": 0.9333, "angle": -4.02 }, 741 | { "time": 1.1666, "angle": -16.72 }, 742 | { "time": 1.3666, "angle": -4.02 } 743 | ], 744 | "translate": [ 745 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 746 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 747 | { "time": 1.3666, "x": 0, "y": 0 } 748 | ], 749 | "scale": [ 750 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 751 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 752 | { "time": 1.3666, "x": 1, "y": 1 } 753 | ] 754 | }, 755 | "right hand": { 756 | "rotate": [ 757 | { "time": 0, "angle": 22.92, "curve": "stepped" }, 758 | { "time": 0.9333, "angle": 22.92, "curve": "stepped" }, 759 | { "time": 1.3666, "angle": 22.92 } 760 | ], 761 | "translate": [ 762 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 763 | { "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" }, 764 | { "time": 1.3666, "x": 0, "y": 0 } 765 | ], 766 | "scale": [ 767 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 768 | { "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" }, 769 | { "time": 1.3666, "x": 1, "y": 1 } 770 | ] 771 | }, 772 | "root": { 773 | "rotate": [ 774 | { "time": 0, "angle": 0 }, 775 | { "time": 0.4333, "angle": -14.52 }, 776 | { "time": 0.8, "angle": 9.86 }, 777 | { "time": 1.3666, "angle": 0 } 778 | ], 779 | "scale": [ 780 | { "time": 0, "x": 1, "y": 1, "curve": "stepped" }, 781 | { "time": 1.3666, "x": 1, "y": 1 } 782 | ] 783 | } 784 | } 785 | } 786 | } 787 | } -------------------------------------------------------------------------------- /pyguts/examples/data/spineboy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/spineboy.png -------------------------------------------------------------------------------- /pyguts/examples/data/spineboy2.atlas: -------------------------------------------------------------------------------- 1 | 2 | data/spineboy2.png 3 | format: RGBA8888 4 | filter: Nearest,Nearest 5 | repeat: none 6 | spineboy 7 | rotate: false 8 | xy: 1, 169 9 | size: 145, 341 10 | orig: 145, 341 11 | offset: 0, 0 12 | index: -1 13 | head 14 | rotate: false 15 | xy: 1, 35 16 | size: 121, 132 17 | orig: 121, 132 18 | offset: 0, 0 19 | index: -1 20 | torso 21 | rotate: false 22 | xy: 148, 418 23 | size: 68, 92 24 | orig: 68, 92 25 | offset: 0, 0 26 | index: -1 27 | right-lower-leg 28 | rotate: false 29 | xy: 148, 352 30 | size: 51, 64 31 | orig: 51, 64 32 | offset: 0, 0 33 | index: -1 34 | right-upper-leg 35 | rotate: false 36 | xy: 148, 280 37 | size: 44, 70 38 | orig: 44, 70 39 | offset: 0, 0 40 | index: -1 41 | left-lower-leg 42 | rotate: false 43 | xy: 148, 214 44 | size: 49, 64 45 | orig: 49, 64 46 | offset: 0, 0 47 | index: -1 48 | left-upper-leg 49 | rotate: false 50 | xy: 218, 443 51 | size: 33, 67 52 | orig: 33, 67 53 | offset: 0, 0 54 | index: -1 55 | right-foot 56 | rotate: false 57 | xy: 1, 3 58 | size: 67, 30 59 | orig: 67, 30 60 | offset: 0, 0 61 | index: -1 62 | pelvis 63 | rotate: false 64 | xy: 148, 165 65 | size: 63, 47 66 | orig: 63, 47 67 | offset: 0, 0 68 | index: -1 69 | left-foot 70 | rotate: false 71 | xy: 70, 3 72 | size: 65, 30 73 | orig: 65, 30 74 | offset: 0, 0 75 | index: -1 76 | right-shoulder 77 | rotate: false 78 | xy: 124, 112 79 | size: 52, 51 80 | orig: 52, 51 81 | offset: 0, 0 82 | index: -1 83 | left-shoulder 84 | rotate: false 85 | xy: 124, 57 86 | size: 34, 53 87 | orig: 34, 53 88 | offset: 0, 0 89 | index: -1 90 | left-hand 91 | rotate: false 92 | xy: 178, 125 93 | size: 35, 38 94 | orig: 35, 38 95 | offset: 0, 0 96 | index: -1 97 | right-arm 98 | rotate: false 99 | xy: 160, 65 100 | size: 21, 45 101 | orig: 21, 45 102 | offset: 0, 0 103 | index: -1 104 | eyes-closed 105 | rotate: false 106 | xy: 218, 414 107 | size: 34, 27 108 | orig: 34, 27 109 | offset: 0, 0 110 | index: -1 111 | right-foot-idle 112 | rotate: false 113 | xy: 201, 384 114 | size: 53, 28 115 | orig: 53, 28 116 | offset: 0, 0 117 | index: -1 118 | left-pant-bottom 119 | rotate: false 120 | xy: 201, 360 121 | size: 44, 22 122 | orig: 44, 22 123 | offset: 0, 0 124 | index: -1 125 | right-pant-bottom 126 | rotate: false 127 | xy: 124, 37 128 | size: 46, 18 129 | orig: 46, 18 130 | offset: 0, 0 131 | index: -1 132 | right-hand 133 | rotate: false 134 | xy: 137, 3 135 | size: 32, 32 136 | orig: 32, 32 137 | offset: 0, 0 138 | index: -1 139 | left-arm 140 | rotate: false 141 | xy: 183, 94 142 | size: 35, 29 143 | orig: 35, 29 144 | offset: 0, 0 145 | index: -1 146 | eyes 147 | rotate: false 148 | xy: 183, 65 149 | size: 34, 27 150 | orig: 34, 27 151 | offset: 0, 0 152 | index: -1 153 | neck 154 | rotate: false 155 | xy: 172, 35 156 | size: 34, 28 157 | orig: 34, 28 158 | offset: 0, 0 159 | index: -1 160 | left-ankle 161 | rotate: false 162 | xy: 171, 1 163 | size: 25, 32 164 | orig: 25, 32 165 | offset: 0, 0 166 | index: -1 167 | right-ankle 168 | rotate: false 169 | xy: 198, 3 170 | size: 25, 30 171 | orig: 25, 30 172 | offset: 0, 0 173 | index: -1 174 | -------------------------------------------------------------------------------- /pyguts/examples/data/spineboy2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/spineboy2.png -------------------------------------------------------------------------------- /pyguts/examples/data/spinosaurus.atlas: -------------------------------------------------------------------------------- 1 | 2 | data/spinosaurus.png 3 | format: RGBA8888 4 | filter: Nearest,Nearest 5 | repeat: none 6 | background 7 | rotate: false 8 | xy: 1, 929 9 | size: 1680, 1050 10 | orig: 1680, 1050 11 | offset: 0, 0 12 | index: -1 13 | leaves 14 | rotate: false 15 | xy: 1, 405 16 | size: 1042, 522 17 | orig: 1042, 522 18 | offset: 0, 0 19 | index: -1 20 | logo 21 | rotate: false 22 | xy: 1, 80 23 | size: 917, 323 24 | orig: 917, 323 25 | offset: 0, 0 26 | index: -1 27 | settings 28 | rotate: false 29 | xy: 1045, 851 30 | size: 446, 76 31 | orig: 446, 76 32 | offset: 0, 0 33 | index: -1 34 | play 35 | rotate: false 36 | xy: 1683, 1902 37 | size: 218, 77 38 | orig: 218, 77 39 | offset: 0, 0 40 | index: -1 41 | quit 42 | rotate: false 43 | xy: 1, 1 44 | size: 216, 77 45 | orig: 216, 77 46 | offset: 0, 0 47 | index: -1 48 | -------------------------------------------------------------------------------- /pyguts/examples/data/spinosaurus.json: -------------------------------------------------------------------------------- 1 | { 2 | "bones": [ 3 | { "name": "root", "y": -526.31 }, 4 | { "name": "logo", "parent": "root", "y": 1332.02 }, 5 | { "name": "play", "parent": "root", "x": 3.02, "y": -83.61 }, 6 | { "name": "settings", "parent": "root", "x": 3.02, "y": -144.37 }, 7 | { "name": "quit", "parent": "root", "x": -2.85, "y": -201.21 }, 8 | { "name": "leaves", "parent": "root", "x": -0.16, "y": 1310.1 } 9 | ], 10 | "slots": [ 11 | { "name": "background", "bone": "root", "attachment": "background" }, 12 | { "name": "leaves", "bone": "leaves", "attachment": "leaves" }, 13 | { "name": "logo", "bone": "logo", "attachment": "logo" }, 14 | { "name": "play", "bone": "play", "color": "fff99dff", "attachment": "play" }, 15 | { "name": "quit", "bone": "quit", "color": "fff99dff", "attachment": "quit" }, 16 | { "name": "settings", "bone": "settings", "color": "fff99dff", "attachment": "settings" } 17 | ], 18 | "skins": { 19 | "default": { 20 | "background": { 21 | "background": { "y": 526.31, "width": 1680, "height": 1050 } 22 | }, 23 | "leaves": { 24 | "leaves": { "y": -28.54, "width": 1042, "height": 522 } 25 | }, 26 | "logo": { 27 | "logo": { "y": -20.39, "width": 917, "height": 323 } 28 | }, 29 | "play": { 30 | "play": { "width": 218, "height": 77 } 31 | }, 32 | "quit": { 33 | "quit": { "width": 216, "height": 77 } 34 | }, 35 | "settings": { 36 | "settings": { "width": 446, "height": 76 } 37 | } 38 | } 39 | }, 40 | "animations": { 41 | "animation": { 42 | "bones": { 43 | "logo": { 44 | "translate": [ 45 | { 46 | "time": 0, 47 | "x": 0, 48 | "y": 40.8, 49 | "curve": [ 0.043, 0.15, 0.344, 1.26 ] 50 | }, 51 | { 52 | "time": 0.3333, 53 | "x": 0, 54 | "y": -597.71, 55 | "curve": [ 0.425, 0.17, 0.591, 0.99 ] 56 | }, 57 | { 58 | "time": 1, 59 | "x": 0, 60 | "y": -583.71, 61 | "curve": [ 0.402, 0, 0.603, 1 ] 62 | }, 63 | { 64 | "time": 1.6666, 65 | "x": 0, 66 | "y": -592.11, 67 | "curve": [ 0.408, 0.01, 0.655, 0.98 ] 68 | }, 69 | { 70 | "time": 2.3333, 71 | "x": 0, 72 | "y": -583.71, 73 | "curve": [ 0.402, 0, 0.603, 0.99 ] 74 | }, 75 | { 76 | "time": 3, 77 | "x": 0, 78 | "y": -592.11, 79 | "curve": [ 0.408, 0.01, 0.655, 0.98 ] 80 | }, 81 | { "time": 3.6666, "x": 0, "y": -583.71 } 82 | ], 83 | "scale": [ 84 | { 85 | "time": 0, 86 | "x": 0.342, 87 | "y": 0.342, 88 | "curve": [ 0, 0, 0.744, 0.4 ] 89 | }, 90 | { 91 | "time": 0.3333, 92 | "x": 1, 93 | "y": 1, 94 | "curve": [ 0.189, 0.37, 0.658, 0.98 ] 95 | }, 96 | { 97 | "time": 1, 98 | "x": 1.02, 99 | "y": 1.03, 100 | "curve": [ 0.37, 0, 0.66, 0.99 ] 101 | }, 102 | { 103 | "time": 1.6666, 104 | "x": 1, 105 | "y": 1, 106 | "curve": [ 0.387, 0.01, 0.686, 1 ] 107 | }, 108 | { 109 | "time": 2.3333, 110 | "x": 1.02, 111 | "y": 1.03, 112 | "curve": [ 0.37, 0, 0.66, 0.99 ] 113 | }, 114 | { 115 | "time": 3, 116 | "x": 1, 117 | "y": 1, 118 | "curve": [ 0.387, 0.01, 0.686, 1 ] 119 | }, 120 | { "time": 3.6666, "x": 1.02, "y": 1.03 } 121 | ] 122 | }, 123 | "play": { 124 | "translate": [ 125 | { "time": 0, "x": 0, "y": 0, "curve": "stepped" }, 126 | { 127 | "time": 0.6666, 128 | "x": 0, 129 | "y": 0, 130 | "curve": [ 0, 0, 0.448, 1.62 ] 131 | }, 132 | { "time": 0.8666, "x": 0, "y": 480.2 } 133 | ], 134 | "scale": [ 135 | { 136 | "time": 1.3333, 137 | "x": 1, 138 | "y": 1, 139 | "curve": [ 0, 0, 0.525, 2.46 ] 140 | }, 141 | { "time": 1.5666, "x": 1.231, "y": 1.231, "curve": "stepped" }, 142 | { 143 | "time": 1.8333, 144 | "x": 1.231, 145 | "y": 1.231, 146 | "curve": [ 0, 0, 0.525, 2.46 ] 147 | }, 148 | { "time": 2.0666, "x": 1, "y": 1 } 149 | ] 150 | }, 151 | "settings": { 152 | "translate": [ 153 | { 154 | "time": 0.8, 155 | "x": 0, 156 | "y": 0, 157 | "curve": [ 0, 0, 0.448, 1.62 ] 158 | }, 159 | { "time": 1, "x": 0, "y": 431.2 } 160 | ], 161 | "scale": [ 162 | { 163 | "time": 1.8666, 164 | "x": 1, 165 | "y": 1, 166 | "curve": [ 0, 0, 0.525, 2.46 ] 167 | }, 168 | { "time": 2.1, "x": 1.23, "y": 1.23, "curve": "stepped" }, 169 | { 170 | "time": 2.3666, 171 | "x": 1.23, 172 | "y": 1.23, 173 | "curve": [ 0, 0, 0.525, 2.46 ] 174 | }, 175 | { "time": 2.6, "x": 1, "y": 1 } 176 | ] 177 | }, 178 | "quit": { 179 | "translate": [ 180 | { 181 | "time": 0.9333, 182 | "x": 0, 183 | "y": 0, 184 | "curve": [ 0, 0, 0.448, 1.62 ] 185 | }, 186 | { "time": 1.1333, "x": 0, "y": 376.32 } 187 | ], 188 | "scale": [ 189 | { 190 | "time": 2.4, 191 | "x": 1, 192 | "y": 1, 193 | "curve": [ 0, 0, 0.525, 2.46 ] 194 | }, 195 | { "time": 2.6333, "x": 1.23, "y": 1.23 } 196 | ] 197 | }, 198 | "leaves": { 199 | "translate": [ 200 | { 201 | "time": 0, 202 | "x": 0, 203 | "y": 0, 204 | "curve": [ 0.043, 0.15, 0.344, 1.26 ] 205 | }, 206 | { 207 | "time": 0.3333, 208 | "x": 0.16, 209 | "y": -601.23, 210 | "curve": [ 0.425, 0.17, 0.591, 0.99 ] 211 | }, 212 | { 213 | "time": 1.3333, 214 | "x": 0.16, 215 | "y": -580.83, 216 | "curve": [ 0.402, 0, 0.603, 1 ] 217 | }, 218 | { "time": 2, "x": 0.16, "y": -595.11 }, 219 | { 220 | "time": 2.6666, 221 | "x": 0.16, 222 | "y": -580.83, 223 | "curve": [ 0.402, 0, 0.603, 1 ] 224 | }, 225 | { "time": 3.3333, "x": 0.16, "y": -595.11 } 226 | ], 227 | "scale": [ 228 | { 229 | "time": 0, 230 | "x": 0.34, 231 | "y": 0.34, 232 | "curve": [ 0, 0, 0.744, 0.4 ] 233 | }, 234 | { "time": 0.3333, "x": 1, "y": 1 }, 235 | { "time": 1.3333, "x": 1.03, "y": 1.02 }, 236 | { "time": 2, "x": 1, "y": 1 }, 237 | { "time": 2.6666, "x": 1.03, "y": 1.02 }, 238 | { "time": 3.3333, "x": 1, "y": 1 } 239 | ] 240 | } 241 | }, 242 | "slots": { 243 | "logo": { 244 | "color": [ 245 | { "time": 0, "color": "ffffff00" }, 246 | { "time": 0.3333, "color": "ffffffff" } 247 | ] 248 | }, 249 | "play": { 250 | "color": [ 251 | { "time": 1.3333, "color": "fff99dff" }, 252 | { "time": 1.5666, "color": "ffffffff", "curve": "stepped" }, 253 | { "time": 1.8333, "color": "ffffffff" }, 254 | { "time": 2.0666, "color": "fff99dff" } 255 | ] 256 | }, 257 | "quit": { 258 | "color": [ 259 | { "time": 2.4, "color": "fff99dff" }, 260 | { "time": 2.6333, "color": "ffffffff" } 261 | ] 262 | }, 263 | "settings": { 264 | "color": [ 265 | { "time": 1.8666, "color": "fff99dff" }, 266 | { "time": 2.1, "color": "ffffffff", "curve": "stepped" }, 267 | { "time": 2.3666, "color": "ffffffff" }, 268 | { "time": 2.6, "color": "fff99dff" } 269 | ] 270 | }, 271 | "leaves": { 272 | "color": [ 273 | { "time": 0, "color": "ffffff00" }, 274 | { "time": 0.3333, "color": "ffffffff" } 275 | ] 276 | } 277 | } 278 | } 279 | } 280 | } -------------------------------------------------------------------------------- /pyguts/examples/data/spinosaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terrysimons/spine-python/179edf1f8f56ca2c487a1cdbfb623fe6a0d16060/pyguts/examples/data/spinosaurus.png -------------------------------------------------------------------------------- /pyguts/examples/dragon_pygame.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | import pygame 6 | 7 | import pyguts as spine 8 | 9 | if __name__ == '__main__': 10 | pygame.init() 11 | 12 | width, height = (1024, 768) 13 | 14 | screen = pygame.display.set_mode((width, height)) 15 | screen.fill((0,0,0)) 16 | caption = 'PyGuts - A Pygame front-end based on the python-spine Runtime' 17 | pygame.display.set_caption(caption, 'Spine Runtime') 18 | 19 | atlas = spine.Atlas(file='./data/dragon.atlas') 20 | skeletonJson = spine.SkeletonJson(spine.AtlasAttachmentLoader(atlas)) 21 | skeletonData = skeletonJson.readSkeletonDataFile('./data/dragon.json') 22 | flyingAnimation = skeletonData.findAnimation('flying') 23 | 24 | skeleton = spine.Skeleton(skeletonData=skeletonData) 25 | skeleton.debug = False 26 | 27 | skeleton.setToBindPose() 28 | skeleton.x = 480 29 | skeleton.y = 320 30 | skeleton.flipX = False 31 | skeleton.flipY = False 32 | skeleton.updateWorldTransform() 33 | 34 | clock = pygame.time.Clock() 35 | animationTime = 0.0 36 | 37 | done = False 38 | 39 | while not done: 40 | for event in pygame.event.get(): 41 | if event.type == pygame.QUIT: 42 | pygame.quit() 43 | done = True 44 | elif event.type == pygame.KEYDOWN: 45 | if pygame.key.get_pressed()[pygame.K_ESCAPE]: 46 | done = True 47 | clock.tick(0) 48 | animationTime += clock.get_time() / 1000.0 49 | flyingAnimation.apply(skeleton=skeleton, 50 | time=animationTime, 51 | loop=True) 52 | skeleton.updateWorldTransform() 53 | screen.fill((0, 0, 0)) 54 | skeleton.draw(screen, 0) 55 | pygame.display.set_caption('%s %.2f' % (caption, clock.get_fps()), 'Spine Runtime') 56 | pygame.display.flip() 57 | pygame.quit() 58 | -------------------------------------------------------------------------------- /pyguts/examples/goblins_pygame.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | import pygame 6 | 7 | import pyguts as spine 8 | 9 | if __name__ == '__main__': 10 | pygame.init() 11 | 12 | width, height = (640, 480) 13 | 14 | screen = pygame.display.set_mode((width, height)) 15 | screen.fill((0,0,0)) 16 | caption = 'PyGuts - A Pygame front-end based on the python-spine Runtime' 17 | pygame.display.set_caption(caption, 'Spine Runtime') 18 | 19 | atlas = spine.Atlas(file='./data/goblins.atlas') 20 | skeletonJson = spine.SkeletonJson(spine.AtlasAttachmentLoader(atlas)) 21 | skeletonData = skeletonJson.readSkeletonDataFile('./data/goblins.json') 22 | walkAnimation = skeletonData.findAnimation('walk') 23 | 24 | goblin = spine.Skeleton(skeletonData=skeletonData) 25 | goblin.debug = True 26 | 27 | goblin.setSkin('goblin') 28 | goblin.setToBindPose() 29 | goblin.x = 120 30 | goblin.y = 400 31 | goblin.flipX = False 32 | goblin.flipY = False 33 | goblin.updateWorldTransform() 34 | 35 | goblingirl = spine.Skeleton(skeletonData=skeletonData) 36 | goblingirl.debug = True 37 | 38 | goblingirl.setSkin('goblingirl') 39 | goblingirl.setToBindPose() 40 | goblingirl.x = 420 41 | goblingirl.y = 400 42 | goblingirl.flipX = False 43 | goblingirl.flipY = False 44 | goblingirl.updateWorldTransform() 45 | 46 | clock = pygame.time.Clock() 47 | animationTime = 0.0 48 | 49 | done = False 50 | 51 | while not done: 52 | for event in pygame.event.get(): 53 | if event.type == pygame.QUIT: 54 | pygame.quit() 55 | done = True 56 | elif event.type == pygame.KEYDOWN: 57 | if pygame.key.get_pressed()[pygame.K_ESCAPE]: 58 | done = True 59 | clock.tick(0) 60 | animationTime += clock.get_time() / 1000.0 61 | walkAnimation.apply(skeleton=goblin, 62 | time=animationTime, 63 | loop=True) 64 | walkAnimation.apply(skeleton=goblingirl, 65 | time=animationTime, 66 | loop=True) 67 | goblin.updateWorldTransform() 68 | goblingirl.updateWorldTransform() 69 | screen.fill((0, 0, 0)) 70 | goblin.draw(screen, 0) 71 | goblingirl.draw(screen, 0) 72 | pygame.display.set_caption('%s %.2f' % (caption, clock.get_fps()), 'Spine Runtime') 73 | pygame.display.flip() 74 | pygame.quit() 75 | -------------------------------------------------------------------------------- /pyguts/examples/mix_pygame.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | import pygame 6 | 7 | import pyguts as spine 8 | 9 | if __name__ == '__main__': 10 | pygame.init() 11 | 12 | width, height = (640, 480) 13 | 14 | screen = pygame.display.set_mode((width, height)) 15 | screen.fill((0,0,0)) 16 | caption = 'PyGuts - A Pygame front-end based on the python-spine Runtime' 17 | pygame.display.set_caption(caption, 'Spine Runtime') 18 | 19 | atlas = spine.Atlas(file='./data/spineboy.atlas') 20 | skeletonJson = spine.SkeletonJson(spine.AtlasAttachmentLoader(atlas)) 21 | skeletonData = skeletonJson.readSkeletonDataFile(file='./data/spineboy.json') 22 | walkAnimation = skeletonData.findAnimation('walk') 23 | jumpAnimation = skeletonData.findAnimation('jump') 24 | 25 | skeleton = spine.Skeleton(skeletonData=skeletonData) 26 | skeleton.debug = True 27 | 28 | skeleton.setToBindPose() 29 | skeleton.x = -50 30 | skeleton.y = 400 31 | skeleton.flipX = False 32 | skeleton.flipY = False 33 | skeleton.updateWorldTransform() 34 | 35 | clock = pygame.time.Clock() 36 | animationTime = 0.0 37 | 38 | done = False 39 | 40 | time = 0 41 | 42 | while not done: 43 | for event in pygame.event.get(): 44 | if event.type == pygame.QUIT: 45 | pygame.quit() 46 | done = True 47 | elif event.type == pygame.KEYDOWN: 48 | if pygame.key.get_pressed()[pygame.K_ESCAPE]: 49 | done = True 50 | clock.tick(60.0) 51 | 52 | delta = clock.get_time() * 1.0 53 | 54 | time += delta / 1000.00 55 | 56 | jump = jumpAnimation.duration 57 | beforeJump = 1.0 58 | blendIn = 0.4 59 | blendOut = 0.4 60 | blendOutStart = beforeJump + jump - blendOut 61 | total = 3.75 62 | 63 | root = skeleton.bones[0] 64 | speed = 180.0 65 | 66 | if time > beforeJump + blendIn and time < blendOutStart: 67 | speed = 360.0 68 | 69 | root.x = root.x + speed * delta / 1000.00 70 | 71 | screen.fill((0, 0, 0)) 72 | 73 | if time > total: 74 | # restart 75 | time = 0.0 76 | root.x = -50.0 77 | elif time > beforeJump + jump: 78 | # just walk after jump 79 | walkAnimation.apply(skeleton, time, True) 80 | elif time > blendOutStart: 81 | # blend out jump 82 | walkAnimation.apply(skeleton, time, True) 83 | jumpAnimation.mix(skeleton, time - beforeJump, False, 1.0 - (time - blendOutStart) / blendOut) 84 | elif time > beforeJump + blendIn: 85 | # just jump 86 | jumpAnimation.apply(skeleton, time - beforeJump, False) 87 | elif time > beforeJump: 88 | # blend in jump 89 | walkAnimation.apply(skeleton, time, True) 90 | jumpAnimation.mix(skeleton, time - beforeJump, False, (time - beforeJump) / blendIn) 91 | else: 92 | # just walk before jump 93 | walkAnimation.apply(skeleton, time, True) 94 | 95 | skeleton.updateWorldTransform() 96 | skeleton.update(clock.get_time()) 97 | skeleton.draw(screen, 0) 98 | pygame.display.set_caption('%s %.2f' % (caption, clock.get_fps()), 'Spine Runtime') 99 | pygame.display.flip() 100 | pygame.quit() 101 | -------------------------------------------------------------------------------- /pyguts/examples/powerup_pygame.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | import pygame 6 | 7 | import pyguts as spine 8 | 9 | if __name__ == '__main__': 10 | pygame.init() 11 | 12 | width, height = (640, 480) 13 | 14 | screen = pygame.display.set_mode((width, height)) 15 | screen.fill((0,0,0)) 16 | caption = 'PyGuts - A Pygame front-end based on the python-spine Runtime' 17 | pygame.display.set_caption(caption, 'Spine Runtime') 18 | 19 | atlas = spine.Atlas(file='./data/powerup.atlas') 20 | skeletonJson = spine.SkeletonJson(spine.AtlasAttachmentLoader(atlas)) 21 | skeletonData = skeletonJson.readSkeletonDataFile('./data/powerup.json') 22 | animation = skeletonData.findAnimation('animation') 23 | 24 | skeleton = spine.Skeleton(skeletonData=skeletonData) 25 | skeleton.debug = False 26 | 27 | skeleton.setToBindPose() 28 | skeleton.x = 320 29 | skeleton.y = 400 30 | skeleton.flipX = False 31 | skeleton.flipY = False 32 | skeleton.updateWorldTransform() 33 | 34 | clock = pygame.time.Clock() 35 | animationTime = 0.0 36 | 37 | done = False 38 | 39 | while not done: 40 | for event in pygame.event.get(): 41 | if event.type == pygame.QUIT: 42 | pygame.quit() 43 | done = True 44 | elif event.type == pygame.KEYDOWN: 45 | if pygame.key.get_pressed()[pygame.K_ESCAPE]: 46 | done = True 47 | clock.tick(0) 48 | animationTime += clock.get_time() / 1000.0 49 | animation.apply(skeleton=skeleton, 50 | time=animationTime, 51 | loop=True) 52 | skeleton.updateWorldTransform() 53 | screen.fill((0, 0, 0)) 54 | skeleton.draw(screen, 0) 55 | pygame.display.set_caption('%s %.2f' % (caption, clock.get_fps()), 'Spine Runtime') 56 | pygame.display.flip() 57 | pygame.quit() 58 | -------------------------------------------------------------------------------- /pyguts/examples/spine_pygame.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | import pygame 6 | 7 | import pyguts as spine 8 | 9 | if __name__ == '__main__': 10 | pygame.init() 11 | 12 | width, height = (640, 480) 13 | 14 | screen = pygame.display.set_mode((width, height)) 15 | screen.fill((0,0,0)) 16 | caption = 'PyGuts - A Pygame front-end based on the python-spine Runtime' 17 | pygame.display.set_caption(caption, 'Spine Runtime') 18 | 19 | atlas = spine.Atlas(file='./data/spineboy.atlas') 20 | skeletonJson = spine.SkeletonJson(spine.AtlasAttachmentLoader(atlas)) 21 | skeletonData = skeletonJson.readSkeletonDataFile('./data/spineboy.json') 22 | walkAnimation = skeletonData.findAnimation('walk') 23 | 24 | skeleton = spine.Skeleton(skeletonData=skeletonData) 25 | skeleton.debug = True 26 | 27 | skeleton.setToBindPose() 28 | skeleton.x = 320 29 | skeleton.y = 400 30 | skeleton.flipX = False 31 | skeleton.flipY = False 32 | skeleton.updateWorldTransform() 33 | 34 | clock = pygame.time.Clock() 35 | animationTime = 0.0 36 | 37 | done = False 38 | 39 | while not done: 40 | for event in pygame.event.get(): 41 | if event.type == pygame.QUIT: 42 | pygame.quit() 43 | done = True 44 | elif event.type == pygame.KEYDOWN: 45 | if pygame.key.get_pressed()[pygame.K_ESCAPE]: 46 | done = True 47 | clock.tick(0) 48 | animationTime += clock.get_time() / 1000.0 49 | walkAnimation.apply(skeleton=skeleton, 50 | time=animationTime, 51 | loop=True) 52 | skeleton.updateWorldTransform() 53 | screen.fill((0, 0, 0)) 54 | skeleton.draw(screen, 0) 55 | pygame.display.set_caption('%s %.2f' % (caption, clock.get_fps()), 'Spine Runtime') 56 | pygame.display.flip() 57 | pygame.quit() 58 | -------------------------------------------------------------------------------- /pyguts/examples/spinosaurus_pygame.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | import pygame 6 | 7 | import pyguts as spine 8 | 9 | if __name__ == '__main__': 10 | pygame.init() 11 | 12 | width, height = (1024, 768) 13 | 14 | screen = pygame.display.set_mode((width, height)) 15 | screen.fill((0,0,0)) 16 | caption = 'PyGuts - A Pygame front-end based on the python-spine Runtime' 17 | pygame.display.set_caption(caption, 'Spine Runtime') 18 | 19 | atlas = spine.Atlas(file='./data/spinosaurus.atlas') 20 | skeletonJson = spine.SkeletonJson(spine.AtlasAttachmentLoader(atlas)) 21 | skeletonData = skeletonJson.readSkeletonDataFile('./data/spinosaurus.json') 22 | animation = skeletonData.findAnimation('animation') 23 | 24 | skeleton = spine.Skeleton(skeletonData=skeletonData) 25 | skeleton.debug = False 26 | 27 | skeleton.setToBindPose() 28 | skeleton.x = 512 29 | skeleton.y = 360 30 | skeleton.flipX = False 31 | skeleton.flipY = False 32 | skeleton.updateWorldTransform() 33 | 34 | clock = pygame.time.Clock() 35 | animationTime = 0.0 36 | 37 | done = False 38 | 39 | while not done: 40 | for event in pygame.event.get(): 41 | if event.type == pygame.QUIT: 42 | pygame.quit() 43 | done = True 44 | elif event.type == pygame.KEYDOWN: 45 | if pygame.key.get_pressed()[pygame.K_ESCAPE]: 46 | done = True 47 | clock.tick(0) 48 | animationTime += clock.get_time() / 1000.0 49 | animation.apply(skeleton=skeleton, 50 | time=animationTime, 51 | loop=True) 52 | skeleton.updateWorldTransform() 53 | screen.fill((0, 0, 0)) 54 | skeleton.draw(screen, 0) 55 | pygame.display.set_caption('%s %.2f' % (caption, clock.get_fps()), 'Spine Runtime') 56 | pygame.display.flip() 57 | pygame.quit() 58 | -------------------------------------------------------------------------------- /pyguts/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup 4 | 5 | setup(name='pyguts', 6 | version='1.0b14', 7 | description='A pygame front-end for spine-python.', 8 | author='Terry Simons', 9 | author_email='terry.simons@gmail.com', 10 | url='https://github.com/terrysimons/spine-python/pyguts', 11 | package_dir={'pyguts': 'src'}, 12 | packages=['pyguts'], 13 | classifiers=['License :: OSI Approved :: BSD License'], 14 | install_requires=['spine_python'] 15 | ) 16 | -------------------------------------------------------------------------------- /pyguts/src/Atlas.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | import pygame 5 | 6 | 7 | import spine 8 | 9 | class AtlasPage(spine.AtlasPage): 10 | def __init__(self): 11 | super(AtlasPage, self).__init__() 12 | self.texture = None 13 | 14 | 15 | class AtlasRegion(spine.AtlasRegion): 16 | def __init__(self): 17 | super(AtlasRegion, self).__init__() 18 | self.page = None 19 | 20 | 21 | class Atlas(spine.Atlas): 22 | def __init__(self, file): 23 | super(Atlas, self).__init__() 24 | super(Atlas, self).loadWithFile(file) 25 | 26 | 27 | def newAtlasPage(self, name): 28 | page = AtlasPage() 29 | page.texture = pygame.image.load(os.path.realpath(name)).convert_alpha() 30 | return page 31 | 32 | 33 | def newAtlasRegion(self, page): 34 | region = AtlasRegion() 35 | region.page = page 36 | return region 37 | 38 | 39 | def findRegion(self, name): 40 | return super(Atlas, self).findRegion(name) 41 | -------------------------------------------------------------------------------- /pyguts/src/AtlasAttachmentLoader.py: -------------------------------------------------------------------------------- 1 | import spine 2 | 3 | import RegionAttachment 4 | 5 | class AtlasAttachmentLoader(spine.AttachmentLoader.AttachmentLoader): 6 | def __init__(self, atlas): 7 | self.atlas = atlas 8 | 9 | def newAttachment(self, type, name): 10 | if type == spine.AttachmentLoader.AttachmentType.region: 11 | region = self.atlas.findRegion(name) 12 | if not region: 13 | raise Exception("Atlas region not found: %s" % name) 14 | return RegionAttachment.RegionAttachment(region) 15 | else: 16 | raise Exception('Unknown attachment type: %s' % type) 17 | 18 | 19 | -------------------------------------------------------------------------------- /pyguts/src/RegionAttachment.py: -------------------------------------------------------------------------------- 1 | import spine 2 | 3 | import pygame 4 | 5 | class Color(object): 6 | def __init__(self): 7 | super(Color, self).__init__() 8 | self.r = 0.0 9 | self.g = 0.0 10 | self.b = 0.0 11 | self.a = 0.0 12 | 13 | class TextureCoordinates(object): 14 | def __init__(self): 15 | super(TextureCoordinates, self).__init__() 16 | self.x = 0.0 17 | self.y = 0.0 18 | 19 | class Vertex(object): 20 | def __init__(self): 21 | super(Vertex, self).__init__() 22 | self.color = Color() 23 | self.texCoords = TextureCoordinates() 24 | 25 | class RegionAttachment(spine.RegionAttachment): 26 | def __init__(self, region): 27 | super(RegionAttachment, self).__init__() 28 | self.verticies = [Vertex(), Vertex(), Vertex(), Vertex()] 29 | self.u = region.x 30 | self.u2 = self.u + region.width 31 | self.v = region.y 32 | self.v2 = self.v + region.height 33 | self.rect = pygame.Rect((self.u, self.v, region.width, region.height)) 34 | self.texture = region.page.texture.subsurface(self.rect) 35 | self.offset = pygame.Rect(0, 0, region.width, region.height) 36 | self.offset.center = (region.width / 2, region.height / 2) 37 | if region.rotate: 38 | self.verticies[1].texCoords.x = self.u 39 | self.verticies[1].texCoords.y = self.v2 40 | self.verticies[2].texCoords.x = self.u 41 | self.verticies[2].texCoords.y = self.v 42 | self.verticies[3].texCoords.x = self.u2 43 | self.verticies[3].texCoords.y = self.v 44 | self.verticies[0].texCoords.x = self.u2 45 | self.verticies[0].texCoords.y = self.v2 46 | else: 47 | self.verticies[0].texCoords.x = self.u 48 | self.verticies[0].texCoords.y = self.v2 49 | self.verticies[1].texCoords.x = self.u 50 | self.verticies[1].texCoords.y = self.v 51 | self.verticies[2].texCoords.x = self.u2 52 | self.verticies[2].texCoords.y = self.v 53 | self.verticies[3].texCoords.x = self.u2 54 | self.verticies[3].texCoords.y = self.v2 55 | 56 | 57 | def draw(self, slot): 58 | skeleton = slot.skeleton 59 | 60 | r = skeleton.r * slot.r * 255.0 61 | g = skeleton.g * slot.g * 255.0 62 | b = skeleton.b * slot.b * 255.0 63 | a = skeleton.a * slot.a * 255.0 64 | 65 | self.verticies[0].color.r = r 66 | self.verticies[0].color.g = g 67 | self.verticies[0].color.b = b 68 | self.verticies[0].color.a = a 69 | self.verticies[1].color.r = r 70 | self.verticies[1].color.g = g 71 | self.verticies[1].color.b = b 72 | self.verticies[1].color.a = a 73 | self.verticies[2].color.r = r 74 | self.verticies[2].color.g = g 75 | self.verticies[2].color.b = b 76 | self.verticies[2].color.a = a 77 | self.verticies[3].color.r = r 78 | self.verticies[3].color.g = g 79 | self.verticies[3].color.b = b 80 | self.verticies[3].color.a = a 81 | 82 | self.updateOffset() 83 | self.updateWorldVerticies(slot.bone) 84 | 85 | skeleton.texture = self.texture 86 | skeleton.vertexArray.append(self.verticies[0]) 87 | skeleton.vertexArray.append(self.verticies[1]) 88 | skeleton.vertexArray.append(self.verticies[2]) 89 | skeleton.vertexArray.append(self.verticies[3]) 90 | 91 | 92 | def updateWorldVertices(self, bone): 93 | x = bone.worldX 94 | y = bone.worldY 95 | m00 = bone.m00 96 | m01 = bone.m01 97 | m10 = bone.m10 98 | m11 = bone.m11 99 | self.verticies[0].position.x = self.offset[0] * m00 + offset[1] * m01 + x 100 | self.verticies[0].position.y = self.offset[0] * m10 + offset[1] * m11 + y 101 | self.verticies[1].position.x = self.offset[2] * m00 + offset[3] * m01 + x 102 | self.verticies[1].position.y = self.offset[2] * m10 + offset[3] * m11 + y 103 | self.verticies[2].position.x = self.offset[4] * m00 + offset[5] * m01 + x 104 | self.verticies[2].position.y = self.offset[4] * m10 + offset[5] * m11 + y 105 | self.verticies[3].position.x = self.offset[6] * m00 + offset[7] * m01 + x 106 | self.verticies[3].position.y = self.offset[6] * m10 + offset[7] * m11 + y 107 | 108 | -------------------------------------------------------------------------------- /pyguts/src/Skeleton.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import spine 4 | 5 | import pygame 6 | 7 | class Circle(object): 8 | def __init__(self, x, y, r): 9 | super(Circle, self).__init__() 10 | self.x = x 11 | self.y = y 12 | self.r = r 13 | self.color = (0, 255, 0, 255) 14 | 15 | 16 | class Line(object): 17 | def __init__(self, length): 18 | super(Line, self).__init__() 19 | self.x = 0.0 20 | self.y = 0.0 21 | self.x1 = 0.0 22 | self.x2 = 0.0 23 | self.length = length 24 | self.rotation = 0.0 25 | self.color = (255, 0, 0, 255) 26 | self.texture = pygame.Surface((640, 480), pygame.SRCALPHA, 32) 27 | pygame.draw.rect(self.texture, (255, 255, 0, 64), (0, 0, self.texture.get_width(), self.texture.get_height()), 1) 28 | 29 | 30 | def rotate(self): 31 | return pygame.transform.rotozoom(self.texture, self.rotation, self.xScale) 32 | 33 | 34 | class Skeleton(spine.Skeleton): 35 | def __init__(self, skeletonData): 36 | super(Skeleton, self).__init__(skeletonData=skeletonData) 37 | self.x = 0 38 | self.y = 0 39 | self.texture = None 40 | self.debug = True 41 | self.images = [] 42 | self.clock = None 43 | 44 | def draw(self, screen, states): 45 | x = 0 46 | y = 0 47 | 48 | for slot in self.drawOrder: 49 | if slot.attachment: 50 | texture = slot.attachment.texture.copy() 51 | if texture: 52 | x = slot.bone.worldX + slot.attachment.x * slot.bone.m00 + slot.attachment.y * slot.bone.m01 53 | y = -(slot.bone.worldY + slot.attachment.x * slot.bone.m10 + slot.attachment.y * slot.bone.m11) 54 | rotation = -(slot.bone.worldRotation + slot.attachment.rotation) 55 | xScale = slot.bone.worldScaleX + slot.attachment.scaleX - 1 56 | yScale = slot.bone.worldScaleY + slot.attachment.scaleY - 1 57 | 58 | x += self.x 59 | y += self.y 60 | 61 | if self.flipX: 62 | xScale = -xScale 63 | rotation = -rotation 64 | if self.flipY: 65 | yScale = -yScale 66 | rotation = -rotation 67 | 68 | flipX = False 69 | flipY = False 70 | 71 | if xScale < 0: 72 | flipX = True 73 | xScale = math.fabs(xScale) 74 | if yScale < 0: 75 | flipY = True 76 | yScale = math.fabs(yScale) 77 | 78 | 79 | texture.fill((slot.r, slot.g, slot.b, slot.a), None, pygame.BLEND_RGBA_MULT) 80 | 81 | center = texture.get_rect().center 82 | texture = pygame.transform.flip(texture, flipX, flipY) 83 | texture = pygame.transform.smoothscale(texture, (int(texture.get_width() * xScale), int(texture.get_height() * yScale))) 84 | texture = pygame.transform.rotozoom(texture, -rotation, 1) 85 | 86 | # Center image 87 | x = x - texture.get_width() / 2 88 | y = y - texture.get_height() / 2 89 | screen.blit(texture, (x, y)) 90 | 91 | if self.debug: 92 | if not self.clock: 93 | self.clock = pygame.time.Clock() 94 | self.clock.tick() 95 | # Draw the FPS in the bottom right corner. 96 | pygame.font.init() 97 | myfont = pygame.font.SysFont(None, 24, bold=True) 98 | mytext = myfont.render('FPS: %.2f' % self.clock.get_fps(), True, (255, 255, 255)) 99 | 100 | screen.blit(mytext, (screen.get_width() - mytext.get_width(), screen.get_height() - mytext.get_height())) 101 | 102 | for bone in self.bones: 103 | 104 | if not bone.line: 105 | bone.line = Line(bone.data.length) 106 | bone.line.x = bone.worldX + self.x 107 | bone.line.y = -bone.worldY + self.y 108 | bone.line.rotation = -bone.worldRotation 109 | bone.line.color = (255, 0, 0) 110 | 111 | if self.flipX: 112 | bone.line.xScale = -1 113 | bone.line.rotation = -bone.line.rotation 114 | else: 115 | bone.line.xScale = 1 116 | if self.flipY: 117 | bone.line.yScale = -1 118 | bone.line.rotation = -bone.line.rotation 119 | else: 120 | bone.line.yScale = 1 121 | 122 | bone.line.x1 = bone.line.x + math.cos(math.radians(bone.line.rotation)) * bone.line.length 123 | bone.line.y1 = bone.line.y + math.sin(math.radians(bone.line.rotation)) * bone.line.length 124 | 125 | pygame.draw.line(screen, bone.line.color, (bone.line.x, bone.line.y), (bone.line.x1, bone.line.y1)) 126 | 127 | if not bone.circle: 128 | bone.circle = Circle(0, 0, 3) 129 | bone.circle.x = int(bone.worldX) + self.x 130 | bone.circle.y = -int(bone.worldY) + self.y 131 | bone.circle.color = (0, 255, 0) 132 | 133 | if 'top left' in bone.data.name: 134 | bone.circle.color = (255, 0, 0) 135 | if 'top right' in bone.data.name: 136 | bone.circle.color = (255, 140, 0) 137 | if 'bottom right' in bone.data.name: 138 | bone.circle.color = (255, 255, 0) 139 | if 'bottom left' in bone.data.name: 140 | bone.circle.color = (199, 21, 133) 141 | 142 | pygame.draw.circle(screen, 143 | bone.circle.color, 144 | (bone.circle.x, bone.circle.y), 145 | bone.circle.r, 146 | 0) 147 | -------------------------------------------------------------------------------- /pyguts/src/__init__.py: -------------------------------------------------------------------------------- 1 | from Atlas import * 2 | from AtlasAttachmentLoader import * 3 | from Skeleton import * 4 | 5 | from spine.SkeletonJson import * 6 | 7 | -------------------------------------------------------------------------------- /spine-python/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup 4 | 5 | setup(name='spine-python', 6 | version='1.0b9', 7 | description='A Pure Python Spine runtime.', 8 | author='Terry Simons', 9 | author_email='terry.simons@gmail.com', 10 | url='https://github.com/terrysimons/spine-python/spine-python', 11 | package_dir={'spine': 'src'}, 12 | packages=['spine', 'spine.Atlas', 'spine.Animation'], 13 | classifiers=['License :: OSI Approved :: BSD License'] 14 | ) 15 | -------------------------------------------------------------------------------- /spine-python/src/Animation/Timeline.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Timeline(object): 4 | def __init__(self, keyframeCount): 5 | super(Timeline, self).__init__() 6 | 7 | def getKeyframeCount(self): 8 | pass 9 | 10 | def apply(skeleton, time, alpha): 11 | pass 12 | 13 | 14 | class CurveTimeline(Timeline): 15 | def __init__(self, keyframeCount): 16 | super(CurveTimeline, self).__init__(keyframeCount) 17 | self.FRAME_SPACING = 6 18 | self.LINEAR = 0 19 | self.STEPPED = -1 20 | self.BEZIER_SEGMENTS = 10.0 21 | self.curves = [0] * ((keyframeCount - 1) * 6) 22 | 23 | 24 | def setLinear(self, keyframeIndex): 25 | self.curves[keyframeIndex * self.FRAME_SPACING] = self.LINEAR 26 | self.curves[keyframeIndex * 6] = self.LINEAR 27 | 28 | 29 | def setStepped(self, keyframeIndex): 30 | self.curves[keyframeIndex * self.FRAME_SPACING] = self.STEPPED 31 | self.curves[keyframeIndex * 6] = self.STEPPED 32 | 33 | 34 | def setCurve(self, keyframeIndex, cx1, cy1, cx2, cy2): 35 | subdiv_step = 1.0 / self.BEZIER_SEGMENTS 36 | subdiv_step2 = subdiv_step * subdiv_step 37 | subdiv_step3 = subdiv_step2 * subdiv_step 38 | pre1 = 3 * subdiv_step 39 | pre2 = 3 * subdiv_step2 40 | pre4 = 6 * subdiv_step2 41 | pre5 = 6 * subdiv_step3 42 | tmp1x = -cx1 * 2 + cx2 43 | tmp1y = -cy1 * 2 + cy2 44 | tmp2x = (cx1 - cx2) * 3 + 1 45 | tmp2y = (cy1 - cy2) * 3 + 1 46 | i = keyframeIndex * 6 47 | self.curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3 48 | self.curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3 49 | self.curves[i + 2] = tmp1x * pre4 + tmp2x * pre5 50 | self.curves[i + 3] = tmp1y * pre4 + tmp2y * pre5 51 | self.curves[i + 4] = tmp2x * pre5 52 | self.curves[i + 5] = tmp2y * pre5 53 | 54 | 55 | def getCurvePercent(self, keyframeIndex, percent): 56 | curveIndex = keyframeIndex * self.FRAME_SPACING 57 | curveIndex = keyframeIndex * 6 58 | dfx = self.curves[curveIndex] 59 | if dfx == self.LINEAR: 60 | return percent 61 | if dfx == self.STEPPED: 62 | return 0.0 63 | dfy = self.curves[curveIndex + 1] 64 | ddfx = self.curves[curveIndex + 2] 65 | ddfy = self.curves[curveIndex + 3] 66 | dddfx = self.curves[curveIndex + 4] 67 | dddfy = self.curves[curveIndex + 5] 68 | x = dfx 69 | y = dfy 70 | i = self.BEZIER_SEGMENTS - 2 71 | while True: 72 | if x >= percent: 73 | lastX = x - dfx 74 | lastY = y - dfy 75 | return lastY + (y - lastY) * (percent - lastX) / (x - lastX) 76 | if i == 0: 77 | break 78 | i -= 1 79 | dfx += ddfx 80 | dfy += ddfy 81 | ddfx += dddfx 82 | ddfy += dddfy 83 | x += dfx 84 | y += dfy 85 | return y + (1 - y) * (percent - x) / (1 - x) # Last point is 1,1 86 | 87 | 88 | def binarySearch(values, target, step): 89 | low = 0 90 | high = int(math.floor(len(values) / step - 2)) 91 | if high == 0: 92 | return step 93 | current = int(math.floor(high >> 1)) 94 | while True: 95 | if values[(current + 1) * step] <= target: 96 | low = current + 1 97 | else: 98 | high = current 99 | if low == high: 100 | return (low + 1) * step 101 | current = int(math.floor((low + high) >> 1)) 102 | return 0 103 | 104 | 105 | class RotateTimeline(CurveTimeline): 106 | def __init__(self, keyframeCount): 107 | super(RotateTimeline, self).__init__(keyframeCount) 108 | self.LAST_FRAME_TIME = -2 109 | self.FRAME_SPACING = -self.LAST_FRAME_TIME 110 | self.FRAME_VALUE = 1 111 | self.frames = [0.0] * (keyframeCount * self.FRAME_SPACING) 112 | self.boneIndex = 0 113 | 114 | 115 | def getDuration(self): 116 | return self.frames[self.LAST_FRAME_TIME] 117 | 118 | 119 | def getKeyframeCount(self): 120 | return len(self.frames) / self.FRAME_SPACING 121 | 122 | 123 | def setKeyframe(self, keyframeIndex, time, value): 124 | keyframeIndex *= self.FRAME_SPACING 125 | self.frames[keyframeIndex] = time 126 | self.frames[keyframeIndex + 1] = value 127 | 128 | 129 | def apply(self, skeleton, time, alpha): 130 | if time < self.frames[0]: 131 | return 132 | 133 | bone = skeleton.bones[self.boneIndex] 134 | 135 | if time >= self.frames[self.LAST_FRAME_TIME]: # Time is after last frame 136 | amount = bone.data.rotation + self.frames[-1] - bone.rotation 137 | while amount > 180: 138 | amount = amount - 360 139 | while amount < -180: 140 | amount = amount + 360 141 | bone.rotation = bone.rotation + amount * alpha 142 | return 143 | 144 | # Interpolate between the last frame and the current frame 145 | frameIndex = binarySearch(self.frames, time, self.FRAME_SPACING) 146 | lastFrameValue = self.frames[frameIndex - 1] 147 | frameTime = self.frames[frameIndex] 148 | percent = 1.0 - (time - frameTime) / (self.frames[frameIndex + self.LAST_FRAME_TIME] - frameTime) 149 | if percent < 0.0: 150 | percent = 0.0 151 | elif percent > 1.0: 152 | percent = 1.0 153 | percent = self.getCurvePercent(frameIndex / self.FRAME_SPACING - 1, percent) 154 | 155 | amount = self.frames[frameIndex + self.FRAME_VALUE] - lastFrameValue 156 | while amount > 180: 157 | amount = amount - 360 158 | while amount < -180: 159 | amount = amount + 360 160 | amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation 161 | while amount > 180: 162 | amount = amount - 360 163 | while amount < -180: 164 | amount = amount + 360 165 | bone.rotation = bone.rotation + amount * alpha 166 | return 167 | 168 | 169 | class TranslateTimeline(CurveTimeline): 170 | def __init__(self, keyframeCount): 171 | super(TranslateTimeline, self).__init__(keyframeCount) 172 | self.LAST_FRAME_TIME = -3 173 | self.FRAME_SPACING = -self.LAST_FRAME_TIME 174 | self.FRAME_X = 1 175 | self.FRAME_Y = 2 176 | self.frames = [0.0] * (keyframeCount * self.FRAME_SPACING) 177 | self.boneIndex = 0 178 | 179 | 180 | def getDuration(self): 181 | return self.frames[self.LAST_FRAME_TIME] 182 | 183 | 184 | def getKeyframeCount(self): 185 | return len(frames) / self.FRAME_SPACING 186 | 187 | 188 | def setKeyframe(self, keyframeIndex, time, x, y): 189 | keyframeIndex = keyframeIndex * self.FRAME_SPACING 190 | self.frames[keyframeIndex] = time 191 | self.frames[keyframeIndex + 1] = x 192 | self.frames[keyframeIndex + 2] = y 193 | 194 | 195 | def apply(self, skeleton, time, alpha): 196 | if time < self.frames[0]: # Time is before the first frame 197 | return 198 | 199 | bone = skeleton.bones[self.boneIndex] 200 | 201 | if time >= self.frames[self.LAST_FRAME_TIME]: # Time is after the last frame. 202 | bone.x = bone.x + (bone.data.x + self.frames[self.LAST_FRAME_TIME + 1] - bone.x) * alpha 203 | bone.y = bone.y + (bone.data.y + self.frames[self.LAST_FRAME_TIME + 2] - bone.y) * alpha 204 | return 205 | 206 | # Interpolate between the last frame and the current frame 207 | frameIndex = binarySearch(self.frames, time, self.FRAME_SPACING) 208 | lastFrameX = self.frames[frameIndex - 2] 209 | lastFrameY = self.frames[frameIndex - 1] 210 | frameTime = self.frames[frameIndex] 211 | percent = 1.0 - (time - frameTime) / (self.frames[frameIndex + self.LAST_FRAME_TIME] - frameTime) 212 | if percent < 0.0: 213 | percent = 0.0 214 | if percent > 1.0: 215 | percent = 1.0 216 | percent = self.getCurvePercent(frameIndex / self.FRAME_SPACING - 1, percent) 217 | 218 | bone.x = bone.x + (bone.data.x + lastFrameX + (self.frames[frameIndex + self.FRAME_X] - lastFrameX) * percent - bone.x) * alpha 219 | bone.y = bone.y + (bone.data.y + lastFrameY + (self.frames[frameIndex + self.FRAME_Y] - lastFrameY) * percent - bone.y) * alpha 220 | return 221 | 222 | 223 | class ScaleTimeline(TranslateTimeline): 224 | def __init__(self, keyframeCount): 225 | super(ScaleTimeline, self).__init__(keyframeCount) 226 | self.LAST_FRAME_TIME = -3 227 | self.FRAME_SPACING = -self.LAST_FRAME_TIME 228 | self.FRAME_X = 1 229 | self.FRAME_Y = 2 230 | 231 | 232 | def apply(self, skeleton, time, alpha): 233 | if time < self.frames[0]: 234 | return 235 | 236 | bone = skeleton.bones[self.boneIndex] 237 | if time >= self.frames[self.LAST_FRAME_TIME]: # Time is after last frame 238 | bone.scaleX += (bone.data.scaleX - 1 + self.frames[len(self.frames) - 2] - bone.scaleX) * alpha 239 | bone.scaleY += (bone.data.scaleY - 1 + self.frames[len(self.frames) - 1] - bone.scaleY) * alpha 240 | return 241 | 242 | # Interpolate between the last frame and the current frame 243 | frameIndex = binarySearch(self.frames, time, self.FRAME_SPACING) 244 | lastFrameX = self.frames[frameIndex - 2] 245 | lastFrameY = self.frames[frameIndex - 1] 246 | frameTime = self.frames[frameIndex] 247 | percent = 1.0 - (time - frameTime) / (self.frames[frameIndex + self.LAST_FRAME_TIME] - frameTime) 248 | if percent < 0.0: 249 | percent = 0.0 250 | elif percent > 1.0: 251 | percent = 1.0 252 | percent = self.getCurvePercent(frameIndex / self.FRAME_SPACING - 1, percent) 253 | 254 | bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (self.frames[frameIndex + self.FRAME_X] - lastFrameX) * percent - bone.scaleX) * alpha 255 | bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (self.frames[frameIndex + self.FRAME_Y] - lastFrameY) * percent - bone.scaleY) * alpha 256 | return 257 | 258 | 259 | class ColorTimeline(CurveTimeline): 260 | def __init__(self, keyframeCount): 261 | super(ColorTimeline, self).__init__(keyframeCount) 262 | self.LAST_FRAME_TIME = -5 263 | self.FRAME_SPACING = -self.LAST_FRAME_TIME 264 | self.FRAME_R = 1 265 | self.FRAME_G = 2 266 | self.FRAME_B = 3 267 | self.FRAME_A = 4 268 | self.frames = [0] * (keyframeCount * self.FRAME_SPACING) 269 | self.slotIndex = 0 270 | 271 | 272 | def getDuration(self): 273 | return self.frames[self.LAST_FRAME_TIME] 274 | 275 | 276 | def getKeyframeCount(self): 277 | return len(self.frames) / self.FRAME_SPACING 278 | 279 | 280 | def setKeyframe(self, keyframeIndex, time, r, g, b, a): 281 | keyframeIndex *= self.FRAME_SPACING 282 | self.frames[keyframeIndex] = time 283 | self.frames[keyframeIndex + 1] = r 284 | self.frames[keyframeIndex + 2] = g 285 | self.frames[keyframeIndex + 3] = b 286 | self.frames[keyframeIndex + 4] = a 287 | 288 | 289 | def apply(self, skeleton, time, alpha): 290 | if time < self.frames[0]: # Time is before first frame. 291 | return 292 | 293 | slot = skeleton.slots[self.slotIndex] 294 | 295 | if time >= self.frames[self.LAST_FRAME_TIME]: # -5 296 | i = len(self.frames) - 1 297 | slot.r = self.frames[i - 3] # -4 298 | slot.g = self.frames[i - 2] # -3 299 | slot.b = self.frames[i - 1] # -2 300 | slot.a = self.frames[i] # -1 301 | return 302 | 303 | # Interpolate between the last frame and the current frame. 304 | frameIndex = binarySearch(self.frames, time, self.FRAME_SPACING) 305 | lastFrameR = self.frames[frameIndex - 4] 306 | lastFrameG = self.frames[frameIndex - 3] 307 | lastFrameB = self.frames[frameIndex - 2] 308 | lastFrameA = self.frames[frameIndex - 1] 309 | frameTime = self.frames[frameIndex] 310 | percent = 1 - (time - frameTime) / (self.frames[frameIndex + self.LAST_FRAME_TIME] - frameTime) 311 | if percent < 0.0: 312 | percent = 0.0 313 | if percent > 255: 314 | percent = 255 315 | percent = self.getCurvePercent(frameIndex / self.FRAME_SPACING - 1, percent) 316 | 317 | r = lastFrameR + (self.frames[frameIndex + self.FRAME_R] - lastFrameR) * percent 318 | g = lastFrameG + (self.frames[frameIndex + self.FRAME_G] - lastFrameG) * percent 319 | b = lastFrameB + (self.frames[frameIndex + self.FRAME_B] - lastFrameB) * percent 320 | a = lastFrameA + (self.frames[frameIndex + self.FRAME_A] - lastFrameA) * percent 321 | if alpha < 1: 322 | slot.r += (r - slot.r) * alpha 323 | slot.g += (g - slot.g) * alpha 324 | slot.b += (b - slot.b) * alpha 325 | slot.a += (a - slot.a) * alpha 326 | else: 327 | slot.r = r 328 | slot.g = g 329 | slot.b = b 330 | slot.a = a 331 | return 332 | 333 | 334 | class AttachmentTimeline(Timeline): 335 | def __init__(self, keyframeCount): 336 | super(AttachmentTimeline, self).__init__(keyframeCount) 337 | self.LAST_FRAME_TIME = -1 338 | self.FRAME_SPACING = -self.LAST_FRAME_TIME 339 | self.frames = [0.0] * keyframeCount 340 | self.attachmentNames = [None] * keyframeCount 341 | self.slotIndex = 0 342 | 343 | 344 | def getDuration(self): 345 | return self.frames[self.LAST_FRAME_TIME] 346 | 347 | 348 | def getKeyframeCount(self): 349 | len(self.frames) 350 | 351 | 352 | def setKeyframe(self, keyframeIndex, time, attachmentName): 353 | self.frames[keyframeIndex] = time 354 | self.attachmentNames[keyframeIndex] = attachmentName 355 | 356 | 357 | def apply(self, skeleton, time, alpha): 358 | if time < self.frames[0]: # Time is before first frame 359 | return 360 | 361 | frameIndex = 0 362 | if time >= self.frames[self.LAST_FRAME_TIME]: # Time is after last frame. 363 | frameIndex = self.LAST_FRAME_TIME 364 | else: 365 | frameIndex = binarySearch(self.frames, time, self.FRAME_SPACING) - 1 366 | attachmentName = self.attachmentNames[frameIndex] 367 | skeleton.slots[self.slotIndex].setAttachment(skeleton.getAttachmentByIndex(self.slotIndex, attachmentName)) 368 | return 369 | 370 | 371 | 372 | -------------------------------------------------------------------------------- /spine-python/src/Animation/__init__.py: -------------------------------------------------------------------------------- 1 | import Timeline 2 | 3 | class Animation(object): 4 | def __init__(self, name, timelines, duration): 5 | if not timelines: 6 | raise Exception('Timelines cannot be None.') 7 | self.name = name 8 | self.timelines = timelines 9 | self.duration = duration 10 | 11 | 12 | def mix(self, skeleton, time, loop, alpha): 13 | if not skeleton: 14 | raise Exception('Skeleton cannot be None.') 15 | 16 | if loop and duration: 17 | time = time % duration 18 | if loop and self.duration: 19 | time = time % self.duration 20 | 21 | for timeline in self.timelines: 22 | timeline.apply(skeleton, time, alpha) 23 | 24 | 25 | def apply(self, skeleton, time, loop): 26 | if not skeleton: 27 | raise Exception('Skeleton cannot be None.') 28 | 29 | if loop and self.duration: 30 | time = time % self.duration 31 | 32 | for timeline in self.timelines: 33 | timeline.apply(skeleton, time, 1) 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /spine-python/src/Atlas/AtlasPage.py: -------------------------------------------------------------------------------- 1 | class AtlasPage(object): 2 | def __init__(self): 3 | super(AtlasPage, self).__init__() 4 | self.name = None 5 | self.format = None 6 | self.minFilter = None 7 | self.magFilter = None 8 | self.uWrap = None 9 | self.vWrap = None 10 | 11 | 12 | -------------------------------------------------------------------------------- /spine-python/src/Atlas/AtlasRegion.py: -------------------------------------------------------------------------------- 1 | class BaseAtlasRegion(object): 2 | def __init__(self): 3 | self.name = NOne 4 | self.x = 0 5 | self.y = 0 6 | self.width = 0 7 | self.height = 0 8 | self.offsetX = 0.0 9 | self.offsetY = 0.0 10 | self.originalWidth = 0 11 | self.originalHeight = 0 12 | self.index = 0 13 | self.rotate = False 14 | self.flip = False 15 | self.splits = [] 16 | self.pads = [] 17 | -------------------------------------------------------------------------------- /spine-python/src/Atlas/__init__.py: -------------------------------------------------------------------------------- 1 | import itertools, collections 2 | import os 3 | 4 | 5 | from .. import Enum 6 | 7 | formatNames = ('Alpha', 8 | 'Intensity', 9 | 'LuminanceAlpha', 10 | 'RGB565', 11 | 'RGBA4444', 12 | 'RGB888', 13 | 'RGBA8888') 14 | 15 | textureFiltureNames = ('Nearest', 16 | 'Linear', 17 | 'MipMap', 18 | 'MipMapNearestNearest', 19 | 'MipMapLinearNearest', 20 | 'MipMapNearestLinear', 21 | 'MipMapLinearLinear') 22 | 23 | class AtlasPage(object): 24 | def __init__(self): 25 | super(AtlasPage, self).__init__() 26 | self.name = None 27 | self.format = None 28 | self.minFilter = None 29 | self.magFilter = None 30 | self.uWrap = None 31 | self.vWrap = None 32 | 33 | 34 | class AtlasRegion(object): 35 | def __init__(self): 36 | super(AtlasRegion, self).__init__() 37 | self.name = None 38 | self.x = 0 39 | self.y = 0 40 | self.width = 0 41 | self.height = 0 42 | self.offsetX = 0.0 43 | self.offsetY = 0.0 44 | self.originalWidth = 0 45 | self.originalHeight = 0 46 | self.index = 0 47 | self.rotate = False 48 | self.flip = False 49 | self.splits = [] 50 | self.pads = [] 51 | 52 | 53 | Format = Enum.enum(alpha=0, 54 | intensity=1, 55 | luminanceAlpha=2, 56 | rgb565=3, 57 | rgba4444=4, 58 | rgb888=5, 59 | rgba8888=6) 60 | 61 | 62 | TextureFilter = Enum.enum(nearest=0, 63 | linear=1, 64 | mipMap=2, 65 | mipMapNearestNearest=3, 66 | mipMapLinearNearest=4, 67 | mipMapNearestLinear=5, 68 | mipMapLinearLinear=6) 69 | 70 | 71 | TextureWrap = Enum.enum(mirroredRepeat=0, 72 | clampToEdge=1, 73 | repeat=2) 74 | 75 | 76 | class Atlas(object): 77 | def __init__(self): 78 | super(Atlas, self).__init__() 79 | self.pages = [] 80 | self.regions = [] 81 | 82 | 83 | def loadWithFile(self, file): 84 | if not file: 85 | raise Exception('input cannot be null.') 86 | 87 | text = None 88 | 89 | with open(os.path.realpath(file), 'r') as fh: 90 | text = fh.readlines() 91 | self.load(text) 92 | 93 | def load(self, text): 94 | page = None 95 | region = None 96 | _page = None 97 | _region = {} 98 | 99 | 100 | for line in text: 101 | value = line.strip().rstrip() 102 | if len(value) == 0: 103 | _page = {} 104 | page = None 105 | if not page: 106 | if not ':' in value: 107 | value = value.strip().rstrip() 108 | _page['name'] = value 109 | else: 110 | (key, value) = value.split(':') 111 | key = key.strip().rstrip() 112 | value = value.strip().rstrip() 113 | if ',' in value: 114 | value = value.split(',') 115 | _page[key] = [x.strip().rstrip() for x in value] 116 | else: 117 | if value == 'false': 118 | value = False 119 | elif value == 'true': 120 | value = True 121 | _page[key] = value 122 | if key == 'repeat': 123 | page = self.newAtlasPage(_page['name']) 124 | page.format = _page['format'] 125 | page.minFilter = _page['filter'][0] 126 | page.magFilter = _page['filter'][1] 127 | if _page['repeat'] == 'x': 128 | page.uWrap = TextureWrap.repeat 129 | page.vWrap = TextureWrap.clampToEdge 130 | elif _page['repeat'] == 'y': 131 | page.uWrap = TextureWrap.clampToEdge 132 | page.vWrap = TextureWrap.repeat 133 | elif _page['repeat'] == 'xy': 134 | page.uWrap = TextureWrap.repeat 135 | page.vWrap = TextureWrap.repeat 136 | self.pages.append(page) 137 | else: 138 | if not ':' in value: 139 | value = value.strip().rstrip() 140 | _region['name'] = value 141 | else: 142 | (key, value) = value.split(':') 143 | key = key.strip().rstrip() 144 | value = value.strip().rstrip() 145 | if ',' in value: 146 | value = value.split(',') 147 | _region[key] = [int(x.strip().rstrip()) for x in value] 148 | else: 149 | if value == 'false': 150 | value = False 151 | elif value == 'true': 152 | value = True 153 | _region[key] = value 154 | if key == 'index': 155 | region = self.newAtlasRegion(page) 156 | region.name = _region['name'] 157 | region.x = _region['xy'][0] 158 | region.y = _region['xy'][1] 159 | region.width = _region['size'][0] 160 | region.height = _region['size'][1] 161 | if 'split' in _region: 162 | region.splits.append(_region['split'][0]) 163 | region.splits.append(_region['split'][1]) 164 | region.splits.append(_region['split'][2]) 165 | region.splits.append(_region['split'][3]) 166 | if 'pad' in _region: 167 | region.pads.append(_region['pad'][0]) 168 | region.pads.append(_region['pad'][1]) 169 | region.pads.append(_region['pad'][2]) 170 | region.pads.append(_region['pad'][3]) 171 | region.originalWidth = _region['orig'][0] 172 | region.originalHeight = _region['orig'][1] 173 | region.offsetX = _region['offset'][0] 174 | region.offsetY = _region['offset'][1] 175 | region.index = int(_region['index']) 176 | self.regions.append(region) 177 | _region = {} 178 | continue 179 | 180 | 181 | def findRegion(self, name): 182 | for region in self.regions: 183 | if region.name == name: 184 | return region 185 | return None 186 | 187 | 188 | def newAtlasPage(self, name): 189 | pass 190 | 191 | 192 | def newAtlasRegion(self, page): 193 | pass 194 | 195 | 196 | -------------------------------------------------------------------------------- /spine-python/src/Attachment.py: -------------------------------------------------------------------------------- 1 | class Attachment(object): 2 | def __init__(self): 3 | self.name = None 4 | 5 | def draw(self, slot): 6 | pass 7 | -------------------------------------------------------------------------------- /spine-python/src/AttachmentLoader.py: -------------------------------------------------------------------------------- 1 | import Enum 2 | 3 | AttachmentType = Enum.enum(region=0, 4 | regionSequence=1) 5 | 6 | class AttachmentLoader(object): 7 | def __init__(self): 8 | super(AttachmentLoader, self).__init__() 9 | 10 | def newAttachment(type, name): 11 | pass 12 | 13 | -------------------------------------------------------------------------------- /spine-python/src/Bone.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class Bone(object): 4 | def __init__(self, data): 5 | super(Bone, self).__init__() 6 | self.data = data 7 | self.parent = None 8 | self.x = data.x 9 | self.y = data.y 10 | self.rotation = data.rotation 11 | self.scaleX = data.scaleX 12 | self.scaleY = data.scaleY 13 | self.m00 = 0.0 14 | self.m01 = 0.0 15 | self.m10 = 0.0 16 | self.m11 = 0.0 17 | self.worldX = 0.0 18 | self.worldY = 0.0 19 | self.worldRotation = 0.0 20 | self.worldScaleX = 0.0 21 | self.worldScaleY = 0.0 22 | self.line = None 23 | self.circle = None 24 | 25 | 26 | def setToBindPose(self): 27 | self.x = self.data.x 28 | self.y = self.data.y 29 | self.rotation = self.data.rotation 30 | self.scaleX = self.data.scaleX 31 | self.scaleY = self.data.scaleY 32 | 33 | 34 | def updateWorldTransform(self, flipX, flipY): 35 | if self.parent: 36 | self.worldX = self.x * self.parent.m00 + self.y * self.parent.m01 + self.parent.worldX 37 | self.worldY = self.x * self.parent.m10 + self.y * self.parent.m11 + self.parent.worldY 38 | self.worldScaleX = self.parent.worldScaleX * self.scaleX 39 | self.worldScaleY = self.parent.worldScaleY * self.scaleY 40 | self.worldRotation = self.parent.worldRotation + self.rotation 41 | else: 42 | self.worldX = self.x 43 | self.worldY = self.y 44 | self.worldScaleX = self.scaleX 45 | self.worldScaleY = self.scaleY 46 | self.worldRotation = self.rotation 47 | 48 | radians = math.radians(self.worldRotation) 49 | cos = math.cos(radians) 50 | sin = math.sin(radians) 51 | self.m00 = cos * self.worldScaleX 52 | self.m10 = sin * self.worldScaleX 53 | self.m01 = -sin * self.worldScaleY 54 | self.m11 = cos * self.worldScaleY 55 | 56 | if flipX: 57 | self.m00 = -self.m00 58 | self.m01 = -self.m01 59 | if flipY: 60 | self.m10 = -self.m10 61 | self.m11 = -self.m11 62 | # The C++ runtime has this, but Corona doesn't. 63 | #if self.data.flipY: 64 | # self.m10 = -self.m10 if self.m10 != 0.0 else 0.0 65 | # self.m11 = -self.m11 if self.m11 != 0.0 else 0.0 66 | 67 | -------------------------------------------------------------------------------- /spine-python/src/BoneData.py: -------------------------------------------------------------------------------- 1 | class BoneData(object): 2 | def __init__(self, name): 3 | super(BoneData, self).__init__() 4 | self.name = name 5 | self.parent = None 6 | self.length = 0.0 7 | self.x = 0.0 8 | self.y = 0.0 9 | self.rotation = 0.0 10 | self.scaleX = 1.0 11 | self.scaleY = 1.0 12 | self.flipY = False 13 | 14 | -------------------------------------------------------------------------------- /spine-python/src/Enum.py: -------------------------------------------------------------------------------- 1 | def enum(**enums): 2 | return type('Enum', (), enums) 3 | 4 | -------------------------------------------------------------------------------- /spine-python/src/RegionAttachment.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import Attachment 4 | 5 | class RegionAttachment(Attachment.Attachment): 6 | def __init__(self): 7 | super(RegionAttachment, self).__init__() 8 | self.x = 0.0 9 | self.y = 0.0 10 | self.scaleX = 1.0 11 | self.scaleY = 1.0 12 | self.rotation = 0.0 13 | self.width = 0.0 14 | self.height = 0.0 15 | self.offset = [0.0, 16 | 0.0, 17 | 0.0, 18 | 0.0, 19 | 0.0, 20 | 0.0, 21 | 0.0, 22 | 0.0] 23 | 24 | 25 | def updateOffset(self): 26 | localX2 = self.width / 2.0 27 | localY2 = self.height / 2.0 28 | localX = -localX2 29 | localY = -localY2 30 | localX *= self.scaleX 31 | localY *= self.scaleY 32 | radians = math.radians(self.rotation) 33 | cos = math.cos(radians) 34 | sin = math.sin(radians) 35 | localXCos = localX * cos + self.x 36 | localXSin = localX * sin 37 | localYCos = localY * cos + self.y 38 | localYSin = localY * sin 39 | localX2Cos = localX2 * cos + self.x 40 | localX2Sin = localX2 * sin 41 | localY2Cos = localY2 * cos + self.y 42 | localY2Sin = localY2 * sin 43 | self.offset[0] = localXCos - localYSin 44 | self.offset[1] = localYCos + localXSin 45 | self.offset[2] = localXCos - localY2Sin 46 | self.offset[3] = localY2Cos + localXSin 47 | self.offset[4] = localX2Cos - localY2Sin 48 | self.offset[5] = localY2Cos + localX2Sin 49 | self.offset[6] = localX2Cos - localYSin 50 | self.offset[7] = localYCos + localX2Sin 51 | 52 | 53 | def updateWorldVerticies(self, bone): 54 | pass 55 | 56 | -------------------------------------------------------------------------------- /spine-python/src/Skeleton.py: -------------------------------------------------------------------------------- 1 | from Bone import Bone 2 | from Slot import Slot 3 | 4 | class Skeleton(object): 5 | def __init__(self, skeletonData): 6 | super(Skeleton, self).__init__() 7 | self.data = skeletonData 8 | self.skin = None 9 | self.r = 1.0 10 | self.g = 1.0 11 | self.b = 1.0 12 | self.a = 1.0 13 | self.time = 0.0 14 | self.bones = [] 15 | self.slots = [] 16 | self.drawOrder = [] 17 | self.flipX = False 18 | self.flipY = False 19 | 20 | if not self.data: 21 | raise Exception('skeletonData can not be null.') 22 | 23 | boneCount = len(self.data.bones) 24 | self.bones = [None] * boneCount 25 | for i in range(boneCount): 26 | boneData = self.data.bones[i] 27 | bone = Bone(data=boneData) 28 | if boneData.parent: 29 | for ii in range(boneCount): 30 | if self.data.bones[ii] == boneData.parent: 31 | bone.parent = self.bones[ii] 32 | break 33 | self.bones[i] = bone 34 | 35 | slotCount = len(self.data.slots) 36 | self.slots = [None] * slotCount 37 | for i in range(slotCount): 38 | slotData = self.data.slots[i] 39 | bone = None 40 | for ii in range(boneCount): 41 | if self.data.bones[ii] == slotData.boneData: 42 | bone = self.bones[ii] 43 | break 44 | slot = Slot(slotData=slotData, skeleton=self, bone=bone) 45 | self.slots[i] = slot 46 | self.drawOrder.append(slot) 47 | 48 | 49 | def updateWorldTransform(self): 50 | for i, bone in enumerate(self.bones): 51 | self.bones[i].updateWorldTransform(self.flipX, self.flipY) 52 | 53 | 54 | def setToBindPose(self): 55 | self.setBonesToBindPose() 56 | self.setSlotsToBindPose() 57 | 58 | 59 | def setBonesToBindPose(self): 60 | for i, bone in enumerate(self.bones): 61 | self.bones[i].setToBindPose() 62 | 63 | 64 | def setSlotsToBindPose(self): 65 | for i, bone in enumerate(self.slots): 66 | self.slots[i].setToBindPoseWithIndex(i) 67 | 68 | 69 | def getRootBone(self): 70 | if len(self.bones): 71 | return self.bones[0] 72 | return None 73 | 74 | 75 | def setRootBone(self, bone): 76 | if len(self.bones): 77 | self.bones[0] = bone 78 | 79 | 80 | def findBone(self, boneName): 81 | for i, bone in enumerate(self.bones): 82 | if self.data.bones[i].name == boneName: 83 | return self.bones[i] 84 | return None 85 | 86 | 87 | def findBoneIndex(self, boneName): 88 | for i, bone in enumerate(self.bones): 89 | if self.data.bones[i].name == boneName: 90 | return i 91 | return -1 92 | 93 | 94 | def findSlot(self, slotName): 95 | for i, slot in enumerate(self.slots): 96 | if self.data.slots[i].name == slotName: 97 | return self.slots[i] 98 | return None 99 | 100 | 101 | def findSlotIndex(self, slotName): 102 | for i, slot in enumerate(self.slots): 103 | if self.data.slots[i].name == slotName: 104 | return i 105 | return -1 106 | 107 | 108 | def setSkin(self, skinName): 109 | skin = self.data.findSkin(skinName) 110 | if not skin: 111 | raise Exception('Skin not found: %s' % skinName) 112 | self.setSkinToSkin(skin) 113 | 114 | 115 | def setSkinToSkin(self, newSkin): 116 | if self.skin and newSkin: 117 | newSkin.attachAll(self, self.skin) 118 | self.skin = newSkin 119 | 120 | 121 | def getAttachmentByName(self, slotName, attachmentName): 122 | return self.getAttachmentByIndex(self.data.findSlotIndex(slotName), attachmentName) 123 | 124 | 125 | def getAttachmentByIndex(self, slotIndex, attachmentName): 126 | if self.data.defaultSkin: 127 | attachment = self.data.defaultSkin.getAttachment(slotIndex, attachmentName) 128 | if attachment: 129 | return attachment 130 | if self.skin: 131 | return self.skin.getAttachment(slotIndex, attachmentName) 132 | return None 133 | 134 | 135 | def setAttachment(self, slotName, attachmentName): 136 | for i in range(len(self.slots)): 137 | if self.slots[i].data.name == slotName: 138 | self.slots[i].setAttachment(self.getAttachmentByIndex(i, attachmentName)) 139 | return 140 | raise Exception('Slot not found: %s' % slotName) 141 | 142 | 143 | def update(self, delta): 144 | self.time += delta 145 | 146 | 147 | -------------------------------------------------------------------------------- /spine-python/src/SkeletonData.py: -------------------------------------------------------------------------------- 1 | class SkeletonData(object): 2 | def __init__(self): 3 | super(SkeletonData, self).__init__() 4 | self.bones = [] 5 | self.slots = [] 6 | self.skins = [] 7 | self.animations = [] 8 | self.defaultSkin = None 9 | 10 | 11 | def findBone(self, boneName): 12 | for i, bone in enumerate(self.bones): 13 | if bone.name == boneName: 14 | return bone 15 | return None 16 | 17 | 18 | def findBoneIndex(self, boneName): 19 | for i, bone in enumerate(self.bones): 20 | if bone.name == boneName: 21 | return i 22 | return -1 23 | 24 | 25 | def findSlot(self, slotName): 26 | for i, slot in enumerate(self.slots): 27 | if slot.name == slotName: 28 | return slot 29 | return None 30 | 31 | 32 | def findSlotIndex(self, slotName): 33 | for i, slot in enumerate(self.slots): 34 | if slot.name == slotName: 35 | return i 36 | return -1 37 | 38 | 39 | def findSkin(self, skinName): 40 | for i, skin in enumerate(self.skins): 41 | if skin.name == skinName: 42 | return skin 43 | return None 44 | 45 | 46 | def findAnimation(self, animationName): 47 | for i, animation in enumerate(self.animations): 48 | if animation.name == animationName: 49 | return animation 50 | return None 51 | -------------------------------------------------------------------------------- /spine-python/src/SkeletonJson.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import sys 4 | 5 | import SkeletonData 6 | import BoneData 7 | import SlotData 8 | import Skin 9 | import AttachmentLoader 10 | 11 | import Animation 12 | 13 | 14 | def readCurve(timeline, keyframeIndex, valueMap): 15 | try: 16 | curve = valueMap['curve'] 17 | except KeyError: 18 | return timeline 19 | 20 | if curve == 'stepped': 21 | timeline.setStepped(keyframeIndex) 22 | else: 23 | timeline.setCurve(keyframeIndex, 24 | float(curve[0]), 25 | float(curve[1]), 26 | float(curve[2]), 27 | float(curve[3])) 28 | return timeline 29 | 30 | 31 | class SkeletonJson(object): 32 | def __init__(self, attachmentLoader): 33 | super(SkeletonJson, self).__init__() 34 | self.attachmentLoader = attachmentLoader 35 | self.scale = 1.0 36 | self.flipY = False 37 | 38 | def readSkeletonDataFile(self, file, path=None): 39 | if path: 40 | file = '{path}/{file}'.format(path=path, file=file) 41 | 42 | file = os.path.realpath(file) 43 | 44 | jasonPayload = None 45 | 46 | with open(file, 'r') as jsonFile: 47 | jsonPayload = ''.join(jsonFile.readlines()) 48 | 49 | return self.readSkeletonData(jsonPayload=jsonPayload) 50 | 51 | 52 | def readSkeletonData(self, jsonPayload): 53 | try: 54 | root = json.loads(jsonPayload) 55 | except ValueError: 56 | if os.path.isfile(jsonPayload): 57 | print('The API has changed. You need to load skeleton data with readSkeletonDataFile(), not readSkeletonData()') 58 | sys.exit() 59 | 60 | skeletonData = SkeletonData.SkeletonData() 61 | 62 | for boneMap in root.get('bones', []): 63 | boneData = BoneData.BoneData(name=boneMap['name']) 64 | 65 | if 'parent' in boneMap: 66 | boneData.parent = skeletonData.findBone(boneMap['parent']) 67 | if not boneData.parent: 68 | raise Exception('Parent bone not found: %s' % boneMap['name']) 69 | 70 | boneData.length = float(boneMap.get('length', 0.0)) * self.scale 71 | boneData.x = float(boneMap.get('x', 0.0)) * self.scale 72 | boneData.y = float(boneMap.get('y', 0.0)) * self.scale 73 | boneData.rotation = float(boneMap.get('rotation', 0.0)) 74 | boneData.scaleX = float(boneMap.get('scaleX', 1.0)) 75 | boneData.scaleY = float(boneMap.get('scaleY', 1.0)) 76 | skeletonData.bones.append(boneData) 77 | 78 | for slotMap in root.get('slots', []): 79 | slotName = slotMap['name'] 80 | boneName = slotMap['bone'] 81 | boneData = skeletonData.findBone(boneName) 82 | 83 | if not BoneData: 84 | raise Exception('Slot bone not found: %s' % boneName) 85 | slotData = SlotData.SlotData(name=slotName, boneData=boneData) 86 | 87 | if 'color' in slotMap: 88 | s = slotMap['color'] 89 | slotData.r = int(slotMap['color'][0:2], 16) 90 | slotData.g = int(slotMap['color'][2:4], 16) 91 | slotData.b = int(slotMap['color'][4:6], 16) 92 | slotData.a = int(slotMap['color'][6:8], 16) 93 | 94 | if 'attachment' in slotMap: 95 | slotData.attachmentName = slotMap['attachment'] 96 | 97 | skeletonData.slots.append(slotData) 98 | 99 | skinsMap = root.get('skins', {}) 100 | for skinName in skinsMap.keys(): 101 | skin = Skin.Skin(skinName) 102 | skeletonData.skins.append(skin) 103 | if skinName == 'default': 104 | skeletonData.defaultSkin = skin 105 | 106 | slotMap = skinsMap[skinName] 107 | for slotName in slotMap.keys(): 108 | slotIndex = skeletonData.findSlotIndex(slotName) 109 | 110 | attachmentsMap = slotMap[slotName] 111 | for attachmentName in attachmentsMap.keys(): 112 | attachmentMap = attachmentsMap[attachmentName] 113 | 114 | type = None 115 | 116 | typeString = attachmentMap.get('type', 'region') 117 | 118 | if typeString == 'region': 119 | type = AttachmentLoader.AttachmentType.region 120 | elif typeString == 'regionSequence': 121 | type = AttachmentLoader.AttachmentType.regionSequence 122 | else: 123 | raise Exception('Unknown attachment type: %s (%s)' % (attachment['type'], 124 | attachmentName)) 125 | 126 | attachment = self.attachmentLoader.newAttachment(type, 127 | attachmentMap.get('name', attachmentName)) 128 | 129 | if type == AttachmentLoader.AttachmentType.region or type == AttachmentLoader.AttachmentType.regionSequence: 130 | regionAttachment = attachment 131 | regionAttachment.name = attachmentName 132 | regionAttachment.x = float(attachmentMap.get('x', 0.0)) * self.scale 133 | regionAttachment.y = float(attachmentMap.get('y', 0.0)) * self.scale 134 | regionAttachment.scaleX = float(attachmentMap.get('scaleX', 1.0)) 135 | regionAttachment.scaleY = float(attachmentMap.get('scaleY', 1.0)) 136 | regionAttachment.rotation = float(attachmentMap.get('rotation', 0.0)) 137 | regionAttachment.width = float(attachmentMap.get('width', 32)) * self.scale 138 | regionAttachment.height = float(attachmentMap.get('height', 32)) * self.scale 139 | skin.addAttachment(slotIndex, attachmentName, attachment) 140 | 141 | animations = root.get('animations', {}) 142 | for animationName in animations: 143 | animationMap = animations.get(animationName, {}) 144 | animationData = self.readAnimation(name=animationName, 145 | root=animationMap, 146 | skeletonData=skeletonData) 147 | skeletonData.animations.append(animationData) 148 | 149 | return skeletonData 150 | 151 | 152 | def readAnimation(self, name, root, skeletonData): 153 | if not skeletonData: 154 | raise Exception('skeletonData cannot be null.') 155 | 156 | timelines = [] 157 | duration = 0.0 158 | 159 | bones = root.get('bones', {}) 160 | 161 | for boneName in bones.keys(): 162 | boneIndex = skeletonData.findBoneIndex(boneName) 163 | if boneIndex == -1: 164 | raise Exception('Bone not found: %s' % boneName) 165 | 166 | timelineMap = bones[boneName] 167 | 168 | for timelineName in timelineMap.keys(): 169 | values = timelineMap[timelineName] 170 | 171 | if timelineName == 'rotate': 172 | timeline = Animation.Timeline.RotateTimeline(len(values)) 173 | timeline.boneIndex = boneIndex 174 | 175 | keyframeIndex = 0 176 | for valueMap in values: 177 | time = valueMap['time'] 178 | timeline.setKeyframe(keyframeIndex, time, valueMap['angle']) 179 | timeline = readCurve(timeline, keyframeIndex, valueMap) 180 | keyframeIndex += 1 181 | timelines.append(timeline) 182 | if timeline.getDuration() > duration: 183 | duration = timeline.getDuration() 184 | elif timelineName == 'translate' or timelineName == 'scale': 185 | timeline = None 186 | timelineScale = 1.0 187 | if timelineName == 'scale': 188 | timeline = Animation.Timeline.ScaleTimeline(len(values)) 189 | else: 190 | timeline = Animation.Timeline.TranslateTimeline(len(values)) 191 | timelineScale = self.scale 192 | timeline.boneIndex = boneIndex 193 | 194 | keyframeIndex = 0 195 | for valueMap in values: 196 | time = valueMap['time'] 197 | timeline.setKeyframe(keyframeIndex, 198 | valueMap['time'], 199 | valueMap.get('x', 0.0), 200 | valueMap.get('y', 0.0)) 201 | timeline = readCurve(timeline, keyframeIndex, valueMap) 202 | keyframeIndex += 1 203 | timelines.append(timeline) 204 | if timeline.getDuration() > duration: 205 | duration = timeline.getDuration() 206 | else: 207 | raise Exception('Invalid timeline type for a bone: %s (%s)' % (timelineName, boneName)) 208 | 209 | 210 | slots = root.get('slots', {}) 211 | 212 | for slotName in slots.keys(): 213 | slotIndex = skeletonData.findSlotIndex(slotName) 214 | if slotIndex == -1: 215 | raise Exception('Slot not found: %s' % slotName) 216 | 217 | timelineMap = slots[slotName] 218 | for timelineName in timelineMap.keys(): 219 | values = timelineMap[timelineName] 220 | if timelineName == 'color': 221 | timeline = Animation.Timeline.ColorTimeline(len(values)) 222 | timeline.slotIndex = slotIndex 223 | 224 | keyframeIndex = 0 225 | for valueMap in values: 226 | timeline.setKeyframe(keyframeIndex, 227 | valueMap['time'], 228 | int(valueMap['color'][0:2], 16), 229 | int(valueMap['color'][2:4], 16), 230 | int(valueMap['color'][4:6], 16), 231 | int(valueMap['color'][6:8], 16)) 232 | timeline = readCurve(timeline, keyframeIndex, valueMap) 233 | keyframeIndex += 1 234 | timelines.append(timeline) 235 | if timeline.getDuration > duration: 236 | duration = timeline.getDuration() 237 | 238 | elif timelineName == 'attachment': 239 | timeline = Animation.Timeline.AttachmentTimeline(len(values)) 240 | timeline.slotIndex = slotIndex 241 | 242 | keyframeIndex = 0 243 | for valueMap in values: 244 | valueName = valueMap['name'] 245 | timeline.setKeyframe(keyframeIndex, valueMap['time'], '' if not valueName else valueName) 246 | keyframeIndex += 1 247 | timelines.append(timeline) 248 | if timeline.getDuration > duration: 249 | duration = timeline.getDuration() 250 | else: 251 | raise Exception('Invalid timeline type for a slot: %s (%s)' % (timelineName, slotName)) 252 | 253 | animation = Animation.Animation(name, timelines, duration) 254 | return animation 255 | 256 | 257 | -------------------------------------------------------------------------------- /spine-python/src/Skin.py: -------------------------------------------------------------------------------- 1 | class Key(object): 2 | def __init__(self, slotIndex, name): 3 | super(Key, self).__init__() 4 | self.slotIndex = slotIndex 5 | self.name = name 6 | 7 | def __lt__(self, key): 8 | if self.slotIndex == key.slotIndex: 9 | return self.name < key.name 10 | return self.slotIndex < key.slotIndex 11 | 12 | def __hash__(self): 13 | return hash((self.slotIndex, self.name)) 14 | 15 | def __eq__(self, other): 16 | return (self.slotIndex, self.name) == (other.slotIndex, other.name) 17 | 18 | 19 | class Skin(object): 20 | def __init__(self, name): 21 | super(Skin, self).__init__() 22 | if not name: 23 | raise Exception('Name cannot be None.') 24 | self.name = name 25 | self.attachments = {} 26 | 27 | 28 | def addAttachment(self, slotIndex, name, attachment): 29 | if not name: 30 | raise Exception('Name cannot be None.') 31 | key = Key(slotIndex=slotIndex, name=name) 32 | self.attachments[key] = attachment 33 | 34 | 35 | def getAttachment(self, slotIndex, name): 36 | key = Key(slotIndex=slotIndex, name=name) 37 | if key in self.attachments: 38 | return self.attachments[key] 39 | return None 40 | 41 | 42 | def attachAll(self, skeleton, oldSkin): 43 | for key, attachment in self.attachments.iteritems(): 44 | slot = skeleton.slots[key.slotIndex] 45 | if skeleton.slots[key.slotIndex].attachment == attachment: 46 | newAttachment = self.getAttachment(key.slotIndex, key.name) 47 | if newAttachment: 48 | skeleton.slots[key.slotIndex].setAttachment(newAttachment) 49 | 50 | -------------------------------------------------------------------------------- /spine-python/src/Slot.py: -------------------------------------------------------------------------------- 1 | class Slot(object): 2 | def __init__(self, slotData, skeleton, bone): 3 | super(Slot, self).__init__() 4 | if not slotData: 5 | raise Exception('slotData cannot be None.') 6 | if not skeleton: 7 | raise Exception('skeleton cannot be None.') 8 | if not bone: 9 | raise Exception('bone cannot be None.') 10 | self.data = slotData 11 | self.skeleton = skeleton 12 | self.bone = bone 13 | self.r = 255 14 | self.g = 255 15 | self.b = 255 16 | self.a = 255 17 | self.attachment = None 18 | self.attachmentTime = 0.0 19 | self.setToBindPose() 20 | 21 | 22 | def setColor(self, r, g, b, a): 23 | self.r = r 24 | self.g = g 25 | self.b = b 26 | self.a = a 27 | 28 | 29 | def setAttachment(self, attachment): 30 | self.attachment = attachment 31 | self.attachmentTime = self.skeleton.time 32 | 33 | 34 | def setAttachmentTime(self, time): 35 | self.attachmentTime = self.skeleton.time - time 36 | 37 | 38 | def getAttachmentTime(self): 39 | return self.skeleton.time - self.attachmentTime 40 | 41 | 42 | def setToBindPose(self): 43 | for i, slot in enumerate(self.skeleton.data.slots): 44 | if self.data == slot: 45 | self.setToBindPoseWithIndex(i) 46 | 47 | 48 | def setToBindPoseWithIndex(self, slotIndex): 49 | self.setColor(self.data.r, self.data.g, self.data.b, self.data.a) 50 | self.setAttachment(self.skeleton.getAttachmentByIndex(slotIndex, self.data.attachmentName) if self.data.attachmentName else None) 51 | 52 | 53 | -------------------------------------------------------------------------------- /spine-python/src/SlotData.py: -------------------------------------------------------------------------------- 1 | class SlotData(object): 2 | def __init__(self, name, boneData): 3 | super(SlotData, self).__init__() 4 | if not name: 5 | raise Exception('Name cannot be None.') 6 | 7 | if not boneData: 8 | raise Exception('boneData cannot be None.') 9 | 10 | self.name = name 11 | self.boneData = boneData 12 | self.r = 255 13 | self.g = 255 14 | self.b = 255 15 | self.a = 255 16 | self.attachmentName = None 17 | 18 | 19 | def setColor(r, g, b, a): 20 | self.r = r 21 | self.g = g 22 | self.b = b 23 | self.a = a 24 | 25 | -------------------------------------------------------------------------------- /spine-python/src/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging.getLogger('spine').addHandler(logging.NullHandler()) 4 | 5 | import AttachmentLoader 6 | from Atlas import * 7 | from RegionAttachment import * 8 | from Skeleton import * 9 | 10 | 11 | --------------------------------------------------------------------------------