Compare commits

...

907 Commits

Author SHA1 Message Date
tuxinyu
99698904cb 1111111111111 2025-11-05 20:28:17 +08:00
tuxinyu
d4839a56d7 1111111111 2025-11-04 21:46:07 +08:00
tuxinyu
282b5a9eea 111111111 2025-11-04 21:24:44 +08:00
puxuan
887eb5a9c0 config 2025-11-04 09:48:04 +08:00
puxuan
3448608f15 Merge branch 'dev_hero' into dev_hero_2 2025-11-04 09:46:54 +08:00
tuxinyu
bbd66e3e00 1111111111111 2025-11-03 21:29:58 +08:00
changyuxiang
befedf64ec wwwwwwwwwwwwwwwwwwwww 2025-11-03 21:25:38 +08:00
tuxinyu
5386c24504 11111111111 2025-11-03 21:05:13 +08:00
puxuan
d686512f63 引导 2025-11-03 20:38:20 +08:00
puxuan
8adf53316b Merge branch 'dev_hero' into dev_hero_2 2025-11-03 20:36:06 +08:00
puxuan
b92e5b89ec res 2025-11-03 20:33:57 +08:00
tuxinyu
3ced501994 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-11-03 20:21:25 +08:00
tuxinyu
3093ef4090 11111111 2025-11-03 20:20:10 +08:00
changyuxiang
df95c52b96 改命名 2025-11-03 19:33:16 +08:00
changyuxiang
6d73ccff00 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-11-03 19:28:25 +08:00
puxuan
66232f5e98 fix bug 2025-11-03 17:00:05 +08:00
puxuan
950316ee4b ui 2025-11-03 15:07:13 +08:00
puxuan
39388fd074 fix bug 2025-11-03 12:11:19 +08:00
puxuan
51b6713b1e fix bug 2025-11-03 12:06:09 +08:00
puxuan
47fdba73ae fix bug 2025-11-03 12:01:06 +08:00
puxuan
03cb55a053 屏蔽广告 2025-11-02 21:44:30 +08:00
puxuan
9b92dfe59c config 2025-10-31 21:57:53 +08:00
puxuan
6824f0a4ad Merge branch 'dev_hero' into dev_hero_2 2025-10-31 21:57:03 +08:00
changyuxiang
1de3560cbe 1 2025-10-31 21:56:36 +08:00
changyuxiang
b30f3c7f8e 1 2025-10-31 21:52:14 +08:00
puxuan
0e69e79e7c fix bug 2025-10-31 21:51:54 +08:00
puxuan
fbb3b526ba Merge branch 'dev_hero' into dev_hero_2 2025-10-31 21:26:14 +08:00
puxuan
28dc4d0547 fix bug 2025-10-31 21:25:55 +08:00
changyuxiang
f8cd5af72d 1 2025-10-31 20:41:13 +08:00
puxuan
c0d9bde0e3 Merge branch 'dev_hero' into dev_hero_2 2025-10-31 20:33:04 +08:00
puxuan
cbce1e763f 竞技场 2025-10-31 20:32:48 +08:00
puxuan
989528fb19 fix bug 2025-10-31 20:12:49 +08:00
changyuxiang
bfb73d847f 1 2025-10-31 20:06:00 +08:00
puxuan
9d793b77d8 fix bug 2025-10-31 17:43:21 +08:00
puxuan
e16ec04399 fix bug 2025-10-31 16:41:10 +08:00
puxuan
e47b25c768 fix bug 2025-10-31 15:42:38 +08:00
puxuan
ed24e15ec9 万能块特效 2025-10-31 15:31:48 +08:00
puxuan
451fd0ce81 fix bug 2025-10-31 14:48:16 +08:00
puxuan
ed413b1ec4 config 2025-10-31 14:07:08 +08:00
puxuan
8d091709e0 fix bug 2025-10-31 12:04:02 +08:00
puxuan
71f7222f0a fix bug 2025-10-31 11:32:52 +08:00
puxuan
dee9d7cc12 Merge branch 'dev_hero' into dev_hero_2 2025-10-31 09:37:57 +08:00
changyuxiang
cfbf191f67 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-30 21:49:25 +08:00
changyuxiang
590c1e7488 小怪音效 2025-10-30 21:49:20 +08:00
puxuan
f07dc748bc fix bug 2025-10-30 21:40:17 +08:00
tuxinyu
ba50a1f1e0 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-30 21:30:26 +08:00
tuxinyu
0a117db90e 11111111 2025-10-30 21:30:16 +08:00
puxuan
735742b767 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-30 21:20:32 +08:00
puxuan
5123b7984e Merge branch 'dev_hero_2' into dev_hero 2025-10-30 21:19:27 +08:00
puxuan
f235f33dea 引导 2025-10-30 21:19:09 +08:00
tuxinyu
c6877c6828 111111111 2025-10-30 21:18:36 +08:00
tuxinyu
70c510cbbf 111111111 2025-10-30 21:12:23 +08:00
puxuan
2c04d8d58f 技能增加能量特效 2025-10-30 21:08:31 +08:00
puxuan
54d434e7f5 config 2025-10-30 20:17:09 +08:00
puxuan
4718cc678c Merge branch 'dev_hero_2' into dev_hero 2025-10-30 20:14:51 +08:00
puxuan
90cfba07ec 敌方属性 2025-10-30 20:13:42 +08:00
changyuxiang
ea9e7bed20 2 2025-10-30 19:56:08 +08:00
changyuxiang
8e10a42a76 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-30 19:46:31 +08:00
changyuxiang
89759c494f 1 2025-10-30 19:46:28 +08:00
puxuan
76f1bc51ad Merge branch 'dev_hero' into dev_hero_2 2025-10-30 19:17:19 +08:00
puxuan
7346cfbd67 . 2025-10-30 19:17:03 +08:00
puxuan
5cfff8f347 fix bug 2025-10-30 16:41:04 +08:00
puxuan
6761b1ba0a fix bug 2025-10-30 15:50:36 +08:00
puxuan
aef5a9a65e fix bug 2025-10-30 11:04:43 +08:00
puxuan
4be4b62167 fix bug 2025-10-30 10:41:05 +08:00
puxuan
4394a1e3e2 fix bug 2025-10-30 10:37:50 +08:00
puxuan
fe53bb012b . 2025-10-30 10:05:13 +08:00
puxuan
9686b4b97d Merge branch 'dev_hero' into dev_hero_2 2025-10-30 09:52:52 +08:00
tuxinyu
486b5100ac 1111111111 2025-10-29 21:57:32 +08:00
tuxinyu
208febb5b3 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-29 21:41:45 +08:00
tuxinyu
651c281c2f 1111111111 2025-10-29 21:41:38 +08:00
puxuan
940340cef8 fix bug 2025-10-29 21:32:12 +08:00
puxuan
b74e4e435b Merge branch 'dev_hero' into dev_hero_2 2025-10-29 21:23:01 +08:00
puxuan
eb4b1152a0 fix bug 2025-10-29 21:22:25 +08:00
changyuxiang
3fb0e3c90a 音效一大堆 2025-10-29 21:19:26 +08:00
tuxinyu
4cebc4b154 11111111111 2025-10-29 21:03:39 +08:00
tuxinyu
ac12bc45c4 111111111 2025-10-29 20:57:23 +08:00
tuxinyu
7150d872cf Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-29 20:53:41 +08:00
tuxinyu
49cf038bdb 11111111111111 2025-10-29 20:53:17 +08:00
puxuan
c1ca37bda5 Merge branch 'dev_hero' into dev_hero_2 2025-10-29 19:39:32 +08:00
puxuan
4944275cff 首充 2025-10-29 19:39:20 +08:00
changyuxiang
8511e51c00 改名字 2025-10-29 19:32:34 +08:00
changyuxiang
0d26fd250e 首充-剑仙 2025-10-29 19:28:53 +08:00
changyuxiang
fa630edd73 匹配成功动画 2025-10-29 19:22:30 +08:00
puxuan
602c93913c res 2025-10-29 19:21:20 +08:00
puxuan
bad9f48449 fix bug 2025-10-29 19:16:46 +08:00
puxuan
35dc7f578d fix bug 2025-10-29 16:38:54 +08:00
puxuan
14d5d42d08 fix bug 2025-10-29 15:17:36 +08:00
puxuan
7179ed8418 Merge branch 'dev_hero' into dev_hero_2 2025-10-29 09:47:00 +08:00
changyuxiang
cce578bee9 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-28 21:28:59 +08:00
puxuan
67efcf901b 竞技场 2025-10-28 21:27:58 +08:00
changyuxiang
48d81e5ba5 1 2025-10-28 21:19:22 +08:00
puxuan
7787a00ee1 Merge branch 'dev_hero' into dev_hero_2 2025-10-28 20:58:47 +08:00
puxuan
699e392036 fix bug 2025-10-28 20:58:11 +08:00
changyuxiang
c932ccaba6 竞技场-匹配中和匹配中(。。。) 2025-10-28 20:50:53 +08:00
changyuxiang
8109001683 胜利失败 2025-10-28 19:36:17 +08:00
changyuxiang
5d44b88212 段位图标 2025-10-28 19:31:35 +08:00
puxuan
993d54f500 fix bug 2025-10-28 18:33:55 +08:00
puxuan
6493b5c699 fix bug 2025-10-28 17:47:47 +08:00
puxuan
3dc8c37011 fix bug 2025-10-28 15:38:29 +08:00
puxuan
db8e86b49d fix bug 2025-10-28 11:34:25 +08:00
puxuan
d8fb97368a fix bug 2025-10-28 11:14:03 +08:00
puxuan
2ef607f0ab fix bug 2025-10-28 10:29:25 +08:00
puxuan
ce6f7a090b Merge branch 'dev_hero_2' into dev_hero 2025-10-28 09:37:29 +08:00
tuxinyu
a2d36fb396 11111111 2025-10-27 21:35:56 +08:00
changyuxiang
aa4f2bba5f 1 2025-10-27 20:38:43 +08:00
puxuan
1e8e9cc8f0 fix bug 2025-10-27 18:36:52 +08:00
puxuan
f2a2650f38 UI 2025-10-27 15:24:22 +08:00
puxuan
f0d7cabc29 . 2025-10-27 11:53:59 +08:00
puxuan
cdae7019c7 邮箱 2025-10-27 11:51:58 +08:00
puxuan
e685c77351 伤害公式 2025-10-27 10:54:45 +08:00
puxuan
95851df2af Merge branch 'dev_hero_2' into dev_hero 2025-10-26 18:11:36 +08:00
puxuan
639ceeb387 装备属性 2025-10-26 18:11:16 +08:00
tuxinyu
275bca1375 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-26 17:46:21 +08:00
tuxinyu
9886fc088c 1111111111 2025-10-26 17:46:08 +08:00
changyuxiang
f1410a4f58 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-26 15:44:26 +08:00
puxuan
7d62cb408e 升级升星属性 2025-10-24 17:52:16 +08:00
puxuan
97b91ec0d9 fix bug 2025-10-24 16:37:31 +08:00
puxuan
513ee323df fix bug 2025-10-24 14:37:15 +08:00
puxuan
6f3d42635e 资源整理 2025-10-24 12:02:08 +08:00
puxuan
265b5474e1 config 2025-10-24 11:40:12 +08:00
puxuan
b727316a77 背包 2025-10-24 11:05:09 +08:00
puxuan
598f288902 Merge branch 'dev_hero' into dev_hero_2 2025-10-24 09:54:54 +08:00
puxuan
31be75d787 ui 2025-10-24 09:54:31 +08:00
changyuxiang
a6d99ba19b 首充-火花姬 2025-10-23 21:31:00 +08:00
puxuan
5f867a9a84 冲刺 2025-10-23 20:09:26 +08:00
puxuan
a572fe571d fix bug 2025-10-23 18:21:29 +08:00
puxuan
d51954e25f fix bug 2025-10-23 18:11:39 +08:00
puxuan
1e99c284b0 资源整理 2025-10-23 18:10:58 +08:00
puxuan
46b11ccf9e 资源整理 2025-10-23 17:33:51 +08:00
puxuan
c40bb80cca . 2025-10-23 17:19:17 +08:00
puxuan
2dc4bdae98 res 2025-10-23 17:17:49 +08:00
puxuan
418dd48412 资源整理 2025-10-23 17:14:08 +08:00
puxuan
0e44ceaff7 资源整理 2025-10-23 16:10:53 +08:00
puxuan
f27864d87e 背包 2025-10-23 16:00:11 +08:00
puxuan
7dfed34849 特权 2025-10-23 11:31:30 +08:00
puxuan
5d5fd03238 商店 2025-10-22 20:51:21 +08:00
puxuan
9d1e561916 fix bug 2025-10-22 18:34:13 +08:00
puxuan
c26a8289be fix bug 2025-10-22 17:33:37 +08:00
puxuan
fc2bc97405 fix bug 2025-10-22 15:06:27 +08:00
puxuan
ab66a2dd52 fix bug 2025-10-22 11:59:47 +08:00
puxuan
6448443c0f 主界面 2025-10-22 11:46:57 +08:00
puxuan
049a754327 副本 2025-10-22 11:14:43 +08:00
puxuan
5d8bf297e8 res 2025-10-22 10:22:14 +08:00
puxuan
6b062362f2 fix bug 2025-10-22 10:14:27 +08:00
puxuan
965b98f0a8 fix bug 2025-10-22 09:30:00 +08:00
puxuan
2ed2daabf2 fix bug 2025-10-21 18:23:54 +08:00
puxuan
79d68e8caf 天赋动画 2025-10-21 16:07:49 +08:00
puxuan
7ecf780dab Merge branch 'dev_hero_2' into dev_hero
# Conflicts:
#	Assets/prefabs/effects/battle/sfx_c1_p35002_05.prefab
2025-10-21 10:30:18 +08:00
puxuan
7116c6a74a 基金 2025-10-21 10:28:57 +08:00
puxuan
79c7a15552 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-20 21:20:55 +08:00
puxuan
a91941b139 fix bug 2025-10-20 21:20:52 +08:00
tuxinyu
11a4631d28 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-20 21:10:48 +08:00
tuxinyu
7d761de229 1111111111111 2025-10-20 21:10:38 +08:00
puxuan
c9f22e7671 . 2025-10-20 20:54:34 +08:00
puxuan
8570d9dd2d .. 2025-10-20 20:53:21 +08:00
changyuxiang
b53e9b037e 1 2025-10-20 20:47:07 +08:00
tuxinyu
53bd3da968 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-20 20:45:09 +08:00
tuxinyu
8f20ac7cb0 111111111111 2025-10-20 20:45:01 +08:00
puxuan
7a4e927513 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-20 20:37:18 +08:00
puxuan
24901b3966 fix bug 2025-10-20 20:37:13 +08:00
tuxinyu
3943be89c5 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-20 20:31:53 +08:00
tuxinyu
ccd96db341 111111111 2025-10-20 20:31:44 +08:00
puxuan
9b7fe04959 res 2025-10-20 20:14:51 +08:00
puxuan
add4dcaa57 fix bug 2025-10-20 20:11:43 +08:00
puxuan
17510ca30c fix bug 2025-10-20 20:06:12 +08:00
puxuan
284aed53e3 七日签到 2025-10-20 19:25:02 +08:00
puxuan
b18bb603cc 特权 2025-10-20 17:20:02 +08:00
puxuan
44531ae9f9 倍速 2025-10-20 16:40:15 +08:00
puxuan
66157b5c7d 特权 2025-10-20 15:29:05 +08:00
puxuan
c09deb3f35 res 2025-10-20 14:47:37 +08:00
puxuan
9dae3eb965 buff 2025-10-20 14:06:23 +08:00
puxuan
55449888a4 config 2025-10-20 11:18:20 +08:00
puxuan
3d534e7523 广告 2025-10-20 11:10:29 +08:00
puxuan
56bbcacc2b Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-18 18:06:01 +08:00
puxuan
f4387fca51 fix bug 2025-10-18 18:05:57 +08:00
tuxinyu
fe31d8da1b 111111111 2025-10-18 17:59:53 +08:00
tuxinyu
4142eabe88 11111111111 2025-10-18 16:54:29 +08:00
tuxinyu
bc524cbb10 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-18 16:38:49 +08:00
tuxinyu
7eb00e61fa 11111111111 2025-10-18 16:38:41 +08:00
changyuxiang
1aa646ca37 优化技能落点位置 2025-10-18 16:27:33 +08:00
tuxinyu
6100bcc988 111111111111 2025-10-18 16:11:31 +08:00
tuxinyu
d5c3de2bcb Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-18 15:49:17 +08:00
tuxinyu
a3a918ec95 11111 2025-10-18 15:48:03 +08:00
changyuxiang
8803fe5ee4 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-18 15:47:40 +08:00
changyuxiang
fc43266090 1 2025-10-18 15:46:17 +08:00
tuxinyu
caf7e428b7 1111111 2025-10-18 15:08:51 +08:00
tuxinyu
230d4e21a6 11111111111 2025-10-18 15:04:16 +08:00
tuxinyu
bc16ece6d7 11111111 2025-10-18 15:02:36 +08:00
tuxinyu
974db01487 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-18 14:37:33 +08:00
tuxinyu
6c75f30ffe 111111111111 2025-10-18 14:37:22 +08:00
puxuan
29ded94b59 肉鸽 2025-10-18 10:53:57 +08:00
puxuan
b8b1b86fbb fix bug 2025-10-17 20:46:29 +08:00
puxuan
455e71bf7a fix bug 2025-10-17 20:37:51 +08:00
changyuxiang
ac16f8d0d2 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-17 20:27:58 +08:00
changyuxiang
120d0079ec 改事件帧 2025-10-17 20:27:28 +08:00
tuxinyu
e5f914814d 111111111 2025-10-17 20:25:15 +08:00
puxuan
2065c73a5c 特殊天赋 2025-10-17 16:13:58 +08:00
puxuan
c450235ffd 肉鸽 2025-10-17 12:18:03 +08:00
puxuan
a500c79107 Merge branch 'dev_hero_2' into dev_hero 2025-10-17 10:03:50 +08:00
puxuan
41af84e469 config 2025-10-17 10:03:12 +08:00
tuxinyu
7710ffac6b 1111111111 2025-10-16 21:39:19 +08:00
tuxinyu
70083216c3 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-16 21:32:02 +08:00
tuxinyu
fb15192cb0 111111111 2025-10-16 21:31:48 +08:00
puxuan
b845ca91b3 fix bug 2025-10-16 21:26:49 +08:00
puxuan
3427faf4bb Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-16 21:17:06 +08:00
puxuan
3ea8d17837 肉鸽 2025-10-16 21:17:02 +08:00
changyuxiang
0e41adbf6d Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-16 20:25:34 +08:00
changyuxiang
b4d109fbc7 1 2025-10-16 20:25:28 +08:00
tuxinyu
bc9bfbac0c 11111111111 2025-10-16 19:43:12 +08:00
tuxinyu
440c601b7b 111111 2025-10-16 19:37:57 +08:00
puxuan
1cda0abb3f fix bug 2025-10-16 10:03:18 +08:00
puxuan
2c4fe56d6c Merge branch 'dev_hero' into dev_hero_2 2025-10-16 09:48:55 +08:00
changyuxiang
e630c77bb0 1 2025-10-15 21:54:44 +08:00
changyuxiang
9f533f4da1 Merge branch 'dev_hero_2' of https://git.wdd817.link/puxuan/c1_unity into dev_hero_2 2025-10-15 21:34:25 +08:00
changyuxiang
328dd55733 1 2025-10-15 21:34:22 +08:00
puxuan
401b940473 fix bug 2025-10-15 21:19:46 +08:00
tuxinyu
2c9685502c Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-15 21:12:51 +08:00
tuxinyu
194e1cb608 1111111111 2025-10-15 21:12:35 +08:00
puxuan
55296e95da . 2025-10-15 20:43:00 +08:00
puxuan
1c96c3a82f fix bug 2025-10-15 20:39:32 +08:00
puxuan
6f4a85dd25 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-15 20:07:24 +08:00
puxuan
2ee6438cfc fix bug 2025-10-15 20:04:36 +08:00
tuxinyu
6da425e8c2 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-15 20:03:24 +08:00
tuxinyu
21b74b519c 11111 2025-10-15 20:03:06 +08:00
puxuan
b01520ead7 fix bug 2025-10-15 17:48:28 +08:00
puxuan
9202d9c83b Merge branch 'dev_hero' into dev_hero_2 2025-10-15 16:12:41 +08:00
puxuan
9a25a6dd90 召唤商店 2025-10-15 16:12:22 +08:00
changyuxiang
10b5e282f7 七天乐 2025-10-14 20:38:32 +08:00
kai
24c73e4b5f 天赋 2025-10-14 19:15:23 +08:00
kai
ec76fd9ad9 肉鸽技能图标 2025-10-14 15:53:49 +08:00
kai
f841ca153f 肉鸽技能直接带入 2025-10-14 15:38:38 +08:00
kai
dacb122526 fix bug 2025-10-14 11:13:42 +08:00
kai
454bdf3755 主界面图标 2025-10-14 10:19:48 +08:00
kai
85fa456381 Merge branch 'dev_hero' into dev_hero_2 2025-10-14 10:08:44 +08:00
changyuxiang
53d965aebc 成长基金 2025-10-13 21:36:19 +08:00
puxuan
29eddc6688 主界面图标 2025-10-13 21:15:31 +08:00
puxuan
7817465e42 Merge branch 'dev_hero' into dev_hero_2 2025-10-13 21:07:56 +08:00
puxuan
a6a7f6b75a 首充 2025-10-13 21:07:26 +08:00
changyuxiang
1387150aa7 在传两个图标 2025-10-13 20:55:38 +08:00
changyuxiang
bce3ff4452 一些活动入口图标 2025-10-13 20:15:20 +08:00
puxuan
ab5b4ce521 装备 2025-10-13 19:52:52 +08:00
puxuan
802e756db3 fix bug 2025-10-13 19:36:33 +08:00
puxuan
6d5a74b44c fix bug 2025-10-13 18:23:24 +08:00
puxuan
1f90462c46 fix bug 2025-10-13 14:53:13 +08:00
puxuan
f75e0fccf6 装备红点 2025-10-13 12:02:26 +08:00
puxuan
21b55ec9b6 . 2025-10-11 17:28:25 +08:00
puxuan
e7a00cd1e4 . 2025-10-11 16:46:34 +08:00
puxuan
1b10f1854f config 2025-10-11 15:57:58 +08:00
puxuan
3a0e919426 Merge branch 'dev_hero' into dev_hero_2 2025-10-11 15:52:27 +08:00
puxuan
c623b9f038 config 2025-10-11 15:52:08 +08:00
puxuan
d527822974 装备 2025-10-11 15:48:03 +08:00
changyuxiang
3a3ab128ab Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-10 21:07:06 +08:00
changyuxiang
dfd5a42748 挂机+抽奖入口图标+改英雄可升级动效 2025-10-10 21:05:19 +08:00
puxuan
077a4d0f14 副本 2025-10-10 19:46:33 +08:00
puxuan
e32c238a90 副本 2025-10-10 19:22:45 +08:00
puxuan
40bb3b0c0f Merge branch 'dev_hero' into dev_hero_2 2025-10-10 15:19:54 +08:00
puxuan
5935f650b8 . 2025-10-10 15:16:00 +08:00
puxuan
80db106cd1 Merge branch 'dev_act' into dev_hero 2025-10-10 15:15:22 +08:00
puxuan
c1e793fbe3 . 2025-10-10 15:14:29 +08:00
puxuan
39878f292c 英雄 2025-10-10 15:12:41 +08:00
changyuxiang
7b5d3c5836 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-09 21:38:39 +08:00
tuxinyu
f8e5991c68 1111111 2025-10-09 21:12:09 +08:00
tuxinyu
190d53f430 111111111 2025-10-09 20:50:08 +08:00
changyuxiang
9708208fd5 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-09 20:47:38 +08:00
changyuxiang
58bc0cc529 1 2025-10-09 20:47:23 +08:00
tuxinyu
961fbf6146 1111111 2025-10-09 20:42:30 +08:00
tuxinyu
2659d9950c 111111111111 2025-10-09 20:39:00 +08:00
puxuan
5bd296efe4 fix bug 2025-10-09 19:57:40 +08:00
puxuan
35e2a37420 升星 2025-10-09 19:56:22 +08:00
puxuan
f78071e910 升级 2025-10-09 17:48:18 +08:00
puxuan
a3771c610b 升级 2025-10-09 17:29:10 +08:00
puxuan
ddb9b12654 1 2025-10-09 17:03:34 +08:00
tuxinyu
49e7708675 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-08 21:41:18 +08:00
tuxinyu
2ac928f6a2 11111111 2025-10-08 21:40:57 +08:00
changyuxiang
8dfc52ced1 死灵法师改一下 2025-10-08 18:36:29 +08:00
puxuan
93065c8a00 Merge branch 'dev_act' into dev_hero_2 2025-10-08 18:20:22 +08:00
puxuan
d9cbbb3337 特权 2025-10-08 18:17:27 +08:00
changyuxiang
271308d569 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-08 17:55:46 +08:00
changyuxiang
572ea3e46e 英雄加影子 2025-10-08 17:55:42 +08:00
puxuan
c01bb6dd49 七天乐 2025-10-08 17:26:12 +08:00
tuxinyu
46b4b73cda 11111111 2025-10-08 17:01:57 +08:00
tuxinyu
92ff9e6393 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-08 16:56:02 +08:00
tuxinyu
1a89a7e49a 11111111 2025-10-08 16:54:57 +08:00
puxuan
743d0f097b 特权 2025-10-08 16:03:28 +08:00
changyuxiang
033bdbf11f 狼加影子,改抽奖UI动效 2025-10-08 15:23:15 +08:00
changyuxiang
e0d20294fe 1 2025-10-08 14:27:29 +08:00
changyuxiang
d6ea584023 改45001技能 2025-10-08 14:25:10 +08:00
changyuxiang
d161fac759 补充一个,改点东西 2025-10-08 14:07:54 +08:00
puxuan
b95a8b1378 hero 2025-10-08 10:55:47 +08:00
changyuxiang
f04c3f44e9 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-10-07 20:09:03 +08:00
changyuxiang
007dbf7d4f 改几个动作 2025-10-07 20:08:47 +08:00
puxuan
ddcb2c72f0 新加任务 2025-10-07 20:00:23 +08:00
puxuan
4fc4b6b23e lua 2025-10-07 18:32:30 +08:00
puxuan
4aa2e6f2a7 Merge branch 'dev_hero' into dev_act
# Conflicts:
#	Assets/lua/app/config/buff.lua.bytes
#	Assets/lua/app/config/fx.lua.bytes
#	Assets/lua/app/config/skill.lua.bytes
#	Assets/lua/app/config/strings/cn/attr.lua.bytes
#	Assets/lua/app/config/strings/cn/task_type.lua.bytes
#	Assets/lua/app/config/strings/de/attr.lua.bytes
#	Assets/lua/app/config/strings/en/attr.lua.bytes
#	Assets/lua/app/config/strings/en/task_type.lua.bytes
#	Assets/lua/app/config/strings/es/attr.lua.bytes
#	Assets/lua/app/config/strings/es/task_type.lua.bytes
#	Assets/lua/app/config/strings/fr/attr.lua.bytes
#	Assets/lua/app/config/strings/id/attr.lua.bytes
#	Assets/lua/app/config/strings/id/task_type.lua.bytes
#	Assets/lua/app/config/strings/ja/attr.lua.bytes
#	Assets/lua/app/config/strings/ja/task_type.lua.bytes
#	Assets/lua/app/config/strings/ko/attr.lua.bytes
#	Assets/lua/app/config/strings/ko/task_type.lua.bytes
#	Assets/lua/app/config/strings/pt/attr.lua.bytes
#	Assets/lua/app/config/strings/pt/task_type.lua.bytes
#	Assets/lua/app/config/strings/ru/attr.lua.bytes
#	Assets/lua/app/config/strings/th/attr.lua.bytes
#	Assets/lua/app/config/strings/th/task_type.lua.bytes
#	Assets/lua/app/config/strings/vi/attr.lua.bytes
#	Assets/lua/app/config/strings/vi/task_type.lua.bytes
#	Assets/lua/app/config/strings/zh/attr.lua.bytes
#	Assets/lua/app/config/strings/zh/task_type.lua.bytes
2025-10-07 18:30:51 +08:00
puxuan
7b6ede56cc 2025-10-07 18:30:02 +08:00
puxuan
614909a19f 每日挑战 2025-10-07 18:28:34 +08:00
puxuan
8060568ced 签到 2025-10-07 17:19:46 +08:00
changyuxiang
cd4622580a 改俩动画 2025-10-07 17:10:38 +08:00
puxuan
9c290fa178 活动 2025-10-07 11:21:54 +08:00
tuxinyu
5f4f6087d2 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-30 19:25:37 +08:00
tuxinyu
9858563402 111111 2025-09-30 19:25:26 +08:00
puxuan
479c5976ec Merge branch 'dev_hero' into dev_act 2025-09-30 09:32:23 +08:00
changyuxiang
603a25ed57 改怪 2025-09-29 21:34:01 +08:00
puxuan
6fc419c7ce . 2025-09-29 21:17:42 +08:00
puxuan
c819d7ce8a 礼包 2025-09-29 21:10:50 +08:00
puxuan
7b4916851e 基金 2025-09-29 19:53:13 +08:00
puxuan
2a6bdfd66e Merge branch 'dev_hero' into dev_act 2025-09-29 17:38:08 +08:00
puxuan
23ac799d02 召唤 2025-09-29 17:33:25 +08:00
puxuan
e911269404 活动 2025-09-29 17:03:14 +08:00
puxuan
e57618f534 冲刺 2025-09-29 16:27:54 +08:00
puxuan
d8249cc3ac 冲刺 2025-09-29 15:37:57 +08:00
changyuxiang
bb804e059a 抽奖 2025-09-28 21:27:28 +08:00
puxuan
778505742a lua 2025-09-28 20:37:41 +08:00
puxuan
c3ce4f0615 Merge branch 'dev_hero' into dev_act 2025-09-28 20:36:36 +08:00
changyuxiang
c1e72278f0 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-28 20:30:54 +08:00
changyuxiang
a1b4dbb1b4 1 2025-09-28 20:30:46 +08:00
changyuxiang
b5981bae15 改个怪物 2025-09-28 20:18:55 +08:00
puxuan
f93e31fb95 活动 2025-09-28 20:05:55 +08:00
tuxinyu
20d555500d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-28 19:47:01 +08:00
tuxinyu
58b59379d9 11111111 2025-09-28 19:46:52 +08:00
puxuan
dc4c1fc49e 活动 2025-09-28 16:11:00 +08:00
puxuan
e10aa91ae9 冲刺活动 2025-09-28 14:43:19 +08:00
puxuan
6a5c903e48 fix bug 2025-09-26 16:48:34 +08:00
puxuan
4369ed4075 config 2025-09-26 15:42:14 +08:00
puxuan
d906155c9c Merge branch 'dev_hero' into dev_act 2025-09-26 09:45:03 +08:00
puxuan
0ac2b10096 活动 2025-09-26 09:44:45 +08:00
changyuxiang
d2005a212d 改两个小怪 2025-09-25 21:47:33 +08:00
puxuan
e91c3d797d 冲刺活动 2025-09-25 20:13:36 +08:00
changyuxiang
eddc613d25 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-25 20:07:58 +08:00
changyuxiang
fd05b716a9 改一下通用获得动效 2025-09-25 20:07:54 +08:00
tuxinyu
cdce72b7a2 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-25 19:35:08 +08:00
changyuxiang
9e5acb67ed 1 2025-09-25 19:31:19 +08:00
tuxinyu
425ea3ec56 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-25 19:29:23 +08:00
tuxinyu
e3fc446960 1111111111 2025-09-25 19:29:07 +08:00
puxuan
38345d5909 Merge branch 'dev_hero' into dev_act 2025-09-25 16:41:07 +08:00
puxuan
776b6ae29f 结算界面 2025-09-25 16:40:26 +08:00
puxuan
1c5b577038 活动 2025-09-25 16:05:10 +08:00
puxuan
18296991a2 商业化 2025-09-25 11:41:03 +08:00
changyuxiang
955d7cca3f Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-24 21:30:40 +08:00
changyuxiang
4c7e7aaf78 改点东西 2025-09-24 21:30:32 +08:00
tuxinyu
d3e870351b 11111111 2025-09-24 21:14:35 +08:00
tuxinyu
cfed0a625f 111111111 2025-09-24 20:49:02 +08:00
changyuxiang
6f7a26f595 改俩英雄 2025-09-24 20:27:21 +08:00
tuxinyu
365ae2a618 11111111111 2025-09-24 19:44:36 +08:00
tuxinyu
d2ac016e74 11111111111 2025-09-24 19:39:24 +08:00
puxuan
08d3ed2d7e 商店 2025-09-24 16:23:21 +08:00
puxuan
8ae9b1c288 2025-09-24 12:04:04 +08:00
puxuan
87b4c11a9c 阵容 2025-09-24 12:03:05 +08:00
puxuan
aa3cd49667 Merge branch 'dev_hero' into dev_equip
# Conflicts:
#	Assets/lua/app/ui/hero/hero_comp.lua.bytes
2025-09-24 11:06:41 +08:00
changyuxiang
060dcda776 1 2025-09-23 21:36:24 +08:00
changyuxiang
72123ff72e Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-23 21:23:27 +08:00
changyuxiang
ad6cc54cfa 1 2025-09-23 21:23:24 +08:00
tuxinyu
a7d661556a 1111111 2025-09-23 21:22:43 +08:00
changyuxiang
6423f40b58 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-23 21:11:27 +08:00
changyuxiang
6d5086d5e6 1 2025-09-23 21:11:22 +08:00
puxuan
be9a8be241 fix bug 2025-09-23 21:10:20 +08:00
puxuan
aa2648ce08 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-23 20:58:33 +08:00
puxuan
dee92b0594 fix bug 2025-09-23 20:58:26 +08:00
changyuxiang
65574eecaa Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-23 20:57:20 +08:00
changyuxiang
db1f0229db 改点东西 2025-09-23 20:57:17 +08:00
tuxinyu
b527d23e44 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-23 20:51:49 +08:00
tuxinyu
25d14cf9c2 1111111111 2025-09-23 20:51:42 +08:00
puxuan
689e1a7ef3 fix bug 2025-09-23 20:48:50 +08:00
tuxinyu
7edaf6ccc0 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-23 20:35:52 +08:00
tuxinyu
9cef0fd55f 111111111 2025-09-23 20:35:42 +08:00
puxuan
fb6c741cc1 fix bug 2025-09-23 20:17:07 +08:00
puxuan
a831629459 敌方属性计算 2025-09-23 20:00:40 +08:00
puxuan
5200466331 Merge branch 'dev_hero' into dev_equip 2025-09-23 16:22:02 +08:00
puxuan
34518800c4 fix bug 2025-09-22 17:38:01 +08:00
puxuan
c4b592025d fix bug 2025-09-22 16:09:04 +08:00
puxuan
2278d90172 . 2025-09-22 15:21:55 +08:00
puxuan
5ef5298243 主界面英雄 2025-09-22 14:57:14 +08:00
puxuan
989d1601eb 引导坐标 2025-09-22 12:00:41 +08:00
puxuan
0c1b99ad82 fix bug 2025-09-22 11:33:05 +08:00
puxuan
026fbcc5c4 fix bug 2025-09-22 10:19:13 +08:00
puxuan
ac5b0c44fa Merge branch 'dev_hero' into dev_equip 2025-09-19 15:02:35 +08:00
puxuan
545a879fa3 config 2025-09-19 15:02:17 +08:00
puxuan
5f1b5b34bd fix bug 2025-09-19 14:56:10 +08:00
puxuan
e7e0bde881 Merge branch 'dev_hero' into dev_equip
# Conflicts:
#	Assets/lua/app/common/data_manager.lua.bytes
#	Assets/lua/app/global/global_const.lua.bytes
2025-09-19 14:52:24 +08:00
puxuan
e36dd5e583 新增肉鸽类型 2025-09-19 14:50:04 +08:00
puxuan
21b5b2b20a 属性 2025-09-18 17:52:48 +08:00
tuxinyu
2647f6925d 11111111 2025-09-17 19:52:54 +08:00
tuxinyu
aa340aae4f 1111111111 2025-09-17 19:35:38 +08:00
puxuan
83f941496d 装备 2025-09-17 17:24:03 +08:00
tuxinyu
3598a27b56 111111111111 2025-09-16 21:10:43 +08:00
tuxinyu
691bd7cccb 11111111 2025-09-16 21:06:32 +08:00
tuxinyu
e0e35ed993 11111111 2025-09-16 21:01:27 +08:00
tuxinyu
0301b00a7d 1111111111 2025-09-16 20:43:24 +08:00
tuxinyu
a8fc5ea363 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-16 20:10:03 +08:00
tuxinyu
08cc62b173 111111 2025-09-16 20:09:56 +08:00
puxuan
1c080a08b2 config 2025-09-16 20:08:47 +08:00
tuxinyu
73230eef02 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-16 19:53:17 +08:00
tuxinyu
00845e9738 111111 2025-09-16 19:53:10 +08:00
puxuan
c06f88f8dc Merge branch 'dev_hero' into dev_equip
# Conflicts:
#	Assets/lua/app/config/localization/localization_global_const.lua.bytes
#	Assets/lua/app/config/skill.lua.bytes
#	Assets/lua/app/config/strings/cn/global.lua.bytes
#	Assets/lua/app/global/global_const.lua.bytes
#	Assets/lua/app/proto/proto_msg_type.lua.bytes
#	Assets/lua/app/ui/hero/hero_detail_ui.lua.bytes
#	Assets/prefabs/ui/hero/hero_detail_ui.prefab
#	Assets/proto/protocol.bytes
2025-09-16 16:12:56 +08:00
puxuan
fb20918bc6 . 2025-09-16 16:11:51 +08:00
puxuan
50a42a6219 config 2025-09-16 16:08:15 +08:00
puxuan
4af4b48bca fix bug 2025-09-16 15:28:04 +08:00
tuxinyu
603f289cb9 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-15 20:33:35 +08:00
tuxinyu
85906420c5 111111 2025-09-15 20:33:25 +08:00
puxuan
447a5364dc 抽卡 2025-09-15 20:32:12 +08:00
tuxinyu
b65a6adc2d 111111111 2025-09-15 20:22:54 +08:00
tuxinyu
5f9e2bf603 111111111 2025-09-15 20:21:53 +08:00
tuxinyu
4a8cd3fb1c 11111111111 2025-09-15 20:09:50 +08:00
tuxinyu
35e73dfc1a Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-15 20:03:59 +08:00
tuxinyu
3d26181207 1111111111 2025-09-15 20:03:53 +08:00
puxuan
c8d0e2b3c5 fix bug 2025-09-15 20:01:46 +08:00
tuxinyu
5873842dae 11111111 2025-09-15 19:48:06 +08:00
tuxinyu
7a4cbe79d8 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-15 19:38:09 +08:00
tuxinyu
31ae34260e 11111111111 2025-09-15 19:38:01 +08:00
puxuan
63ad8832a9 每日挑战 2025-09-15 17:20:59 +08:00
changyuxiang
2751a48575 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-15 12:46:42 +08:00
changyuxiang
f03d3de706 1 2025-09-15 12:46:33 +08:00
tuxinyu
18096ad14d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-15 12:39:56 +08:00
tuxinyu
88cee05344 1111111 2025-09-15 12:39:48 +08:00
changyuxiang
6d52fa22c1 1 2025-09-15 12:37:31 +08:00
changyuxiang
6f0d6c4eba 1 2025-09-15 12:36:45 +08:00
puxuan
4de0784535 fix bug 2025-09-15 11:41:49 +08:00
puxuan
f981f0b664 fix bug 2025-09-15 10:54:29 +08:00
puxuan
44326ddfa0 动画 2025-09-15 10:10:03 +08:00
changyuxiang
8d621fabe4 新英雄获得 2025-09-12 21:05:38 +08:00
changyuxiang
ec09ae2a0f 战力提升 2025-09-12 20:16:07 +08:00
tuxinyu
5f766555a7 1111111 2025-09-12 17:31:24 +08:00
tuxinyu
303fb3fef2 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-12 17:19:32 +08:00
tuxinyu
f250b2c03f 111111111 2025-09-12 17:19:25 +08:00
puxuan
ab71cd250c . 2025-09-12 16:34:27 +08:00
puxuan
06261d6465 . 2025-09-12 16:30:28 +08:00
puxuan
b492e287e4 config 2025-09-12 16:28:15 +08:00
puxuan
b1b42d5258 . 2025-09-12 15:28:08 +08:00
puxuan
dbd220fcfc 2025-09-12 15:24:11 +08:00
puxuan
04ecb7b08c 2025-09-12 15:17:41 +08:00
puxuan
1fc0cbe7b1 抽卡 2025-09-12 15:12:39 +08:00
puxuan
974e8d2337 fix bug 2025-09-12 10:25:24 +08:00
puxuan
03cf4e1843 装备 2025-09-12 09:50:57 +08:00
changyuxiang
d65af7f268 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-11 21:33:56 +08:00
changyuxiang
dbdaff5f3c 25001 2025-09-11 21:33:31 +08:00
tuxinyu
2483e8bdd4 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-11 20:35:42 +08:00
tuxinyu
049d79f8dc 111111111 2025-09-11 20:35:31 +08:00
puxuan
dcc9d416c5 装备 2025-09-09 21:11:16 +08:00
puxuan
b9b7cc1c74 Merge branch 'dev_hero' into dev_equip 2025-09-09 20:15:01 +08:00
puxuan
ceb9317d64 box 2025-09-09 20:13:47 +08:00
puxuan
2089171f80 config 2025-09-09 20:03:02 +08:00
puxuan
7adbf9e3c4 res 2025-09-09 19:42:49 +08:00
puxuan
f4f0111fa9 装备 2025-09-09 19:40:07 +08:00
puxuan
72ba48e7d1 战斗力 2025-09-09 19:25:18 +08:00
puxuan
562be8071c fix bug 2025-09-08 20:10:07 +08:00
puxuan
15f7e7eaf0 背包 2025-09-08 20:02:09 +08:00
puxuan
f11022dc96 背包 2025-09-08 17:36:27 +08:00
puxuan
9627e10463 skill 2025-09-08 15:49:20 +08:00
puxuan
13e846a688 fix bug 2025-09-08 14:31:58 +08:00
changyuxiang
af88eb3db9 1 2025-09-05 22:38:23 +08:00
changyuxiang
8fb94acaa6 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-05 20:48:02 +08:00
changyuxiang
797d32155c 1 2025-09-05 20:47:58 +08:00
puxuan
51a75c0906 config 2025-09-05 16:50:19 +08:00
puxuan
eaee735bff 2025-09-05 16:43:04 +08:00
puxuan
5ab0b5f1ab 公司 2025-09-05 16:42:05 +08:00
puxuan
991d7f52bb fix bug 2025-09-05 15:40:40 +08:00
puxuan
defa53883f boss技能 2025-09-05 15:04:36 +08:00
puxuan
ee14aded6a fix bug 2025-09-05 14:28:41 +08:00
puxuan
558cfdf2d8 功能开启 2025-09-05 10:50:01 +08:00
changyuxiang
9ae7ab2790 1 2025-09-05 10:01:05 +08:00
puxuan
78af86e37e Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-04 20:08:15 +08:00
puxuan
986d295fbe fix bug 2025-09-04 20:08:09 +08:00
changyuxiang
bb92d5a24e 1 2025-09-04 19:56:57 +08:00
changyuxiang
42a58102c4 替换 2025-09-04 19:51:03 +08:00
changyuxiang
7bec44980b p35002 2025-09-04 19:32:31 +08:00
puxuan
64351e1f6b fix bug 2025-09-04 18:33:13 +08:00
puxuan
9ebcf06b5a boss技能弹窗 2025-09-04 18:20:30 +08:00
puxuan
6262219db6 震动 2025-09-04 17:35:45 +08:00
puxuan
40a48df785 fix bug 2025-09-04 17:03:33 +08:00
puxuan
c10d5817a0 config 2025-09-04 16:28:33 +08:00
puxuan
a6dbfc3fa9 fix bug 2025-09-04 16:22:50 +08:00
puxuan
9ddc8a6c1b config 2025-09-04 09:41:13 +08:00
changyuxiang
646cb07192 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-03 21:03:52 +08:00
changyuxiang
beb9547565 1 2025-09-03 21:03:43 +08:00
puxuan
f2717b72e9 fix bug 2025-09-03 20:43:22 +08:00
changyuxiang
e8842259b6 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-03 20:20:25 +08:00
changyuxiang
311c587ddd 箭头 2025-09-03 20:20:19 +08:00
puxuan
6b828c55c0 fix bug 2025-09-03 19:58:45 +08:00
puxuan
ca872ddab7 fix bug 2025-09-03 18:36:02 +08:00
puxuan
80edb5a22f fix bug 2025-09-03 16:51:55 +08:00
puxuan
8f06da008b Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-03 16:43:48 +08:00
puxuan
b146f13e91 fix bug 2025-09-03 16:43:45 +08:00
tuxinyu
7db1817bf3 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-03 15:49:32 +08:00
tuxinyu
6bf327ccb7 562588 2025-09-03 15:49:13 +08:00
puxuan
71f4564255 . 2025-09-02 20:49:34 +08:00
puxuan
3a6e7f9a7c Merge remote-tracking branch 'origin/dev_hero' into dev_android 2025-09-02 20:47:05 +08:00
puxuan
fcb5091001 特效 2025-09-02 20:45:18 +08:00
tuxinyu
aac1a5d5ad 11111 2025-09-02 20:42:18 +08:00
tuxinyu
d3c630ec8e 1111111 2025-09-02 20:39:37 +08:00
tuxinyu
fb70f96ed3 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-02 19:36:42 +08:00
tuxinyu
7a4a8b8f8c 111111 2025-09-02 19:36:31 +08:00
puxuan
be828e96cf lua 2025-09-02 17:31:15 +08:00
puxuan
77fc58e672 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-02 17:30:41 +08:00
puxuan
104a6d1bf5 场景 2025-09-02 17:30:35 +08:00
puxuan
748d55bab5 . 2025-09-02 17:29:17 +08:00
changyuxiang
dd09e4228b 1 2025-09-01 21:29:20 +08:00
tuxinyu
8515c13f92 111111 2025-09-01 20:45:41 +08:00
tuxinyu
efc5900332 111 2025-09-01 20:34:23 +08:00
tuxinyu
9a880a3cce 11111111 2025-09-01 20:33:16 +08:00
tuxinyu
22d3603f19 11111111111 2025-09-01 20:14:58 +08:00
puxuan
448becfe4b . 2025-09-01 19:59:18 +08:00
tuxinyu
c01ed07ef7 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-01 19:44:55 +08:00
tuxinyu
3d3d774273 11111111 2025-09-01 19:44:47 +08:00
puxuan
5c7be3141e res 2025-09-01 19:39:14 +08:00
puxuan
8a50d3a5a1 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-01 19:35:01 +08:00
puxuan
a525866905 建筑 2025-09-01 19:34:53 +08:00
tuxinyu
b2a21397d8 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-01 19:26:42 +08:00
tuxinyu
d05efd7327 11111111 2025-09-01 19:26:33 +08:00
puxuan
45835b8706 Merge branch 'dev_hero' into dev_android 2025-09-01 16:56:29 +08:00
puxuan
2ccda92192 .. 2025-09-01 15:05:58 +08:00
puxuan
110bc8ba88 2025-09-01 15:00:38 +08:00
changyuxiang
e9244a90d1 1 2025-09-01 12:30:30 +08:00
tuxinyu
a25afdb9dd Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-09-01 12:13:01 +08:00
tuxinyu
4bfc954ae4 111111 2025-09-01 12:12:06 +08:00
puxuan
953112ed88 Merge branch 'dev_hero' into dev_android 2025-09-01 11:39:06 +08:00
puxuan
43a4a54ea6 广告 2025-09-01 11:28:45 +08:00
puxuan
4fd0f4a6d0 屏蔽上报 2025-09-01 11:25:36 +08:00
puxuan
418d5780bf 场景5 2025-09-01 10:30:25 +08:00
puxuan
2df5ba26fd config 2025-09-01 09:44:54 +08:00
puxuan
98cc05b3cc fix bug 2025-08-29 17:23:14 +08:00
puxuan
65e9cee902 卡牌召唤 2025-08-29 16:21:17 +08:00
puxuan
008fc9eddf 技能弹窗 2025-08-29 14:40:01 +08:00
puxuan
49f697de6e 技能描述 2025-08-29 14:25:56 +08:00
puxuan
ef470b60db 场景3 4 2025-08-29 11:58:09 +08:00
puxuan
079c1b21f6 挂机 2025-08-28 20:57:42 +08:00
puxuan
6488cf581a fix bug 2025-08-28 20:52:01 +08:00
puxuan
10e8dbb255 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 20:30:29 +08:00
puxuan
cd70a96e95 天赋 2025-08-28 20:30:25 +08:00
changyuxiang
7a4275a1c9 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 20:26:22 +08:00
changyuxiang
f154548f34 场景4 2025-08-28 20:26:15 +08:00
tuxinyu
4cf4604a70 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 20:04:15 +08:00
tuxinyu
fc9122f77f 111111 2025-08-28 20:04:05 +08:00
changyuxiang
d193c93fd0 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 20:00:06 +08:00
changyuxiang
0e339930f0 1 2025-08-28 20:00:00 +08:00
puxuan
4fbafb72c8 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 19:52:38 +08:00
puxuan
8cb98ac1c9 fix bug 2025-08-28 19:52:35 +08:00
tuxinyu
07e5f3b31f Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 19:43:46 +08:00
tuxinyu
d46cea8ec3 1111 2025-08-28 19:43:38 +08:00
puxuan
287f858230 连击 2025-08-28 17:42:10 +08:00
puxuan
fa1198dd00 连击 2025-08-28 17:40:06 +08:00
puxuan
e9244b18c4 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-28 16:37:18 +08:00
puxuan
bbcb866671 fix bug 2025-08-28 16:37:15 +08:00
changyuxiang
7998dee76a 1 2025-08-28 14:46:21 +08:00
puxuan
028fc1d88a . 2025-08-28 11:44:40 +08:00
puxuan
2301851088 res 2025-08-28 11:17:09 +08:00
puxuan
513dd9b5fc 场景2 2025-08-28 11:15:11 +08:00
puxuan
db721dbb53 fix bug 2025-08-28 10:38:47 +08:00
puxuan
d99175f807 res 2025-08-28 10:17:43 +08:00
tuxinyu
ab5df0906d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 21:48:57 +08:00
tuxinyu
dbe73675a8 1111111 2025-08-27 21:48:25 +08:00
puxuan
4b6d350215 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 21:44:56 +08:00
puxuan
67ffcb9c1b fix bug 2025-08-27 21:44:53 +08:00
tuxinyu
3fb8fa1c0e Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 21:44:34 +08:00
changyuxiang
458e466262 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 21:33:44 +08:00
tuxinyu
3522b65858 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 21:33:20 +08:00
changyuxiang
5ed50c0ede 场景3 2025-08-27 21:33:19 +08:00
tuxinyu
1f1356d913 11111 2025-08-27 21:33:07 +08:00
puxuan
5087a05afa 天赋信息界面 2025-08-27 21:29:19 +08:00
puxuan
a01bf53f0a Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 20:54:54 +08:00
puxuan
c36dec1a7b fix bug 2025-08-27 20:54:49 +08:00
tuxinyu
84dca0cd71 1111111 2025-08-27 20:46:52 +08:00
tuxinyu
12211838ce 1111111 2025-08-27 20:37:30 +08:00
tuxinyu
eadaf188dd Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 20:35:49 +08:00
tuxinyu
7989086ebe 11111111 2025-08-27 20:35:35 +08:00
puxuan
515bd7e066 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 20:35:15 +08:00
puxuan
862a3f0177 还原boss 2025-08-27 20:35:09 +08:00
puxuan
db6852ca01 res 2025-08-27 20:30:36 +08:00
tuxinyu
a0dfd94a24 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 20:19:38 +08:00
tuxinyu
65ae28e715 111111111 2025-08-27 20:19:27 +08:00
changyuxiang
e64cabe516 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 20:16:19 +08:00
changyuxiang
caee46ed04 1 2025-08-27 20:16:10 +08:00
tuxinyu
c367168605 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 20:05:19 +08:00
tuxinyu
d76f57d2ec 1111111 2025-08-27 20:05:08 +08:00
changyuxiang
0edf4d4b74 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 19:49:02 +08:00
changyuxiang
be2057beb3 1 2025-08-27 19:47:25 +08:00
tuxinyu
dca5ec2391 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 19:45:35 +08:00
tuxinyu
8abaf2d846 11111111 2025-08-27 19:45:22 +08:00
changyuxiang
74caaa5a88 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 19:43:00 +08:00
changyuxiang
f9d0b87676 场景2动画 2025-08-27 19:42:46 +08:00
puxuan
12c52903aa Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 19:37:41 +08:00
puxuan
8fdadba962 fix bug 2025-08-27 19:37:20 +08:00
tuxinyu
d392473c6e Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 19:31:43 +08:00
tuxinyu
c9bb11ed29 111111 2025-08-27 19:31:28 +08:00
puxuan
b70249c249 fix bug 2025-08-27 19:27:18 +08:00
puxuan
504e40eb38 res 2025-08-27 19:07:24 +08:00
puxuan
945a1ce922 fix bug 2025-08-27 18:57:27 +08:00
puxuan
e4fe7b0726 res 2025-08-27 16:33:11 +08:00
puxuan
a9c7c04316 fix bug 2025-08-27 16:24:09 +08:00
puxuan
29317b4ea4 fix bug 2025-08-27 16:09:59 +08:00
puxuan
e07da910b5 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 14:22:41 +08:00
puxuan
06addac953 fix bug 2025-08-27 14:22:36 +08:00
tuxinyu
d70dec2f19 呃呃呃呃 2025-08-27 10:20:33 +08:00
tuxinyu
310e5f4c79 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-27 10:15:35 +08:00
tuxinyu
9185bd21ce 1111111 2025-08-27 10:15:06 +08:00
puxuan
adaca35ac5 config 2025-08-27 09:46:04 +08:00
changyuxiang
fe9c082c38 快递天使 2025-08-26 21:15:05 +08:00
tuxinyu
4477a52fab Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-26 19:21:23 +08:00
tuxinyu
403001b3ab 1111111 2025-08-26 19:21:03 +08:00
changyuxiang
41be97bb08 1 2025-08-25 20:20:00 +08:00
tuxinyu
1de8644056 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-25 19:30:32 +08:00
tuxinyu
5d9f65f6d0 1111111111 2025-08-25 19:30:17 +08:00
puxuan
1a31862d94 头像 2025-08-22 17:59:17 +08:00
puxuan
a4fdfb1dde 头像 2025-08-22 17:50:07 +08:00
puxuan
3c915c8d73 fix bug 2025-08-22 17:04:00 +08:00
puxuan
e041781019 fix bug 2025-08-22 15:47:26 +08:00
puxuan
6c1aa4263b fix bug 2025-08-22 15:28:02 +08:00
puxuan
d9e7c928f6 config 2025-08-22 14:57:07 +08:00
puxuan
b59fd66886 fix bug 2025-08-22 14:35:07 +08:00
puxuan
6ad37f7cc0 fix bug 2025-08-22 10:56:15 +08:00
puxuan
1dfc90943f talent 2025-08-21 21:44:32 +08:00
puxuan
d30e9e502f fix bug 2025-08-21 21:06:54 +08:00
changyuxiang
1b06feed2c Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-21 19:54:58 +08:00
changyuxiang
d57ef8ace6 1 2025-08-21 19:54:37 +08:00
puxuan
c737e2cd89 config 2025-08-21 19:36:26 +08:00
puxuan
a5d135a78a fix bug 2025-08-21 18:26:13 +08:00
puxuan
f764b389d5 vs 2025-08-21 17:56:15 +08:00
puxuan
e360bb7662 英雄 2025-08-21 17:45:53 +08:00
puxuan
2daa1d6006 idle 2025-08-21 16:23:50 +08:00
puxuan
6f86255585 成就 2025-08-21 16:01:34 +08:00
puxuan
3d7c916058 idle 2025-08-21 14:42:52 +08:00
puxuan
f5a3400308 fix bug 2025-08-21 11:35:08 +08:00
puxuan
2242ca17dd talent 2025-08-21 10:09:51 +08:00
tuxinyu
df8aef2f45 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-20 21:46:14 +08:00
tuxinyu
5684447b6a 11111111 2025-08-20 21:45:25 +08:00
changyuxiang
aba89f58fc 1 2025-08-20 21:24:01 +08:00
changyuxiang
fabe2a6b3d 匹配成功动效 2025-08-20 21:00:44 +08:00
changyuxiang
b7e9c5c3d7 1 2025-08-20 20:18:32 +08:00
changyuxiang
584489c613 1 2025-08-20 19:59:35 +08:00
puxuan
b506620e47 fix bug 2025-08-20 17:44:40 +08:00
puxuan
b9bd81f802 arena 2025-08-20 16:12:27 +08:00
puxuan
ecd5958b55 fix bug 2025-08-20 15:57:02 +08:00
puxuan
5fbf156762 英雄 2025-08-20 11:43:19 +08:00
puxuan
07adc9afd3 config 2025-08-19 21:18:35 +08:00
puxuan
52e9a63ab3 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-19 21:14:20 +08:00
puxuan
8c228bfc90 英雄 2025-08-19 21:14:17 +08:00
changyuxiang
d8386149e7 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-19 20:44:22 +08:00
changyuxiang
925a6cb8eb 1 2025-08-19 20:44:16 +08:00
puxuan
9bfbada234 fix bug 2025-08-19 20:33:25 +08:00
puxuan
457b3b23a8 fix bug 2025-08-19 17:32:44 +08:00
puxuan
c301840cb2 场景 2025-08-19 17:14:23 +08:00
puxuan
edfbd9ec35 fix bug 2025-08-19 15:11:57 +08:00
puxuan
679ae0de42 任务跳转 2025-08-19 14:31:44 +08:00
puxuan
1f414ccc84 fix bug 2025-08-19 10:38:58 +08:00
puxuan
9dd813c593 fix bug 2025-08-18 20:50:24 +08:00
puxuan
c79625c019 英雄技能 2025-08-18 18:13:35 +08:00
puxuan
25ca47f63b fix bug 2025-08-18 11:59:36 +08:00
puxuan
14c28c83bf fix bug 2025-08-18 11:49:07 +08:00
puxuan
9a4dd35b5b Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-18 10:43:00 +08:00
puxuan
6794741f34 主界面 2025-08-18 10:42:57 +08:00
changyuxiang
67d82fdb65 调大小 2025-08-15 21:40:26 +08:00
changyuxiang
ac6a61b6af 1 2025-08-15 21:11:53 +08:00
changyuxiang
4a7df9f57f p44001海的女儿 2025-08-15 20:51:27 +08:00
puxuan
42d074f1cb . 2025-08-15 20:24:05 +08:00
puxuan
c74953aabc 。。 2025-08-15 20:17:28 +08:00
puxuan
5654eb7445 .. 2025-08-15 20:12:27 +08:00
tuxinyu
f1f3c2ba6b 11111111 2025-08-15 19:53:54 +08:00
tuxinyu
d601930533 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-15 19:51:30 +08:00
tuxinyu
673739b538 111111111 2025-08-15 19:51:15 +08:00
puxuan
f3708369a7 chapter2 2025-08-15 18:22:52 +08:00
puxuan
40ae361190 局内 2025-08-15 17:34:34 +08:00
tuxinyu
b2a31dc888 d8d8e 2025-08-15 15:56:46 +08:00
tuxinyu
e2df1b56e0 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-15 15:39:39 +08:00
tuxinyu
be813055c8 guugg 2025-08-15 15:39:21 +08:00
puxuan
cf8b1aa7a8 res 2025-08-15 15:00:48 +08:00
puxuan
cb9acdb86b res 2025-08-15 14:28:17 +08:00
puxuan
46044a175b skill 2025-08-15 11:38:32 +08:00
puxuan
7d0ea33c71 config 2025-08-15 11:16:40 +08:00
puxuan
8d852e11c3 lua 2025-08-15 11:08:40 +08:00
puxuan
6194090eb3 res 2025-08-15 10:40:19 +08:00
changyuxiang
c838e603e6 1 2025-08-14 20:51:56 +08:00
tuxinyu
03e7a5368e Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-14 20:50:30 +08:00
tuxinyu
a666ac3417 1111111 2025-08-14 20:50:19 +08:00
changyuxiang
3a26dc2dd2 平底锅战神p24001 2025-08-14 20:20:19 +08:00
tuxinyu
294bf0121b Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-14 19:40:11 +08:00
tuxinyu
ce94619813 11111111 2025-08-14 19:40:03 +08:00
puxuan
e61171acc8 res 2025-08-14 18:19:14 +08:00
puxuan
698cf0922f 每日挑战任务 2025-08-14 18:05:58 +08:00
puxuan
840672e242 config 2025-08-14 16:03:59 +08:00
puxuan
8f629e1ac0 红点 2025-08-14 16:01:21 +08:00
puxuan
f1cc76dc42 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-14 11:49:12 +08:00
puxuan
d63306b9a4 主线 2025-08-14 11:49:09 +08:00
tuxinyu
83de30c45e 11111111 2025-08-13 21:36:11 +08:00
tuxinyu
f0019edefb Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-13 20:56:39 +08:00
tuxinyu
f0a3b22724 1111111 2025-08-13 20:56:32 +08:00
puxuan
b863a8e3f4 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-13 20:55:35 +08:00
puxuan
f57f7e5225 战斗力 2025-08-13 20:55:28 +08:00
tuxinyu
3ed6ac716d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-13 20:08:04 +08:00
tuxinyu
0d574dfec7 11111111 2025-08-13 20:07:56 +08:00
puxuan
a83f98212b Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-13 20:05:34 +08:00
puxuan
f910e5898d 2025-08-13 20:05:10 +08:00
changyuxiang
19fdca577f Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-13 19:49:42 +08:00
changyuxiang
fe750e0645 boss 2025-08-13 19:49:29 +08:00
tuxinyu
30e75cf876 11111111 2025-08-13 19:47:57 +08:00
tuxinyu
a234e231e7 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-13 19:42:03 +08:00
tuxinyu
e88575790b 111111 2025-08-13 19:41:49 +08:00
puxuan
4a945ae37d 主线 2025-08-13 18:33:41 +08:00
puxuan
01a7063020 2025-08-13 17:17:37 +08:00
puxuan
1468aebe4d 英雄信息 2025-08-13 16:27:40 +08:00
puxuan
22a6577076 抽卡 2025-08-13 15:38:46 +08:00
changyuxiang
9621200f95 所有精英到齐 2025-08-12 20:11:11 +08:00
puxuan
1aff7876ec 抽卡 2025-08-12 19:44:10 +08:00
puxuan
a4ea1fabaa meta 2025-08-12 09:52:23 +08:00
changyuxiang
27b796556c Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-11 20:46:29 +08:00
changyuxiang
05efb66d3b 精英两个 2025-08-11 20:46:06 +08:00
puxuan
881c683953 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-11 20:39:30 +08:00
puxuan
54cdfc3e47 抽卡 2025-08-11 20:39:27 +08:00
tuxinyu
1b23618a5d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-11 13:05:20 +08:00
tuxinyu
48b6c358ef 111111111 2025-08-11 13:05:12 +08:00
puxuan
d9ddc699c9 设置 2025-08-11 10:18:06 +08:00
puxuan
a0cf7ed49d 设置 2025-08-08 17:37:48 +08:00
puxuan
8913c7fc88 设置 2025-08-08 17:14:39 +08:00
puxuan
13126cb4b2 res 2025-08-08 15:27:17 +08:00
puxuan
2c8a5f70e5 res 2025-08-08 14:19:46 +08:00
puxuan
d385b8c795 局内 2025-08-08 11:42:15 +08:00
puxuan
7cd4088ecd Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-08 11:41:24 +08:00
puxuan
313e3f6bdf 局内 2025-08-08 11:41:21 +08:00
tuxinyu
4acd0f9bcb 11111 2025-08-08 10:08:09 +08:00
changyuxiang
6fa1b63954 1 2025-08-06 21:59:34 +08:00
changyuxiang
5b3a108204 胜利失败 2025-08-06 21:34:21 +08:00
puxuan
56a472e971 2025-08-06 20:47:20 +08:00
puxuan
7080ca79f7 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-06 20:46:51 +08:00
puxuan
dd1063d61e task 2025-08-06 20:46:47 +08:00
changyuxiang
d8ca62d0c8 1 2025-08-06 20:05:24 +08:00
tuxinyu
46488baee7 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-06 19:49:48 +08:00
tuxinyu
f011b093d6 11111 2025-08-06 19:49:26 +08:00
puxuan
eb10c29940 android 2025-08-05 17:29:22 +08:00
puxuan
6ef7de12af res 2025-08-05 14:59:18 +08:00
puxuan
67da3359ac Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-05 10:26:51 +08:00
puxuan
c79e3498bc res 2025-08-05 10:26:43 +08:00
tuxinyu
b507498f30 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-04 20:58:52 +08:00
tuxinyu
e763a97390 111111 2025-08-04 20:58:32 +08:00
puxuan
5682c2aace res 2025-08-04 19:51:41 +08:00
puxuan
26b7f4d109 build 2025-08-04 19:44:45 +08:00
puxuan
d351d4549f build 2025-08-04 19:14:30 +08:00
puxuan
4ce72abeb5 res 2025-08-04 18:49:43 +08:00
puxuan
a351869a40 res 2025-08-04 17:15:32 +08:00
puxuan
568915467c 主界面 2025-08-04 17:10:12 +08:00
puxuan
c2d8f2f894 天赋 2025-08-04 11:44:25 +08:00
puxuan
e1593159f8 meta 2025-08-04 09:42:04 +08:00
puxuan
fcfcbfd9ae Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-08-04 09:41:35 +08:00
puxuan
d398da007f talent 2025-08-04 09:41:32 +08:00
tuxinyu
284cdfbe53 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-31 20:54:58 +08:00
tuxinyu
a509b5b119 1111111 2025-07-31 20:54:43 +08:00
changyuxiang
7456741201 1 2025-07-31 20:53:57 +08:00
changyuxiang
62e22bc2e8 1 2025-07-29 20:04:55 +08:00
puxuan
cdc40c57ad 公司 2025-07-28 21:37:47 +08:00
changyuxiang
f8a2738052 删除动作融合 2025-07-28 21:35:05 +08:00
changyuxiang
79e55d3646 1 2025-07-28 21:32:41 +08:00
changyuxiang
e1b1bafd78 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-28 21:05:51 +08:00
changyuxiang
5810bba3d8 精英5个 2025-07-28 21:05:35 +08:00
tuxinyu
7bb1df9f35 111111 2025-07-28 21:04:58 +08:00
tuxinyu
f0bb21c710 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-28 21:00:08 +08:00
tuxinyu
f7b00effe8 1111111 2025-07-28 20:59:27 +08:00
changyuxiang
a0c49f6a6e Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-28 20:42:55 +08:00
changyuxiang
e4aadf984d 1 2025-07-28 20:42:43 +08:00
puxuan
a335e07912 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-28 20:37:13 +08:00
puxuan
2080d5d643 挂机 2025-07-28 20:37:09 +08:00
tuxinyu
b50725a99c Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-28 20:15:46 +08:00
tuxinyu
6d7ddf4a25 1111111 2025-07-28 20:15:25 +08:00
puxuan
f12dad8c7f config 2025-07-23 20:06:30 +08:00
changyuxiang
3c60d66567 1 2025-07-22 21:02:55 +08:00
changyuxiang
2b95659045 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-22 20:48:32 +08:00
changyuxiang
2018520302 1 2025-07-22 20:48:26 +08:00
puxuan
d0fa3731bb arena 2025-07-22 20:43:38 +08:00
puxuan
7db28b8e49 arena 2025-07-21 21:05:32 +08:00
tuxinyu
bec8324c7b Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-17 19:28:15 +08:00
tuxinyu
cdb2e850fb 11111 2025-07-17 19:27:37 +08:00
kai
3f12d50201 每日挑战 2025-07-16 21:58:51 +08:00
kai
4fb30c128d 每日挑战 2025-07-16 21:56:44 +08:00
changyuxiang
b2cd80a254 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-16 21:38:24 +08:00
changyuxiang
f3b8eec0cd 1 2025-07-16 21:38:20 +08:00
puxuan
3510a6bef5 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-15 20:59:50 +08:00
puxuan
94227802b4 arena 2025-07-15 20:59:15 +08:00
changyuxiang
c17c28f4fe 过热小莫、火花机 2025-07-15 20:53:38 +08:00
changyuxiang
97ba55700d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-14 21:42:00 +08:00
changyuxiang
080cb76743 1 2025-07-14 21:41:57 +08:00
puxuan
b921faab86 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-14 21:32:58 +08:00
puxuan
7515a0ef1b arena 2025-07-14 21:32:49 +08:00
changyuxiang
61e7e50afd 最后一个怪 2025-07-14 20:59:43 +08:00
puxuan
86f8891173 主界面箱子 2025-07-14 20:48:32 +08:00
kai
4429fb0e24 竞技场 2025-07-13 23:09:23 +08:00
changyuxiang
776d33f119 1 2025-07-09 22:04:58 +08:00
changyuxiang
a8e400309d 一波小怪 2025-07-09 21:22:43 +08:00
tuxinyu
6cfa99a2fd 11111111 2025-07-09 20:49:33 +08:00
tuxinyu
ff7526810b Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-09 20:00:33 +08:00
tuxinyu
bff03d9595 1111111 2025-07-09 20:00:22 +08:00
kai
e1abcbf979 主界面 2025-07-07 23:37:57 +08:00
puxuan
d7db1af006 Merge branch 'dev_chapter' into dev_hero 2025-07-07 21:39:59 +08:00
puxuan
ccf4d4cf3e 主界面 2025-07-07 21:39:35 +08:00
changyuxiang
ac48012ed0 传两个小怪,差6个 2025-07-07 20:38:27 +08:00
puxuan
c47f373913 Merge branch 'dev_3' into dev_hero 2025-07-07 19:59:32 +08:00
puxuan
6fbcf645cb 屏蔽报错 2025-07-07 19:58:01 +08:00
puxuan
b4c27e47f0 Merge branch 'dev_hero' into dev_chapter
# Conflicts:
#	Assets/arts/atlas/ui/main.spriteatlas
#	Assets/arts/textures/ui/main/main_bar_2_bg.png.meta
#	Assets/arts/textures/ui/main/main_bg_4.png.meta
2025-07-04 12:56:52 +08:00
puxuan
a4c4632f98 res 2025-07-04 12:54:20 +08:00
puxuan
fd3cac4e2e proto 2025-07-04 12:51:21 +08:00
puxuan
424c407aba proto 2025-07-04 12:49:14 +08:00
puxuan
604b634b80 chapter 2025-07-03 20:56:56 +08:00
tuxinyu
c7b30dcf87 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-03 20:46:14 +08:00
tuxinyu
0845703721 1111 2025-07-03 20:40:51 +08:00
changyuxiang
10693e85b3 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-07-02 20:39:09 +08:00
changyuxiang
d06e38ae36 1 2025-07-02 20:39:02 +08:00
tuxinyu
bbcbdabe27 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-06-30 22:14:50 +08:00
tuxinyu
194eef9612 1111111 2025-06-30 22:14:34 +08:00
puxuan
d92df2510a hero 2025-06-30 22:05:54 +08:00
puxuan
d66db62d4b hero 2025-06-30 22:02:12 +08:00
changyuxiang
d128fb5203 2025-06-30 20:08:39 +08:00
kai
d5bdd59e65 . 2025-06-29 16:45:09 +08:00
kai
3a47091fa5 主界面 2025-06-29 16:36:24 +08:00
kai
d988308e79 主界面 2025-06-29 15:15:37 +08:00
kai
4bd8a963ce 主界面 2025-06-29 13:38:53 +08:00
kai
d8fe750a63 竞技场报错 2025-06-29 11:34:35 +08:00
kai
8611677a5d 商店报错 2025-06-29 10:37:02 +08:00
kai
f199aa4642 hero 2025-06-28 19:10:51 +08:00
puxuan
bab3c5b294 hero 2025-06-28 14:15:41 +08:00
puxuan
1d826dca2d 英雄界面 2025-06-26 21:34:10 +08:00
puxuan
5d042832ad hero 2025-06-26 00:14:17 +08:00
puxuan
c8ef9aa7e7 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-06-26 00:13:52 +08:00
puxuan
3e707f40a6 res 2025-06-25 22:44:41 +08:00
puxuan
d1c1de9e75 res 2025-06-25 22:42:55 +08:00
changyuxiang
f526f0fcfb Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-06-25 19:30:41 +08:00
changyuxiang
e6eca956a3 更新怪 2025-06-25 19:30:37 +08:00
tuxinyu
0970248aaa 6we8gf4rweg5 2025-06-24 21:21:54 +08:00
puxuan
5291201c37 lua 2025-06-23 22:15:24 +08:00
changyuxiang
27296bd4ed 怪物123重制版 2025-06-23 21:26:33 +08:00
changyuxiang
75da39d626 10个英雄更新 2025-06-23 20:31:50 +08:00
puxuan
7106d1b991 star 2025-06-23 00:04:42 +08:00
puxuan
69701634df 暂时还原p0001-p0004 2025-06-22 22:15:23 +08:00
puxuan
b457d91a2d Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-06-22 19:06:13 +08:00
puxuan
0223007bc4 star 2025-06-22 19:06:10 +08:00
changyuxiang
4bf6afa963 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-06-20 22:28:06 +08:00
changyuxiang
01569a9965 改名字 2025-06-20 22:28:01 +08:00
tuxinyu
5ee0c9c5f1 Merge branch 'dev_hero' of https://git.wdd817.link/puxuan/c1_unity into dev_hero 2025-06-19 21:15:43 +08:00
tuxinyu
9cedb170d6 5413564 2025-06-19 21:15:37 +08:00
changyuxiang
08434ef5b5 死灵法师 2025-06-19 21:14:08 +08:00
changyuxiang
513acf7dc9 死灵法师 2025-06-19 20:32:37 +08:00
puxuan
9034e6a452 fix bug 2025-06-18 21:24:27 +08:00
puxuan
5b143a061f fix bug 2025-06-17 21:00:44 +08:00
puxuan
dd355826d3 fix bug 2025-06-17 20:51:43 +08:00
puxuan
c530cf25b9 fix bug 2025-06-17 20:29:18 +08:00
puxuan
99cccbbb75 res 2025-06-17 19:59:50 +08:00
puxuan
0510e5c71b fix bug 2025-06-17 19:40:26 +08:00
puxuan
71edfe09ca fix bug 2025-06-16 20:59:30 +08:00
puxuan
35e3a95e79 Merge branch 'dev_spine' into dev_hero 2025-06-16 20:20:28 +08:00
1dde46fb3a 1 2025-06-13 02:26:43 +08:00
47d3a203d8 加个born 2025-06-13 00:18:23 +08:00
puxuan
7f796f480c tips 2025-06-12 22:47:33 +08:00
puxuan
c3d9830278 config 2025-06-12 22:06:18 +08:00
puxuan
1b031303fc Merge branch 'dev_spine' into dev_hero 2025-06-12 22:05:06 +08:00
d5ec878c3f 1 2025-06-12 01:21:57 +08:00
puxuan
68da2a7313 boss技能 2025-06-11 23:52:39 +08:00
puxuan
674e9c8679 mystery_box 2025-06-10 23:37:34 +08:00
puxuan
0b45dbebb8 Merge branch 'dev_spine' into dev_hero 2025-06-10 23:37:00 +08:00
94377eed13 1 2025-06-10 22:27:22 +08:00
puxuan
37dc0e4dad 受击 2025-06-09 23:51:29 +08:00
puxuan
7a0501f3ce Merge branch 'dev_spine' into dev_hero 2025-06-09 23:44:24 +08:00
95533b39a2 1 2025-06-09 23:42:28 +08:00
puxuan
3aeae3c273 Merge branch 'dev_spine' into dev_hero 2025-06-09 23:20:46 +08:00
6e6fc18cd8 2025-06-09 21:55:45 +08:00
e90fdc5796 1 2025-06-08 21:52:16 +08:00
puxuan
b9e1915f98 fix bug 2025-06-06 16:29:18 +08:00
puxuan
d080d9b23e hero 2025-06-05 00:14:52 +08:00
puxuan
d82329610d skill 2025-06-03 23:58:23 +08:00
puxuan
2b15221013 Merge branch 'dev_spine' into dev_hero 2025-06-02 23:37:33 +08:00
tuxinyu
dc0eee51b9 章鱼哥 2025-05-29 20:56:23 +08:00
puxuan
a77df017d7 hero 2025-05-28 00:21:24 +08:00
puxuan
472cefe2ca Merge branch 'dev_spine' into dev_hero 2025-05-27 00:09:19 +08:00
puxuan
4cb91d9c95 升星 2025-05-27 00:08:50 +08:00
8c70edf172 1 2025-05-26 22:53:40 +08:00
57119c41da 1 2025-05-26 22:42:47 +08:00
b7014b03ee 678 2025-05-26 22:42:25 +08:00
puxuan
14a895bfc0 2025-05-25 23:41:09 +08:00
puxuan
e346e7146e hero 2025-05-25 23:34:19 +08:00
puxuan
7718bc4ab0 英雄基础数据 2025-05-25 19:22:07 +08:00
puxuan
4106b91afd Merge branch 'dev_spine' into dev_hero 2025-05-24 23:51:39 +08:00
puxuan
5f87e1e817 hero 2025-05-24 23:49:57 +08:00
000e3803dc 替换UI文件 2025-05-24 21:14:51 +08:00
puxuan
25f8d5badb lua 2025-05-24 15:48:08 +08:00
0ec8c05429 Merge branch 'dev_spine' of https://git.wdd817.link/puxuan/c1_unity into dev_spine 2025-05-24 14:21:16 +08:00
9472a28e5c ui替换 2025-05-24 14:21:13 +08:00
puxuan
1a2510264e config 2025-05-24 12:00:36 +08:00
puxuan
c145034f84 gm 2025-05-23 22:41:43 +08:00
da58ff6466 Merge branch 'dev_spine' of https://git.wdd817.link/puxuan/c1_unity into dev_spine 2025-05-23 22:32:46 +08:00
71467e216d UI版本更新 2025-05-23 22:32:40 +08:00
puxuan
97fd207faf Merge branch 'dev' into dev_spine 2025-05-23 00:05:23 +08:00
puxuan
9916b78bb6 lua 2025-05-22 22:53:38 +08:00
f7ba919c6a Merge branch 'dev_spine' of https://git.wdd817.link/puxuan/c1_unity into dev_spine 2025-05-20 23:49:06 +08:00
2393149460 UI替换 2025-05-20 23:42:34 +08:00
puxuan
1e5d69bed5 fix bug 2025-05-20 23:11:58 +08:00
puxuan
2639862d95 proto 2025-05-19 22:11:40 +08:00
5328524eed Merge branch 'dev_spine' of https://git.wdd817.link/puxuan/c1_unity into dev_spine 2025-05-18 22:57:44 +08:00
c1c8ae1a91 1 2025-05-18 22:57:36 +08:00
puxuan
00b2a50ddb Merge branch 'dev' into dev_spine 2025-05-18 22:39:37 +08:00
1ade69bebe 英雄更新 2025-05-18 21:06:27 +08:00
6f4a9e0238 1 2025-05-18 01:34:11 +08:00
ff733e9981 1英雄 2025-05-18 01:34:05 +08:00
1d30bb96a2 主界面UI和小怪BOSS替换 2025-05-17 20:35:44 +08:00
puxuan
aa81a18d2c . 2025-05-15 23:52:48 +08:00
puxuan
5f101e936a log 2025-05-15 22:41:22 +08:00
puxuan
21d6651d1b lua 2025-05-15 22:32:46 +08:00
puxuan
b1ea12e70d .. 2025-05-15 22:12:18 +08:00
puxuan
a447c7470a 屏蔽配置检查 2025-05-15 08:37:58 +08:00
puxuan
43222b0299 主界面 2025-05-13 00:12:08 +08:00
puxuan
54843c5417 spine 2025-05-06 20:44:39 +08:00
puxuan
d33daf1652 c1 2025-05-05 22:23:55 +08:00
kai
2dd336e3bc gate 2025-04-30 23:19:05 +08:00
kai
986b121df4 升级引擎 2025-04-30 23:12:28 +08:00
17364 changed files with 13488620 additions and 785919 deletions

1
.gitignore vendored
View File

@ -54,3 +54,4 @@ Assets/Editor/FYUtils
Assets/Editor/FYUtils.meta Assets/Editor/FYUtils.meta
fbg.log fbg.log
.vsconfig

View File

@ -20,61 +20,32 @@ namespace BFEditor.Build
} }
} }
public static class BuildMode
{
public const string DEV = "dev";
public const string TEST = "test";
public const string PUBLISH = "publish";
}
[Serializable] [Serializable]
public class BuildInfo public class BuildInfo
{ {
public string bundleName; // 包名 public string bundleName; // 包名
public string version; // 版本号 public string version; // 版本号
public string mode; // 渠道名_debug 或 渠道名_release public string mode; // 内网测试包,外网测试包,外网正式包
public int version_code = 1; // 各自渠道的version_code public int versionCode = 1; // 各自渠道的version code
public List<BulidGitInfo> git_info; // 打包的git信息 public List<BulidGitInfo> git_info; // 打包的git信息
public bool exportProject = false; // 是否只导出工程
public bool onlyAssetBundle = false; // 是否只打ab包
[NonSerialized] [NonSerialized]
public bool skipVersion = false; // 是否跳过版本校验 public bool skipVersion = false; // 是否跳过版本校验
public bool IsGPChannel()
{
return bundleName == "com.combo.heroes.puzzle.rpg";
}
public bool IsGPOfficial()
{
return bundleName == "com.combo.heroes.puzzle.rpg";
}
// dev包使用mono编译不会导出as工程
public bool IsDevChannel()
{
return bundleName == "com.juzu.b6.dev" || bundleName == "com.juzu.b6.dev.android" ||
bundleName == "com.juzu.b6.dev.ios";
}
public bool IsReleaseChannel()
{
return !IsDevChannel();
}
// 是否是内网release
public bool IsLanRelease()
{
return bundleName == "com.juzu.b6.release.android" || bundleName == "com.juzu.b6.release.ios";
}
public bool IsPublish() public bool IsPublish()
{ {
return !IsDevChannel() && !IsLanRelease(); return mode == BuildMode.PUBLISH;
} }
public bool IsIOSPlatform()
{
return bundleName.Contains("ios");
}
public bool IsAndroidPlatform()
{
return !IsIOSPlatform();
}
public string GetBundleName() public string GetBundleName()
{ {
return bundleName; return bundleName;

View File

@ -48,6 +48,12 @@ namespace BFEditor.Build
return false; return false;
} }
// 只打ab包
if (buildInfo.onlyAssetBundle)
{
AssetDatabase.Refresh();
return true;
}
// 删除不进包的多语言 // 删除不进包的多语言
// if (!DeleteOverLanguageAb(buildInfo)) // if (!DeleteOverLanguageAb(buildInfo))
// { // {
@ -73,19 +79,10 @@ namespace BFEditor.Build
watch.Start(); watch.Start();
var result = false; var result = false;
if (BuildAndroidUtils.BuildAndroidPlayer(buildInfo))
if (buildInfo.IsAndroidPlatform() && BuildAndroidUtils.BuildAndroidPlayer(buildInfo))
{ {
result = true; result = true;
} }
#if UNITY_EDITOR_OSX
if (buildInfo.IsIOSPlatform() && BuildIOSUtils.BuildIOSPlayer(buildInfo))
{
result = true;
}
#endif
if (result) if (result)
{ {
watch.Stop(); watch.Stop();
@ -140,8 +137,7 @@ namespace BFEditor.Build
var watch = new System.Diagnostics.Stopwatch(); var watch = new System.Diagnostics.Stopwatch();
watch.Start(); watch.Start();
// var buildTarget = buildInfo.IsIOSPlatform() ? BuildTarget.iOS : BuildTarget.Android; var isRelease = true;
var isRelease = buildInfo.IsReleaseChannel();
Debug.Log("[bfinfo]开始打包资源, bundleName : " + buildInfo.bundleName + " version : " + buildInfo.version + " mode : " + buildInfo.mode); Debug.Log("[bfinfo]开始打包资源, bundleName : " + buildInfo.bundleName + " version : " + buildInfo.version + " mode : " + buildInfo.mode);
// // 检查平台 // // 检查平台
@ -197,7 +193,7 @@ namespace BFEditor.Build
} }
// 本地缓存ab // 本地缓存ab
if (buildInfo.IsReleaseChannel()) if (buildInfo.IsPublish())
{ {
Debug.Log("[bfinfo]正在缓存assetbundles..."); Debug.Log("[bfinfo]正在缓存assetbundles...");
BFEditorUtils.CopyDirWithIgnore(outputPath, Path.Combine(AssetBundleCachePath, buildInfo.version), new List<string> { ".meta" }); BFEditorUtils.CopyDirWithIgnore(outputPath, Path.Combine(AssetBundleCachePath, buildInfo.version), new List<string> { ".meta" });

View File

@ -6,77 +6,116 @@ namespace BFEditor.Build
public enum BFPlatformOptions public enum BFPlatformOptions
{ {
AndroidDev = 1, AndroidDev = 1,
IOSDev, AndroidTest,
AndroidRelease,
AndroidGP, AndroidGP,
AndroidGPRU
} }
public class BuildProjectWindow : EditorWindow public class BuildProjectWindow : EditorWindow
{ {
private static int versionCode = 18; private static int VersionCode = 4;
private static string versionName = "1.6.5"; private static string VersionName = "1.2.10";
private static int VersionCodeRU = 12;
private static string VersionNameRU = "0.4.9";
BFPlatformOptions platform = BFPlatformOptions.AndroidDev; BFPlatformOptions platform = BFPlatformOptions.AndroidDev;
const string ANDROID_DEV_PACKAGE_NAME = "com.juzu.b6.dev.android"; const string ANDROID_GP_PACKAGE_NAME = "com.juzu.b6.dev.android";
const string ANDROID_RELEASE_PACKAGE_NAME = "com.juzu.b6.release.android";
const string ANDROID_GP_PACKAGE_NAME = "com.combo.heroes.puzzle.rpg";
const string IOS_PACKAGE_NAME = "com.juzu.b6.dev.ios";
public BuildProjectWindow() public BuildProjectWindow()
{ {
titleContent = new GUIContent("打包"); titleContent = new GUIContent("打包");
} }
private void OnEnable() { } private void OnEnable() { }
void OnGUI() void OnGUI()
{ {
GUILayout.BeginVertical("box");
EditorGUILayout.LabelField("选择渠道");
platform = (BFPlatformOptions)EditorGUILayout.EnumPopup("", platform);
EditorGUILayout.Space();
EditorGUILayout.LabelField("版本: " + versionName);
EditorGUILayout.Space();
string packageName; string packageName;
string mode; string mode;
string versionName = VersionName;
int versionCode = VersionCode;
bool skipVersion = false; bool skipVersion = false;
string appType;
if (platform == BFPlatformOptions.AndroidDev) if (platform == BFPlatformOptions.AndroidDev)
{ {
packageName = ANDROID_DEV_PACKAGE_NAME; packageName = ANDROID_GP_PACKAGE_NAME;
skipVersion = true; skipVersion = true;
mode = "dev_debug"; mode = BuildMode.DEV;
versionName = "0.1.0";
versionCode = 1;
appType = "内网测试包";
} }
else if(platform == BFPlatformOptions.AndroidRelease) else if(platform == BFPlatformOptions.AndroidTest)
{ {
packageName = ANDROID_RELEASE_PACKAGE_NAME; packageName = ANDROID_GP_PACKAGE_NAME;
mode = "release_release"; mode = BuildMode.TEST;
versionName = "0.1.0";
versionCode = 1;
appType = "外网测试包";
} }
else if(platform == BFPlatformOptions.AndroidGP) else if(platform == BFPlatformOptions.AndroidGP)
{ {
packageName = ANDROID_GP_PACKAGE_NAME; packageName = ANDROID_GP_PACKAGE_NAME;
mode = "publish_release"; mode = BuildMode.PUBLISH;
appType = "外网正式包";
} }
else else
{ {
packageName = IOS_PACKAGE_NAME; packageName = ANDROID_GP_PACKAGE_NAME;
mode = "dev_debug"; skipVersion = true;
mode = BuildMode.DEV;
versionName = "0.1.0";
versionCode = 1;
appType = "内网测试包";
} }
GUILayout.BeginVertical("box");
EditorGUILayout.LabelField("选择");
platform = (BFPlatformOptions)EditorGUILayout.EnumPopup("", platform);
EditorGUILayout.Space();
EditorGUILayout.LabelField("版本: " + versionName);
EditorGUILayout.Space();
EditorGUILayout.LabelField("包名: " + packageName); EditorGUILayout.LabelField("包名: " + packageName);
EditorGUILayout.LabelField("mode: " + mode); EditorGUILayout.Space();
EditorGUILayout.LabelField(appType);
EditorGUILayout.Space();
EditorGUILayout.Space(); EditorGUILayout.Space();
EditorGUILayout.Space(); var buildInfo = new BuildInfo();
buildInfo.version = versionName;
buildInfo.versionCode = versionCode;
buildInfo.mode = mode;
buildInfo.bundleName = packageName;
buildInfo.skipVersion = skipVersion;
if (GUILayout.Button("一键打包")) if (GUILayout.Button("一键APK"))
{ {
var buildInfo = new BuildInfo(); buildInfo.exportProject = false;
buildInfo.version = versionName; buildInfo.onlyAssetBundle = false;
buildInfo.version_code = versionCode; BuildProjectTools.BuildBFPlayer(buildInfo);
buildInfo.mode = mode; }
buildInfo.bundleName = packageName;
buildInfo.skipVersion = skipVersion; EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
if (GUILayout.Button("仅导出工程"))
{
buildInfo.exportProject = true;
buildInfo.onlyAssetBundle = false;
BuildProjectTools.BuildBFPlayer(buildInfo);
}
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
if (GUILayout.Button("仅打ab包"))
{
buildInfo.exportProject = true;
buildInfo.onlyAssetBundle = true;
BuildProjectTools.BuildBFPlayer(buildInfo); BuildProjectTools.BuildBFPlayer(buildInfo);
} }

View File

@ -77,25 +77,12 @@ namespace BFEditor.Build
Directory.CreateDirectory(outputPath); Directory.CreateDirectory(outputPath);
} }
AssetBundleManifest manifest; AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(outputPath, options |
if (release) BuildAssetBundleOptions.StrictMode |
{ BuildAssetBundleOptions.DisableLoadAssetByFileName |
manifest = BuildPipeline.BuildAssetBundles(outputPath, options | BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension |
BuildAssetBundleOptions.StrictMode | BuildAssetBundleOptions.DeterministicAssetBundle,
BuildAssetBundleOptions.DisableLoadAssetByFileName | target);
BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension |
BuildAssetBundleOptions.DeterministicAssetBundle,
target);
}
else
{
manifest = BuildPipeline.BuildAssetBundles(outputPath, options |
BuildAssetBundleOptions.StrictMode |
BuildAssetBundleOptions.DisableLoadAssetByFileName |
BuildAssetBundleOptions.DisableLoadAssetByFileNameWithExtension |
BuildAssetBundleOptions.DeterministicAssetBundle,
target);
}
if (manifest == null) if (manifest == null)
{ {
@ -365,12 +352,12 @@ namespace BFEditor.Build
SetProtoABName(Path.Combine(Application.dataPath, "proto"), index++ / total); SetProtoABName(Path.Combine(Application.dataPath, "proto"), index++ / total);
SetSpineABName(Path.Combine(Application.dataPath, "arts", "spines"), index++ / total); SetSpineABName(Path.Combine(Application.dataPath, "arts", "spines"), index++ / total);
SetFirstABName(Path.Combine(Application.dataPath, "first"), index++ / total); SetFirstABName(Path.Combine(Application.dataPath, "first"), index++ / total);
// SetTimelineABName(Path.Combine(Application.dataPath, "arts", "timeline"), 16f / total); // SetTimelineABName(Path.Combine(Application.dataPath, "arts", "timeline"), index++ / total);
SetVideoABName(Path.Combine(Application.dataPath, "arts", "video"), index++ / total); SetVideoABName(Path.Combine(Application.dataPath, "arts", "video"), index++ / total);
// SetLanguageResABName(Resource.ResourceProcessConfig.LANGUAGE_PATH, 19f / total); // SetLanguageResABName(Resource.ResourceProcessConfig.LANGUAGE_PATH, index++ / total);
// SetBakedatasABName(Path.Combine(Application.dataPath, "arts", "bakedatas"), 21f / total); // SetBakedatasABName(Path.Combine(Application.dataPath, "arts", "bakedatas"), index++ / total);
// SetLightProbesABName(Path.Combine(Application.dataPath, "arts", "lightprobes"), 22f / total); // SetLightProbesABName(Path.Combine(Application.dataPath, "arts", "lightprobes"), index++ / total);
// SetReflectionsABName(Path.Combine(Application.dataPath, "arts", "reflections"), 23f / total); // SetReflectionsABName(Path.Combine(Application.dataPath, "arts", "reflections"), index++ / total);
EditorUtility.ClearProgressBar(); EditorUtility.ClearProgressBar();
AssetDatabase.SaveAssets(); AssetDatabase.SaveAssets();
@ -572,11 +559,11 @@ namespace BFEditor.Build
{ {
EditorUtility.DisplayProgressBar("提示", "正在设置spine ABName", progress); EditorUtility.DisplayProgressBar("提示", "正在设置spine ABName", progress);
var dirInfo = new DirectoryInfo(dirPath); string[] dirList = { "ui" , "characters" };
var dirs = dirInfo.GetDirectories(); for (var i = 0; i < dirList.Length; ++i)
for (var i = 0; i < dirs.Length; i++)
{ {
SetABNameBySubDir(dirs[i]); var dirInfo = new DirectoryInfo(Path.Combine(dirPath, dirList[i]));
SetABNameBySubDir(dirInfo);
} }
} }
@ -596,6 +583,11 @@ namespace BFEditor.Build
var dirInfo = new DirectoryInfo(Path.Combine(dirPath, dirList[i])); var dirInfo = new DirectoryInfo(Path.Combine(dirPath, dirList[i]));
SetABNameBySubDir(dirInfo); SetABNameBySubDir(dirInfo);
} }
var dirInfo2 = new DirectoryInfo(Path.Combine(dirPath, "ui", "activity"));
if (dirInfo2.Exists)
{
SetABNameBySubDir(dirInfo2);
}
} }
static void SetBackgroundABName(string dirPath) static void SetBackgroundABName(string dirPath)

View File

@ -3,12 +3,12 @@ using UnityEditor;
using System.IO; using System.IO;
using UnityEditor.Build.Reporting; using UnityEditor.Build.Reporting;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Collections.Generic;
using System; using System;
using System.Threading; using System.Threading;
using System.Collections.Generic;
namespace BFEditor.Build namespace BFEditor.Build
{ {
public static class BuildAndroidUtils public static class BuildAndroidUtils
{ {
const string JAVA_HOME_ENVIRONMENT = "JAVA_HOME"; const string JAVA_HOME_ENVIRONMENT = "JAVA_HOME";
@ -18,19 +18,19 @@ namespace BFEditor.Build
const string GRADLE_PATH = "/Users/aoddabao/.gradle/wrapper/dists/gradle-5.6.4-all/ankdp27end7byghfw1q2sw75f/gradle-5.6.4/bin/gradle"; const string GRADLE_PATH = "/Users/aoddabao/.gradle/wrapper/dists/gradle-5.6.4-all/ankdp27end7byghfw1q2sw75f/gradle-5.6.4/bin/gradle";
const string BUGLY_APP_ID = "1eb4e5e560"; const string BUGLY_APP_ID = "1eb4e5e560";
const string BUGLY_APP_KEY = "99e249db-4eeb-440e-83e7-c2bd80e8b5e4"; const string BUGLY_APP_KEY = "99e249db-4eeb-440e-83e7-c2bd80e8b5e4";
static Thread buglyUploadThread; static Thread buglyUploadThread;
static string ReleaseSOPath = Application.dataPath + "/../BFVersions/android/ub-release/src/main/jniLibs"; static string ReleaseSOPath = Application.dataPath + "/../BFVersions/android/ub-release/src/main/jniLibs";
static string BuglyPath = Application.dataPath + "/../Bugly"; static string BuglyPath = Application.dataPath + "/../Bugly";
static string BuglySOPath = Application.dataPath + "/../Bugly/so"; static string BuglySOPath = Application.dataPath + "/../Bugly/so";
static string GradleExcuteProjectPath = Application.dataPath + "/../BFVersions/android/ub-release"; static string GradleExcuteProjectPath = Application.dataPath + "/../BFVersions/android/ub-release";
static string DevAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_dev";
static string LanReleaseAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_release";
static string GoogleAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_google_apk"; static string GoogleAsProjectPath = Application.dataPath + "/../BFVersions/android/dz_google_apk";
static string GoogleCommonProjectPath = Application.dataPath + "/../BFVersions/android/google_common"; static string GoogleCommonProjectPath = Application.dataPath + "/../BFVersions/android/google_common";
static string GPAsProjectPath = Application.dataPath + "/../BFVersions/android/ub-gp"; // gp删档测试渠道 static string RuStoreProjectPath = Application.dataPath + "/../BFVersions/android/ru_store";
static string GPOfficialAsProjectPath = Application.dataPath + "/../BFVersions/android/ub-google"; // gp正式渠道 static string RuProjectPath = Application.dataPath + "/../BFVersions/android/ru";
static string GoogleServicesProjectPath = Application.dataPath + "/../BFVersions/android/google-services";
static string PublishAsProjectPath = Application.dataPath + "/../BFVersions/android/publish_release"; static string PublishAsProjectPath = Application.dataPath + "/../BFVersions/android/publish_release";
static string KeystoreFilePath = Application.dataPath + "/../BFVersions/android/keystore/dz_keystore.txt";
static string SignShellPath = Application.dataPath + "/../BFFiles/androidkey"; static string SignShellPath = Application.dataPath + "/../BFFiles/androidkey";
static string GpAlginShellPath = Application.dataPath + "/../BFFiles/androidkey"; static string GpAlginShellPath = Application.dataPath + "/../BFFiles/androidkey";
static HashSet<string> AABInPackageFileHashSet = new HashSet<string>() static HashSet<string> AABInPackageFileHashSet = new HashSet<string>()
@ -38,12 +38,12 @@ namespace BFEditor.Build
"bin", "bin",
"UnityServicesProjectConfiguration.json" "UnityServicesProjectConfiguration.json"
}; };
static BuildAndroidUtils() static BuildAndroidUtils()
{ {
EnsureJavaHome(); EnsureJavaHome();
} }
public static void EnsureJavaHome() public static void EnsureJavaHome()
{ {
// var javaHomeEnvironment = Environment.GetEnvironmentVariable(JAVA_HOME_ENVIRONMENT); // var javaHomeEnvironment = Environment.GetEnvironmentVariable(JAVA_HOME_ENVIRONMENT);
@ -52,35 +52,44 @@ namespace BFEditor.Build
// Environment.SetEnvironmentVariable(JAVA_HOME_ENVIRONMENT, JAVA_HOME_ENVIRONMENT_PATH); // Environment.SetEnvironmentVariable(JAVA_HOME_ENVIRONMENT, JAVA_HOME_ENVIRONMENT_PATH);
// } // }
} }
/// <summary> /// <summary>
/// 打包android /// 打包android
/// </summary> /// </summary>
public static bool BuildAndroidPlayer(BuildInfo buildInfo) public static bool BuildAndroidPlayer(BuildInfo buildInfo)
{ {
var buildTarget = BuildTarget.Android; var buildTarget = BuildTarget.Android;
// 检查平台 // 检查平台
if (EditorUserBuildSettings.activeBuildTarget != buildTarget) if (EditorUserBuildSettings.activeBuildTarget != buildTarget)
{ {
Debug.LogError("[bferror]当前没有在对应平台"); Debug.LogError("[bferror]当前没有在对应平台");
return false; return false;
} }
// 重新生成XLua // 重新生成XLua
CompileScriptsUtils.RegenerateXLuaCode(true); CompileScriptsUtils.RegenerateXLuaCode(true);
// 打包设置 // 打包设置
BuildSettings(buildInfo); BuildSettings(buildInfo);
// 开始打包 // 开始打包
var bpOptions = GetBuildOptions(buildInfo); var bpOptions = GetBuildOptions(buildInfo);
var report = BuildPipeline.BuildPlayer(bpOptions); var report = BuildPipeline.BuildPlayer(bpOptions);
// 打包成功 // 导出工程成功
if (report.summary.result == BuildResult.Succeeded) if (report.summary.result == BuildResult.Succeeded)
{ {
return BuildAndroidAPK(buildInfo); MergeProject(buildInfo, GoogleAsProjectPath);
FixGradleVersion(buildInfo.versionCode, buildInfo.version);
if (buildInfo.exportProject)
{
return true;
}
else
{
return BuildAPK(buildInfo);
}
} }
else else
{ {
@ -88,7 +97,7 @@ namespace BFEditor.Build
return false; return false;
} }
} }
/// <summary> /// <summary>
/// 打包设置 /// 打包设置
/// </summary> /// </summary>
@ -96,45 +105,48 @@ namespace BFEditor.Build
{ {
// 设置bundleVersion // 设置bundleVersion
PlayerSettings.bundleVersion = buildInfo.version; PlayerSettings.bundleVersion = buildInfo.version;
// 设置VersionCode // 设置VersionCode
PlayerSettings.Android.bundleVersionCode = buildInfo.version_code; PlayerSettings.Android.bundleVersionCode = buildInfo.versionCode;
// 设置竖屏 // 设置竖屏
PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait; PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait;
PlayerSettings.allowedAutorotateToPortrait = false; PlayerSettings.allowedAutorotateToPortrait = false;
PlayerSettings.allowedAutorotateToPortraitUpsideDown = false; PlayerSettings.allowedAutorotateToPortraitUpsideDown = false;
PlayerSettings.allowedAutorotateToLandscapeLeft = false; PlayerSettings.allowedAutorotateToLandscapeLeft = false;
PlayerSettings.allowedAutorotateToLandscapeRight = false; PlayerSettings.allowedAutorotateToLandscapeRight = false;
// 安卓构建目标CPU架构 // 安卓构建目标CPU架构
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7 | AndroidArchitecture.ARM64; PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7 | AndroidArchitecture.ARM64;
// 强加Internet权限 // 强加Internet权限
PlayerSettings.Android.forceInternetPermission = true; PlayerSettings.Android.forceInternetPermission = true;
// 关闭启动动画 // 关闭启动动画
PlayerSettings.SplashScreen.show = false; PlayerSettings.SplashScreen.show = false;
// 设置包名 // 设置包名
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, buildInfo.bundleName); PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, buildInfo.bundleName);
Debug.Log("[bfinfo]设置包名:" + buildInfo.bundleName);
// 跳过版本控制 // 跳过版本控制
var symbols = ANDROID_DEFINE_SYMBOLS; var symbols = ANDROID_DEFINE_SYMBOLS;
if (buildInfo.skipVersion) if (buildInfo.skipVersion)
{ {
symbols = symbols + ";SKIP_VERSION;"; symbols = symbols + ";SKIP_VERSION";
}
if (buildInfo.mode == BuildMode.DEV)
{
symbols = symbols + ";BF_APP_DEV";
}
else if (buildInfo.mode == BuildMode.TEST)
{
symbols = symbols + ";BF_APP_TEST";
} }
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols);
Debug.Log("[bfinfo]设置defineSymbols: " + symbols); Debug.Log("[bfinfo]设置defineSymbols: " + symbols);
// 是否是dev
var development = buildInfo.IsDevChannel() ? true : false;
EditorUserBuildSettings.development = development;
// 商品名称 // 商品名称
// 应用名 // 应用名
if (buildInfo.IsPublish()) if (buildInfo.IsPublish())
{ {
@ -142,20 +154,18 @@ namespace BFEditor.Build
} }
else else
{ {
PlayerSettings.productName = development ? "b6-dev" : "b6-release"; PlayerSettings.productName = "b6-dev";
} }
// BuildType设置dev/release EditorUserBuildSettings.development = false;
EditorUserBuildSettings.androidBuildType = development ? AndroidBuildType.Debug : AndroidBuildType.Release; EditorUserBuildSettings.androidBuildType = AndroidBuildType.Release;
// 是否导出as工程 // 是否导出as工程
// EditorUserBuildSettings.exportAsGoogleAndroidProject = development ? false : true;
EditorUserBuildSettings.exportAsGoogleAndroidProject = true; EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
// dev使用Mono release使用IL2CPP var scriptImp = ScriptingImplementation.IL2CPP;
var scriptImp = development ? ScriptingImplementation.Mono2x : ScriptingImplementation.IL2CPP;
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, scriptImp); PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, scriptImp);
} }
/// <summary> /// <summary>
/// 获取打包参数 /// 获取打包参数
/// </summary> /// </summary>
@ -164,43 +174,23 @@ namespace BFEditor.Build
var bpOptions = new BuildPlayerOptions(); var bpOptions = new BuildPlayerOptions();
bpOptions.scenes = AssetBundleUtils.GetBuildScenes(); bpOptions.scenes = AssetBundleUtils.GetBuildScenes();
bpOptions.target = BuildTarget.Android; bpOptions.target = BuildTarget.Android;
// if (buildInfo.IsDevChannel())
// {
// bpOptions.locationPathName = GetDevApkPathName(buildInfo);
// Debug.Log("[bfinfo]apk path : " + bpOptions.locationPathName);
// }
// else
// {
// bpOptions.locationPathName = GetASProjectPathName();
// Debug.Log("[bfinfo]asProject path : " + bpOptions.locationPathName);
// }
bpOptions.locationPathName = GetASProjectPathName(buildInfo); bpOptions.locationPathName = GetASProjectPathName(buildInfo);
BuildOptions options; BuildOptions options = BuildOptions.None;
if (buildInfo.IsReleaseChannel())
{
options = BuildOptions.None;
}
else
{
options = BuildOptions.Development;
}
bpOptions.options = options; bpOptions.options = options;
return bpOptions; return bpOptions;
} }
static string GetDevApkPathName(BuildInfo buildInfo) static string GetDevApkPathName(BuildInfo buildInfo)
{ {
var apkName = buildInfo.skipVersion ? "dz_dev_skip_version.apk" : "dz_dev_debug.apk"; var apkName = buildInfo.skipVersion ? "dz_dev_skip_version.apk" : "dz_dev_debug.apk";
var path = Path.Combine(AS_PROJECT_PATH, apkName); var path = Path.Combine(AS_PROJECT_PATH, apkName);
return path; return path;
} }
static string GetASProjectPathName(BuildInfo buildInfo) static string GetASProjectPathName(BuildInfo buildInfo)
{ {
var dir = Path.Combine(AS_PROJECT_PATH, buildInfo.mode); var dir = Path.Combine(AS_PROJECT_PATH, "publish_release");
if (Directory.Exists(dir)) if (Directory.Exists(dir))
{ {
Directory.Delete(dir, true); Directory.Delete(dir, true);
@ -208,32 +198,53 @@ namespace BFEditor.Build
return dir; return dir;
} }
static bool BuildAPK(BuildInfo buildInfo) static bool BuildAPK(BuildInfo buildInfo, bool isAAB = false)
{ {
if (buildInfo.IsGPChannel()) // 设置jdk环境变量
{ string javaHomePath = System.Environment.GetEnvironmentVariable("JAVE_HOME");
MergeGPToReleaseProject(buildInfo); if (string.IsNullOrEmpty(javaHomePath))
FixGradleVersion(buildInfo.version_code, buildInfo.version); {
} Debug.LogError("[bferror] 找不到环境变量JAVE_HOME");
return false;
if (buildInfo.IsLanRelease()) }
{ var gradleFilePath = Path.Combine(PublishAsProjectPath, "gradle.properties");
AddBuglyParamsToReleaseProject(); var gradleFileText = File.ReadAllText(gradleFilePath);
} if (!gradleFileText.Contains("org.gradle.java.home"))
{
gradleFileText = gradleFileText + "\norg.gradle.java.home=" + javaHomePath.Replace("\\", "/");
}
File.WriteAllText(gradleFilePath, gradleFileText);
// 设置密钥密码
if (File.Exists(KeystoreFilePath))
{
var password = File.ReadAllText(KeystoreFilePath).Replace("\n", "").Replace("\r", "");
var buildGradlePath = Path.Combine(PublishAsProjectPath, "launcher/build.gradle");
var text = File.ReadAllText(buildGradlePath);
var regex = new Regex("REPLACE_PASSWORD");
text = regex.Replace(text, password);
File.WriteAllText(buildGradlePath, text);
}
Debug.Log("[bfinfo]正在buildApk..."); Debug.Log("[bfinfo]正在buildApk...");
var success = true; var success = true;
var args = ""; var args = "assembleRelease";
if (buildInfo.IsReleaseChannel()) if (isAAB)
{ {
args += " assembleRelease"; args = "bundleRelease";
} }
else string gradleHomePath = System.Environment.GetEnvironmentVariable("GRADLE_HOME");
{ if (string.IsNullOrEmpty(gradleHomePath))
args += " assembleDebug"; {
} Debug.LogError("[bferror] 找不到环境变量GRADLE_HOME");
return false;
BFEditorUtils.RunCommond(GRADLE_PATH, args, GradleExcuteProjectPath, }
#if UNITY_EDITOR_OSX
var gradleCommondPath = Path.Combine(gradleHomePath, "gradle");
#else
var gradleCommondPath = Path.Combine(gradleHomePath, "gradle.bat");
#endif
BFEditorUtils.RunCommond(gradleCommondPath, args, PublishAsProjectPath,
(msg) => (msg) =>
{ {
}, },
@ -245,80 +256,35 @@ namespace BFEditor.Build
Debug.LogError("[bferror] " + errorMsg); Debug.LogError("[bferror] " + errorMsg);
} }
}); });
if (buildInfo.IsGPChannel())
{
// 尝试制作并上传bugly符号表 开新Thread不影响打包流程
if (success)
{
CopySOAndUploadBuglySymbol(buildInfo.bundleName, buildInfo.version);
}
}
return success; return success;
} }
static bool BuildAAB(BuildInfo buildInfo)
{
var result = true;
if(buildInfo.IsGPChannel())
{
// MergeGPToReleaseProject(buildInfo);
// FixGradleVersion(buildInfo.version_code, buildInfo.version);
}
return result;
}
static bool BuildAndroidAPK(BuildInfo buildInfo)
{
var result = true;
if(buildInfo.IsDevChannel())
{
MergeProject(buildInfo, DevAsProjectPath);
var dir = Path.Combine(Application.dataPath, "../", AS_PROJECT_PATH, buildInfo.mode);
BFEditorUtils.RunCommond("gradle", " assembleDebug", dir, (msg) => {
}, (errorMsg) => {
Debug.LogError("[bferror] " + errorMsg);
});
}
else if(buildInfo.IsLanRelease())
{
MergeProject(buildInfo, LanReleaseAsProjectPath);
}
else if(buildInfo.IsGPChannel())
{
MergeProject(buildInfo, GoogleAsProjectPath);
FixGradleVersion(buildInfo.version_code, buildInfo.version);
}
return result;
}
/// <summary> /// <summary>
/// 合并dev工程 /// 合并工程
/// </summary> /// </summary>
static void MergeProject(BuildInfo buildInfo, String asProjectPath) static void MergeProject(BuildInfo buildInfo, String asProjectPath)
{ {
Debug.Log("[bfinfo]正在整合dev project..."); Debug.Log("[bfinfo]正在整合 project...");
var dir = Path.Combine(Application.dataPath, "../", AS_PROJECT_PATH, buildInfo.mode); var dir = Path.Combine(Application.dataPath, "../", AS_PROJECT_PATH, "publish_release");
var javaPath = Path.Combine(dir, "unityLibrary/src/main/java"); var javaPath = Path.Combine(dir, "unityLibrary/src/main/java");
var manifestPath = Path.Combine(dir, "unityLibrary/src/main/AndroidManifest.xml"); var manifestPath = Path.Combine(dir, "unityLibrary/src/main/AndroidManifest.xml");
// 老版本unity需要替换这个2021之后的新版本不需要
// 获取到unity打出的build-id // 获取到unity打出的build-id
var reader = new StreamReader(new FileStream(manifestPath, FileMode.Open)); // var reader = new StreamReader(new FileStream(manifestPath, FileMode.Open));
string buildIdLine; // string buildIdLine;
while ((buildIdLine = reader.ReadLine()) != null) // while ((buildIdLine = reader.ReadLine()) != null)
{ // {
if (buildIdLine.Contains("unity.build-id")) // if (buildIdLine.Contains("unity.build-id"))
{ // {
Debug.Log("[bfinfo]修正build-id: " + buildIdLine); // Debug.Log("[bfinfo]修正build-id: " + buildIdLine);
break; // break;
} // }
} // }
reader.Close(); // reader.Close();
reader.Dispose(); // reader.Dispose();
if (Directory.Exists(javaPath)) if (Directory.Exists(javaPath))
{ {
@ -326,71 +292,62 @@ namespace BFEditor.Build
di.Delete(true); di.Delete(true);
} }
BFEditorUtils.CopyDir(GoogleCommonProjectPath, dir); // 如果是俄罗斯支付 则需要覆盖为俄罗斯相关文件
// 获取到google_common复制过去的build.gradle和AndroidManifest // if (buildInfo.bundleName == BF.BFPlatform.ANDROID_GP_PACKAGE_NAME_RU)
var buildGradlePath = Path.Combine(dir, "launcher/build.gradle"); // {
var text = File.ReadAllText(buildGradlePath); // BFEditorUtils.CopyDir(RuProjectPath, dir);
var regex = new Regex("REPLACE_APPLICATION_ID"); // // 获取到build.gradle和AndroidManifest
text = regex.Replace(text, buildInfo.bundleName); // var buildGradlePath = Path.Combine(dir, "launcher/build.gradle");
File.WriteAllText(buildGradlePath, text); // var text = File.ReadAllText(buildGradlePath);
// var regex = new Regex("REPLACE_APPLICATION_ID");
// text = regex.Replace(text, buildInfo.bundleName);
// File.WriteAllText(buildGradlePath, text);
var androidManifestPath = Path.Combine(dir, "launcher/src/main/AndroidManifest.xml"); // var androidManifestPath = Path.Combine(dir, "launcher/src/main/AndroidManifest.xml");
text = File.ReadAllText(androidManifestPath); // text = File.ReadAllText(androidManifestPath);
regex = new Regex("REPLACE_APPLICATION_ID"); // regex = new Regex("REPLACE_APPLICATION_ID");
text = regex.Replace(text, buildInfo.bundleName); // text = regex.Replace(text, buildInfo.bundleName);
File.WriteAllText(androidManifestPath, text); // File.WriteAllText(androidManifestPath, text);
BFEditorUtils.CopyDir(asProjectPath, dir); // // 还有另一个AndroidManifest
// androidManifestPath = Path.Combine(dir, "unityLibrary/src/main/AndroidManifest.xml");
// text = File.ReadAllText(androidManifestPath);
// regex = new Regex("REPLACE_APPLICATION_ID");
// text = regex.Replace(text, buildInfo.bundleName);
// File.WriteAllText(androidManifestPath, text);
// }
// // 否则使用通用谷歌
// else
// {
BFEditorUtils.CopyDir(GoogleCommonProjectPath, dir);
// 获取到google_common复制过去的build.gradle和AndroidManifest
var buildGradlePath = Path.Combine(dir, "launcher/build.gradle");
var text = File.ReadAllText(buildGradlePath);
var regex = new Regex("REPLACE_APPLICATION_ID");
text = regex.Replace(text, buildInfo.bundleName);
File.WriteAllText(buildGradlePath, text);
text = File.ReadAllText(manifestPath); var androidManifestPath = Path.Combine(dir, "launcher/src/main/AndroidManifest.xml");
regex = new Regex("REPLACE_BUILD_ID"); text = File.ReadAllText(androidManifestPath);
text = regex.Replace(text, buildIdLine); regex = new Regex("REPLACE_APPLICATION_ID");
File.WriteAllText(manifestPath, text); text = regex.Replace(text, buildInfo.bundleName);
} File.WriteAllText(androidManifestPath, text);
/// <summary> BFEditorUtils.CopyDir(asProjectPath, dir);
/// 合并gp工程 // 还有dz_google_apk下的AndroidManifest
/// </summary> androidManifestPath = Path.Combine(dir, "unityLibrary/src/main/AndroidManifest.xml");
static void MergeGPToReleaseProject(BuildInfo buildInfo) text = File.ReadAllText(androidManifestPath);
{ regex = new Regex("REPLACE_APPLICATION_ID");
Debug.Log("[bfinfo]正在整合gp渠道sdk..."); text = regex.Replace(text, buildInfo.bundleName);
File.WriteAllText(androidManifestPath, text);
var javaPath = GradleExcuteProjectPath + "/src/main/java"; // }
var manifestPath = GradleExcuteProjectPath + "/src/main/AndroidManifest.xml"; // 统一替换google-services文件
var gsPath = Path.Combine(GoogleServicesProjectPath, Path.Combine(buildInfo.bundleName, "google-services.json"));
// 获取到unity打出的build-id if (File.Exists(gsPath))
var reader = new StreamReader(new FileStream(manifestPath, FileMode.Open));
string buildIdLine;
while ((buildIdLine = reader.ReadLine()) != null)
{
if (buildIdLine.Contains("unity.build-id"))
{
Debug.Log("[bfinfo]修正build-id: " + buildIdLine);
break;
}
}
reader.Close();
reader.Dispose();
if (Directory.Exists(javaPath))
{
var di = new DirectoryInfo(javaPath);
di.Delete(true);
}
if (buildInfo.IsGPOfficial())
{ {
BFEditorUtils.CopyDir(GPOfficialAsProjectPath, GradleExcuteProjectPath); var destFilePath = Path.Combine(dir, "launcher/google-services.json");
File.Copy(gsPath, destFilePath, true);
} }
else
{
BFEditorUtils.CopyDir(GPAsProjectPath, GradleExcuteProjectPath);
}
var text = File.ReadAllText(manifestPath);
var regex = new Regex("REPLACE_BUILD_ID");
text = regex.Replace(text, buildIdLine);
File.WriteAllText(manifestPath, text);
} }
/// <summary> /// <summary>
@ -413,7 +370,7 @@ namespace BFEditor.Build
text2 = regex2.Replace(text2, string.Format("versionName '{0}'", versionName)); text2 = regex2.Replace(text2, string.Format("versionName '{0}'", versionName));
File.WriteAllText(gradleFilePath2, text2); File.WriteAllText(gradleFilePath2, text2);
} }
/// <summary> /// <summary>
/// 内网Release包接入Bugly /// 内网Release包接入Bugly
/// </summary> /// </summary>
@ -429,7 +386,7 @@ namespace BFEditor.Build
"implementation 'com.tencent.bugly:crashreport:latest.release'\n" + "implementation 'com.tencent.bugly:crashreport:latest.release'\n" +
"implementation 'com.tencent.bugly:nativecrashreport:latest.release'\n"); "implementation 'com.tencent.bugly:nativecrashreport:latest.release'\n");
File.WriteAllText(gradleFilePath, text); File.WriteAllText(gradleFilePath, text);
// 修改AndroidManifest.xml // 修改AndroidManifest.xml
var manifestPath = GradleExcuteProjectPath + "/src/main/AndroidManifest.xml"; var manifestPath = GradleExcuteProjectPath + "/src/main/AndroidManifest.xml";
text = File.ReadAllText(manifestPath); text = File.ReadAllText(manifestPath);
@ -442,7 +399,7 @@ namespace BFEditor.Build
"<uses-permission android:name='android.permission.READ_LOGS' />\n" + "<uses-permission android:name='android.permission.READ_LOGS' />\n" +
"<uses-permission android:name='android.permission.POST_NOTIFICATIONS'/>\n"); "<uses-permission android:name='android.permission.POST_NOTIFICATIONS'/>\n");
File.WriteAllText(manifestPath, text); File.WriteAllText(manifestPath, text);
// 修改UnityPlayerActivity.java // 修改UnityPlayerActivity.java
var javaPath = GradleExcuteProjectPath + "/src/main/java/com/juzu/ub/release/android/UnityPlayerActivity.java"; var javaPath = GradleExcuteProjectPath + "/src/main/java/com/juzu/ub/release/android/UnityPlayerActivity.java";
text = File.ReadAllText(javaPath); text = File.ReadAllText(javaPath);
@ -458,7 +415,7 @@ namespace BFEditor.Build
text = text.Insert(index + length, formatInsertString); text = text.Insert(index + length, formatInsertString);
File.WriteAllText(javaPath, text); File.WriteAllText(javaPath, text);
} }
/// <summary> /// <summary>
/// release包加密后签名 /// release包加密后签名
/// </summary> /// </summary>
@ -477,7 +434,7 @@ namespace BFEditor.Build
}); });
return success; return success;
} }
/// <summary> /// <summary>
/// gp包对齐 /// gp包对齐
/// </summary> /// </summary>
@ -524,7 +481,7 @@ namespace BFEditor.Build
{ {
// 将release的so复制到bugly文件下 // 将release的so复制到bugly文件下
BFEditorUtils.CopyDir(ReleaseSOPath, BuglySOPath); BFEditorUtils.CopyDir(ReleaseSOPath, BuglySOPath);
// 开启Thread处理打包so和上传 // 开启Thread处理打包so和上传
TryCloseUploadThread(); TryCloseUploadThread();
var args = "bugly.sh" + " " + BUGLY_APP_ID + " " + BUGLY_APP_KEY + " " + bundleName + " " + version; var args = "bugly.sh" + " " + BUGLY_APP_ID + " " + BUGLY_APP_KEY + " " + bundleName + " " + version;
@ -532,7 +489,7 @@ namespace BFEditor.Build
buglyUploadThread.IsBackground = true; buglyUploadThread.IsBackground = true;
buglyUploadThread.Start(); buglyUploadThread.Start();
} }
static void UploadBuglySymbol(string args) static void UploadBuglySymbol(string args)
{ {
BFEditorUtils.RunCommond("sh", args, BuglyPath, BFEditorUtils.RunCommond("sh", args, BuglyPath,
@ -544,10 +501,10 @@ namespace BFEditor.Build
{ {
Debug.LogError("[bferror] UploadBuglySymbol: " + errorMsg); Debug.LogError("[bferror] UploadBuglySymbol: " + errorMsg);
}); });
TryCloseUploadThread(); TryCloseUploadThread();
} }
static void TryCloseUploadThread() static void TryCloseUploadThread()
{ {
if (buglyUploadThread != null) if (buglyUploadThread != null)

View File

@ -1,348 +1,348 @@
#if UNITY_EDITOR_OSX // #if UNITY_EDITOR_OSX
using UnityEngine; // using UnityEngine;
using UnityEditor; // using UnityEditor;
using UnityEditor.Build.Reporting; // using UnityEditor.Build.Reporting;
using UnityEditor.iOS.Xcode; // using UnityEditor.iOS.Xcode;
using System.IO; // using System.IO;
#endif // #endif
namespace BFEditor.Build // namespace BFEditor.Build
{ // {
public static class BuildIOSUtils // public static class BuildIOSUtils
{ // {
#if UNITY_EDITOR_OSX // #if UNITY_EDITOR_OSX
const string IOS_DEFINE_SYMBOLS = "THREAD_SAFE;USE_AB"; // const string IOS_DEFINE_SYMBOLS = "THREAD_SAFE;USE_AB";
const string DEV_XCODE_LOCAL_PATH = "BFVersions/ios/dev"; // const string DEV_XCODE_LOCAL_PATH = "BFVersions/ios/dev";
const string RELEASE_XCODE_LOCAL_PATH = "BFVersions/ios/release"; // const string RELEASE_XCODE_LOCAL_PATH = "BFVersions/ios/release";
static string devXCodePath = Application.dataPath + "/../" + DEV_XCODE_LOCAL_PATH; // static string devXCodePath = Application.dataPath + "/../" + DEV_XCODE_LOCAL_PATH;
static string releaseXCodePath = Application.dataPath + "/../" + RELEASE_XCODE_LOCAL_PATH; // static string releaseXCodePath = Application.dataPath + "/../" + RELEASE_XCODE_LOCAL_PATH;
static string devOptionsPListPath = Application.dataPath + "/../" + "BFVersions/ios/exports/dev/ExportOptions.plist"; // static string devOptionsPListPath = Application.dataPath + "/../" + "BFVersions/ios/exports/dev/ExportOptions.plist";
static string releaseOptionsPListPath = Application.dataPath + "/../" + "BFVersions/ios/exports/release/ExportOptions.plist"; // static string releaseOptionsPListPath = Application.dataPath + "/../" + "BFVersions/ios/exports/release/ExportOptions.plist";
static string publishOptionsPListPath = Application.dataPath + "/../" + "BFVersions/ios/exports/dis/ExportOptions.plist"; // static string publishOptionsPListPath = Application.dataPath + "/../" + "BFVersions/ios/exports/dis/ExportOptions.plist";
public static bool BuildIOSPlayer(BuildInfo buildInfo) // public static bool BuildIOSPlayer(BuildInfo buildInfo)
{ // {
var buildTarget = BuildTarget.iOS; // var buildTarget = BuildTarget.iOS;
// 检查平台 // // 检查平台
if (EditorUserBuildSettings.activeBuildTarget != buildTarget) // if (EditorUserBuildSettings.activeBuildTarget != buildTarget)
{ // {
Debug.LogError("[bferror]当前没有在对应平台"); // Debug.LogError("[bferror]当前没有在对应平台");
return false; // return false;
} // }
// 重新生成XLua // // 重新生成XLua
CompileScriptsUtils.RegenerateXLuaCode(true); // CompileScriptsUtils.RegenerateXLuaCode(true);
// 打包设置 // // 打包设置
BuildSettings(buildInfo); // BuildSettings(buildInfo);
// 开始打包 // // 开始打包
var bpOptions = GetBuildOptions(buildInfo); // var bpOptions = GetBuildOptions(buildInfo);
var report = BuildPipeline.BuildPlayer(bpOptions); // var report = BuildPipeline.BuildPlayer(bpOptions);
if (report.summary.result == BuildResult.Succeeded) // if (report.summary.result == BuildResult.Succeeded)
{ // {
return BuildIpaFromXCode(buildInfo); // return BuildIpaFromXCode(buildInfo);
} // }
else // else
{ // {
Debug.LogError("[bferror]unity打包xcode失败"); // Debug.LogError("[bferror]unity打包xcode失败");
return false; // return false;
} // }
} // }
/// <summary> // /// <summary>
/// 打包设置 // /// 打包设置
/// </summary> // /// </summary>
static void BuildSettings(BuildInfo buildInfo) // static void BuildSettings(BuildInfo buildInfo)
{ // {
// 设置bundleVersion // // 设置bundleVersion
PlayerSettings.bundleVersion = buildInfo.version; // PlayerSettings.bundleVersion = buildInfo.version;
// 设置buildNumber // // 设置buildNumber
PlayerSettings.iOS.buildNumber = buildInfo.version_code.ToString(); // PlayerSettings.iOS.buildNumber = buildInfo.versionCode.ToString();
// 设置竖屏 // // 设置竖屏
PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait; // PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait;
PlayerSettings.allowedAutorotateToPortrait = false; // PlayerSettings.allowedAutorotateToPortrait = false;
PlayerSettings.allowedAutorotateToPortraitUpsideDown = false; // PlayerSettings.allowedAutorotateToPortraitUpsideDown = false;
PlayerSettings.allowedAutorotateToLandscapeLeft = false; // PlayerSettings.allowedAutorotateToLandscapeLeft = false;
PlayerSettings.allowedAutorotateToLandscapeRight = false; // PlayerSettings.allowedAutorotateToLandscapeRight = false;
// 允许Xcode根据appleDeveloperTeamID自动签署应用程序 // // 允许Xcode根据appleDeveloperTeamID自动签署应用程序
PlayerSettings.iOS.appleEnableAutomaticSigning = !buildInfo.IsPublish(); // PlayerSettings.iOS.appleEnableAutomaticSigning = !buildInfo.IsPublish();
// 使用手动签名时iOS资源调配配置文件的类型自动 // // 使用手动签名时iOS资源调配配置文件的类型自动
PlayerSettings.iOS.iOSManualProvisioningProfileType = buildInfo.IsPublish() ? ProvisioningProfileType.Distribution : ProvisioningProfileType.Automatic; // PlayerSettings.iOS.iOSManualProvisioningProfileType = buildInfo.IsPublish() ? ProvisioningProfileType.Distribution : ProvisioningProfileType.Automatic;
// 关闭启动动画 // // 关闭启动动画
PlayerSettings.SplashScreen.show = false; // PlayerSettings.SplashScreen.show = false;
// 设置包名 // // 设置包名
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.iOS, buildInfo.bundleName); // PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.iOS, buildInfo.bundleName);
Debug.Log("[bfinfo]设置包名:" + buildInfo.bundleName); // Debug.Log("[bfinfo]设置包名:" + buildInfo.bundleName);
// 是否跳过版本控制 // // 是否跳过版本控制
var symbols = IOS_DEFINE_SYMBOLS; // var symbols = IOS_DEFINE_SYMBOLS;
if (buildInfo.skipVersion) // if (buildInfo.skipVersion)
{ // {
symbols = symbols + ";SKIP_VERSION;"; // symbols = symbols + ";SKIP_VERSION;";
} // }
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, symbols); // PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, symbols);
Debug.Log("[bfinfo]设置defineSymbols: " + symbols); // Debug.Log("[bfinfo]设置defineSymbols: " + symbols);
// 是否是dev // // 是否是dev
var development = buildInfo.IsDevChannel(); // var development = buildInfo.IsDevChannel();
EditorUserBuildSettings.development = development; // EditorUserBuildSettings.development = development;
// 商品名称 // // 商品名称
if (buildInfo.IsPublish()) // if (buildInfo.IsPublish())
{ // {
PlayerSettings.productName = "Heroic Expedition"; // PlayerSettings.productName = "Heroic Expedition";
} // }
else // else
{ // {
PlayerSettings.productName = development ? "b6-dev" : "b6-release"; // PlayerSettings.productName = development ? "b6-dev" : "b6-release";
} // }
// BuildType设置dev/release // // BuildType设置dev/release
EditorUserBuildSettings.iOSBuildConfigType = development ? iOSBuildType.Debug : iOSBuildType.Release; // EditorUserBuildSettings.iOSXcodeBuildConfig = development ? XcodeBuildConfig.Debug : XcodeBuildConfig.Release;
// 使用IL2CPP // // 使用IL2CPP
var scriptImp = ScriptingImplementation.IL2CPP; // var scriptImp = ScriptingImplementation.IL2CPP;
PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, scriptImp); // PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, scriptImp);
// 目标平台架构目前支持ARM64 // // 目标平台架构目前支持ARM64
PlayerSettings.SetArchitecture(BuildTargetGroup.iOS, 1); // PlayerSettings.SetArchitecture(BuildTargetGroup.iOS, 1);
} // }
/// <summary> // /// <summary>
/// 获取打包参数 // /// 获取打包参数
/// </summary> // /// </summary>
static BuildPlayerOptions GetBuildOptions(BuildInfo buildInfo) // static BuildPlayerOptions GetBuildOptions(BuildInfo buildInfo)
{ // {
var bpOptions = new BuildPlayerOptions(); // var bpOptions = new BuildPlayerOptions();
bpOptions.scenes = AssetBundleUtils.GetBuildScenes(); // bpOptions.scenes = AssetBundleUtils.GetBuildScenes();
bpOptions.target = BuildTarget.iOS; // bpOptions.target = BuildTarget.iOS;
var path = buildInfo.IsReleaseChannel() ? RELEASE_XCODE_LOCAL_PATH : DEV_XCODE_LOCAL_PATH; // var path = buildInfo.IsReleaseChannel() ? RELEASE_XCODE_LOCAL_PATH : DEV_XCODE_LOCAL_PATH;
bpOptions.locationPathName = path; // bpOptions.locationPathName = path;
Debug.Log("[bfinfo]xcode path : " + path); // Debug.Log("[bfinfo]xcode path : " + path);
var absolutePath = buildInfo.IsReleaseChannel() ? releaseXCodePath : devXCodePath; // var absolutePath = buildInfo.IsReleaseChannel() ? releaseXCodePath : devXCodePath;
if (Directory.Exists(absolutePath)) // if (Directory.Exists(absolutePath))
{ // {
Directory.Delete(absolutePath, true); // Directory.Delete(absolutePath, true);
} // }
if (!buildInfo.IsPublish()) // if (!buildInfo.IsPublish())
{ // {
var options = BuildOptions.Development | BuildOptions.ConnectWithProfiler | BuildOptions.AllowDebugging; // var options = BuildOptions.Development | BuildOptions.ConnectWithProfiler | BuildOptions.AllowDebugging;
bpOptions.options = options; // bpOptions.options = options;
} // }
return bpOptions; // return bpOptions;
} // }
/// <summary> // /// <summary>
/// 打包ipa // /// 打包ipa
/// </summary> // /// </summary>
static bool BuildIpaFromXCode(BuildInfo buildInfo) // static bool BuildIpaFromXCode(BuildInfo buildInfo)
{ // {
// 修改XCode设置 // // 修改XCode设置
FixXCodeProject(buildInfo); // FixXCodeProject(buildInfo);
// 权限 // // 权限
UnlockKeyChain(); // UnlockKeyChain();
// archive // // archive
if (!Archive(buildInfo)) // if (!Archive(buildInfo))
{ // {
return false; // return false;
} // }
// 导出ipa // // 导出ipa
if (!ExportIpa(buildInfo)) // if (!ExportIpa(buildInfo))
{ // {
return false; // return false;
} // }
return true; // return true;
} // }
/// <summary> // /// <summary>
/// xCode工程设置 // /// xCode工程设置
/// </summary> // /// </summary>
static void FixXCodeProject(BuildInfo buildInfo) // static void FixXCodeProject(BuildInfo buildInfo)
{ // {
var isDev = buildInfo.IsDevChannel(); // var isDev = buildInfo.IsDevChannel();
var xCodeProjectPath = isDev ? devXCodePath : releaseXCodePath; // var xCodeProjectPath = isDev ? devXCodePath : releaseXCodePath;
var path = xCodeProjectPath + "/Unity-iPhone.xcodeproj/project.pbxproj"; // var path = xCodeProjectPath + "/Unity-iPhone.xcodeproj/project.pbxproj";
var pbxProject = new PBXProject(); // var pbxProject = new PBXProject();
pbxProject.ReadFromFile(path); // pbxProject.ReadFromFile(path);
var targetGuid = pbxProject.TargetGuidByName("Unity-iPhone"); // var targetGuid = pbxProject.TargetGuidByName("Unity-iPhone");
pbxProject.AddBuildProperty(targetGuid, "OTHER_LDFLAGS", "-ObjC"); // pbxProject.AddBuildProperty(targetGuid, "OTHER_LDFLAGS", "-ObjC");
pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO"); // pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO");
pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO"); // pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO");
pbxProject.SetBuildProperty(targetGuid, "DEVELOPMENT_TEAM", "49QQW8856Q"); // pbxProject.SetBuildProperty(targetGuid, "DEVELOPMENT_TEAM", "49QQW8856Q");
if (buildInfo.IsPublish()) // if (buildInfo.IsPublish())
{ // {
pbxProject.SetBuildProperty(targetGuid, "PROVISIONING_PROFILE_SPECIFIER", "ub_appstore_dis"); // pbxProject.SetBuildProperty(targetGuid, "PROVISIONING_PROFILE_SPECIFIER", "ub_appstore_dis");
} // }
// 添加系统库 // // 添加系统库
AddSystemLibReferenceToProject(pbxProject, targetGuid, "libsqlite3.tbd"); // AddSystemLibReferenceToProject(pbxProject, targetGuid, "libsqlite3.tbd");
AddSystemLibReferenceToProject(pbxProject, targetGuid, "libz.1.tbd"); // AddSystemLibReferenceToProject(pbxProject, targetGuid, "libz.1.tbd");
AddSystemLibReferenceToProject(pbxProject, targetGuid, "libiconv.2.tbd"); // AddSystemLibReferenceToProject(pbxProject, targetGuid, "libiconv.2.tbd");
AddSystemLibReferenceToProject(pbxProject, targetGuid, "libresolv.9.tbd"); // AddSystemLibReferenceToProject(pbxProject, targetGuid, "libresolv.9.tbd");
var pListPath = Path.Combine(xCodeProjectPath, "Info.plist"); // var pListPath = Path.Combine(xCodeProjectPath, "Info.plist");
var pList = new PlistDocument(); // var pList = new PlistDocument();
pList.ReadFromFile(pListPath); // pList.ReadFromFile(pListPath);
// 版本号 // // 版本号
var vKey = "CFBundleShortVersionString"; // var vKey = "CFBundleShortVersionString";
var vValue = new PlistElementString(buildInfo.version); // var vValue = new PlistElementString(buildInfo.version);
var pListRoot = pList.root; // var pListRoot = pList.root;
var rootDict = pListRoot.values; // var rootDict = pListRoot.values;
if (!rootDict.ContainsKey(vKey)) // if (!rootDict.ContainsKey(vKey))
{ // {
rootDict.Add(vKey, vValue); // rootDict.Add(vKey, vValue);
} // }
else // else
{ // {
rootDict[vKey] = vValue; // rootDict[vKey] = vValue;
} // }
// VersionCode // // VersionCode
var vCodeKey = "CFBundleVersion"; // var vCodeKey = "CFBundleVersion";
var vCodeValue = new PlistElementString(buildInfo.version_code.ToString()); // var vCodeValue = new PlistElementString(buildInfo.versionCode.ToString());
if (!rootDict.ContainsKey(vCodeKey)) // if (!rootDict.ContainsKey(vCodeKey))
{ // {
rootDict.Add(vCodeKey, vCodeValue); // rootDict.Add(vCodeKey, vCodeValue);
} // }
else // else
{ // {
rootDict[vCodeKey] = vCodeValue; // rootDict[vCodeKey] = vCodeValue;
} // }
// 数美SDK会使用位置必须加入这个说明 // // 数美SDK会使用位置必须加入这个说明
var localtionKey = "NSLocationWhenInUseUsageDescription"; // var localtionKey = "NSLocationWhenInUseUsageDescription";
var localtionValue = new PlistElementString("We use your location to give you a better localization."); // var localtionValue = new PlistElementString("We use your location to give you a better localization.");
if (!rootDict.ContainsKey(localtionKey)) // if (!rootDict.ContainsKey(localtionKey))
{ // {
rootDict.Add(localtionKey, localtionValue); // rootDict.Add(localtionKey, localtionValue);
} // }
else // else
{ // {
rootDict[localtionKey] = localtionValue; // rootDict[localtionKey] = localtionValue;
} // }
// 提审提示缺少出口合规证明,这里直接设置为false即可 // // 提审提示缺少出口合规证明,这里直接设置为false即可
var encryptionKey = "ITSAppUsesNonExemptEncryption"; // var encryptionKey = "ITSAppUsesNonExemptEncryption";
var encryptionValue = new PlistElementBoolean(false); // var encryptionValue = new PlistElementBoolean(false);
if (!rootDict.ContainsKey(encryptionKey)) // if (!rootDict.ContainsKey(encryptionKey))
{ // {
rootDict.Add(encryptionKey, encryptionValue); // rootDict.Add(encryptionKey, encryptionValue);
} // }
else // else
{ // {
rootDict[encryptionKey] = encryptionValue; // rootDict[encryptionKey] = encryptionValue;
} // }
pList.WriteToFile(pListPath); // pList.WriteToFile(pListPath);
pbxProject.WriteToFile(path); // pbxProject.WriteToFile(path);
} // }
//添加系统lib方法 // //添加系统lib方法
static void AddSystemLibReferenceToProject(PBXProject pbxProject, string targetGuid, string lib) // static void AddSystemLibReferenceToProject(PBXProject pbxProject, string targetGuid, string lib)
{ // {
var fileGuid = pbxProject.AddFile("usr/lib/" + lib, "Frameworks/" + lib, PBXSourceTree.Sdk); // var fileGuid = pbxProject.AddFile("usr/lib/" + lib, "Frameworks/" + lib, PBXSourceTree.Sdk);
pbxProject.AddFileToBuild(targetGuid, fileGuid); // pbxProject.AddFileToBuild(targetGuid, fileGuid);
} // }
/// <summary> // /// <summary>
/// Archive // /// Archive
/// </summary> // /// </summary>
static bool Archive(BuildInfo buildInfo) // static bool Archive(BuildInfo buildInfo)
{ // {
Debug.Log("[bfinfo]正在archive..."); // Debug.Log("[bfinfo]正在archive...");
var result = true; // var result = true;
var xCodeProjectPath = buildInfo.IsDevChannel() ? devXCodePath : releaseXCodePath; // var xCodeProjectPath = buildInfo.IsDevChannel() ? devXCodePath : releaseXCodePath;
var archivePath = xCodeProjectPath + "/build/archive/Unity-iPhone.xcarchive"; // var archivePath = xCodeProjectPath + "/build/archive/Unity-iPhone.xcarchive";
var args = string.Format("archive -scheme Unity-iPhone -configuration Release -archivePath {0}", archivePath); // var args = string.Format("archive -scheme Unity-iPhone -configuration Release -archivePath {0}", archivePath);
BFEditorUtils.RunCommond("xcodebuild", args, xCodeProjectPath, // BFEditorUtils.RunCommond("xcodebuild", args, xCodeProjectPath,
(info) => // (info) =>
{ // {
Debug.Log(info); // Debug.Log(info);
}, // },
(error) => // (error) =>
{ // {
if (error.Contains("ARCHIVE FAILED")) // 失败标志 // if (error.Contains("ARCHIVE FAILED")) // 失败标志
{ // {
result = false; // result = false;
} // }
Debug.LogError("[bferror] " + error); // Debug.LogError("[bferror] " + error);
} // }
); // );
return result; // return result;
} // }
/// <summary> // /// <summary>
/// 导出ipa // /// 导出ipa
/// </summary> // /// </summary>
static bool ExportIpa(BuildInfo buildInfo) // static bool ExportIpa(BuildInfo buildInfo)
{ // {
Debug.Log("[bfinfo]正在导出ipa..."); // Debug.Log("[bfinfo]正在导出ipa...");
var result = false; // var result = false;
var xCodeProjectPath = buildInfo.IsDevChannel() ? devXCodePath : releaseXCodePath; // var xCodeProjectPath = buildInfo.IsDevChannel() ? devXCodePath : releaseXCodePath;
string exportPListPath; // string exportPListPath;
if (buildInfo.IsPublish()) // if (buildInfo.IsPublish())
{ // {
exportPListPath = publishOptionsPListPath; // exportPListPath = publishOptionsPListPath;
} // }
else // else
{ // {
exportPListPath = buildInfo.IsDevChannel() ? devOptionsPListPath : releaseOptionsPListPath; // exportPListPath = buildInfo.IsDevChannel() ? devOptionsPListPath : releaseOptionsPListPath;
} // }
var ipaPath = xCodeProjectPath + "/build/ipa"; // var ipaPath = xCodeProjectPath + "/build/ipa";
var archivePath = xCodeProjectPath + "/build/archive/Unity-iPhone.xcarchive"; // var archivePath = xCodeProjectPath + "/build/archive/Unity-iPhone.xcarchive";
var args = string.Format("-exportArchive -archivePath {0} -exportPath {1} -exportOptionsPlist {2} -allowProvisioningUpdates", archivePath, ipaPath, exportPListPath); // var args = string.Format("-exportArchive -archivePath {0} -exportPath {1} -exportOptionsPlist {2} -allowProvisioningUpdates", archivePath, ipaPath, exportPListPath);
BFEditorUtils.RunCommond("xcodebuild", args, null, // BFEditorUtils.RunCommond("xcodebuild", args, null,
(info) => // (info) =>
{ // {
if(info.Contains("EXPORT SUCCEEDED")) // if(info.Contains("EXPORT SUCCEEDED"))
{ // {
result = true; // result = true;
} // }
}, // },
(error) => // (error) =>
{ // {
} // }
); // );
return result; // return result;
} // }
/// <summary> // /// <summary>
/// 远程打包签名ipa时需要钥匙串权限 // /// 远程打包签名ipa时需要钥匙串权限
/// </summary> // /// </summary>
static void UnlockKeyChain() // static void UnlockKeyChain()
{ // {
BFEditorUtils.RunCommond("security", "-v unlock-keychain -p '123456' /Users/aoddabao/Library/Keychains/login.keychain-db", null, // BFEditorUtils.RunCommond("security", "-v unlock-keychain -p '123456' /Users/aoddabao/Library/Keychains/login.keychain-db", null,
(msg) => // (msg) =>
{ // {
Debug.Log(msg); // Debug.Log(msg);
}, // },
(msg) => // (msg) =>
{ // {
Debug.LogError(msg); // Debug.LogError(msg);
} // }
); // );
} // }
#endif // #endif
} // }
} // }

View File

@ -85,6 +85,9 @@ namespace BFEditor
{ {
//加载lua配置测试 //加载lua配置测试
LuaEnv env = new LuaEnv(); LuaEnv env = new LuaEnv();
env.DoString(@"
print(' Lua : ' .. _VERSION) -- Lua 5.1
");
env.AddLoader((ref string scriptPath) => env.AddLoader((ref string scriptPath) =>
{ {
var text = LoadGameLuaScriptText(scriptPath, isDeveloper); var text = LoadGameLuaScriptText(scriptPath, isDeveloper);
@ -136,58 +139,58 @@ namespace BFEditor
var configFileInfos = configDirInfo.GetFiles(suffix, SearchOption.TopDirectoryOnly); var configFileInfos = configDirInfo.GetFiles(suffix, SearchOption.TopDirectoryOnly);
// 检查棋盘文件格式 // 检查棋盘文件格式
checkBoard("chapter_board", env, sb); // checkBoard("chapter_board", env, sb);
checkBoard("chapter_board_bossrush", env, sb); // checkBoard("chapter_board_bossrush", env, sb);
checkBoard("chapter_board_daily_challenge", env, sb); // checkBoard("chapter_board_daily_challenge", env, sb);
checkBoard("chapter_board_dungeon_armor", env, sb); // checkBoard("chapter_board_dungeon_armor", env, sb);
checkBoard("chapter_board_dungeon_equip", env, sb); // checkBoard("chapter_board_dungeon_equip", env, sb);
checkBoard("chapter_board_dungeon_gold", env, sb); // checkBoard("chapter_board_dungeon_gold", env, sb);
checkBoard("chapter_board_dungeon_shards", env, sb); // checkBoard("chapter_board_dungeon_shards", env, sb);
checkBoard("chapter_board_rune", env, sb); // checkBoard("chapter_board_rune", env, sb);
checkBoard("activity_pvp_board", env, sb); // checkBoard("activity_pvp_board", env, sb);
checkBoard("arena_board", env, sb); // checkBoard("arena_board", env, sb);
// 检查monster // 检查monster
string monsterConfigListLua = "{"; // string monsterConfigListLua = "{";
foreach (var file in configFileInfos) // foreach (var file in configFileInfos)
{ // {
var fileName = file.Name.ToLower(); // var fileName = file.Name.ToLower();
if(fileName.Contains("monster_")) // if(fileName.Contains("monster_"))
{ // {
monsterConfigListLua += "'" + fileName.Replace(".lua", "").Replace(".bytes", "") + "',"; // monsterConfigListLua += "'" + fileName.Replace(".lua", "").Replace(".bytes", "") + "',";
} // }
} // }
monsterConfigListLua += "}"; // monsterConfigListLua += "}";
var luaScriptString = "local ids = {}\n local MONSTER_LIST = " + monsterConfigListLua + "\n"; // var luaScriptString = "local ids = {}\n local MONSTER_LIST = " + monsterConfigListLua + "\n";
luaScriptString += @"local str = {} // luaScriptString += @"local str = {}
for i, name in ipairs(MONSTER_LIST) do // for i, name in ipairs(MONSTER_LIST) do
if name ~= 'monster_base' and name ~= 'monster_position' and name ~= 'monster_position_base' then // if name ~= 'monster_base' and name ~= 'monster_position' and name ~= 'monster_position_base' then
local data = require('app/config/' .. name).data // local data = require('app/config/' .. name).data
for k, v in pairs(data) do // for k, v in pairs(data) do
if ids[k] then // if ids[k] then
table.insert(str, name .. '和' .. ids[k] .. 'mosnter id:' .. k) // table.insert(str, name .. '和' .. ids[k] .. '存在相同的mosnter id:' .. k)
end // end
ids[k] = name // ids[k] = name
end // end
end // end
end // end
if #str > 0 then // if #str > 0 then
return table.concat(str, '\n'); // return table.concat(str, '\n');
end // end
return ''"; // return ''";
var resultStr = env.DoString(luaScriptString); // var resultStr = env.DoString(luaScriptString);
if (resultStr.Length > 0) // if (resultStr.Length > 0)
{ // {
foreach(var strObj in resultStr) // foreach(var strObj in resultStr)
{ // {
var str = Convert.ToString(strObj); // var str = Convert.ToString(strObj);
if(!String.IsNullOrEmpty(str)) // if(!String.IsNullOrEmpty(str))
{ // {
sb.Append(str + "\n"); // sb.Append(str + "\n");
} // }
} // }
} // }
// 检查怪物的坐标信息 // 检查怪物的坐标信息
// var luaScriptString2 = @"local MONSTER_POSITION_KEY = { 'monster_1','monster_2','monster_3','monster_4','monster_5','monster_6','monster_7','monster_8','monster_9','monster_10','monster_11','monster_12'} // var luaScriptString2 = @"local MONSTER_POSITION_KEY = { 'monster_1','monster_2','monster_3','monster_4','monster_5','monster_6','monster_7','monster_8','monster_9','monster_10','monster_11','monster_12'}
// local list = {'enemy_id_1', 'enemy_id_2', 'enemy_id_3'} // local list = {'enemy_id_1', 'enemy_id_2', 'enemy_id_3'}

View File

@ -1,117 +1,117 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEditor; using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
namespace BFEditor.Resource namespace BFEditor.Resource
{ {
public class CheckRaycastTargetWindow : EditorWindow public class CheckRaycastTargetWindow : EditorWindow
{ {
ShowRaycast raycastHelper; ShowRaycast raycastHelper;
RectTransform rt; RectTransform rt;
Vector2 scrollPos; Vector2 scrollPos;
CheckRaycastTargetWindow() CheckRaycastTargetWindow()
{ {
this.titleContent = new GUIContent("检查RaycastTarget"); this.titleContent = new GUIContent("检查RaycastTarget");
} }
void OnEnable() void OnEnable()
{ {
PrefabStage currentPrefabStage = PrefabStageUtility.GetCurrentPrefabStage(); UnityEditor.SceneManagement.PrefabStage currentPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
Transform tran; Transform tran;
if (currentPrefabStage == null) if (currentPrefabStage == null)
tran = Selection.activeTransform; tran = Selection.activeTransform;
else else
tran = currentPrefabStage.prefabContentsRoot.transform; tran = currentPrefabStage.prefabContentsRoot.transform;
if (tran != null) if (tran != null)
rt = tran.GetComponent<RectTransform>(); rt = tran.GetComponent<RectTransform>();
if (rt != null) if (rt != null)
{ {
raycastHelper = rt.GetComponent<ShowRaycast>(); raycastHelper = rt.GetComponent<ShowRaycast>();
if (raycastHelper == null) if (raycastHelper == null)
raycastHelper = rt.gameObject.AddComponent<ShowRaycast>(); raycastHelper = rt.gameObject.AddComponent<ShowRaycast>();
raycastHelper.SetEditorWindowMode(true); raycastHelper.SetEditorWindowMode(true);
} }
} }
void OnGUI() void OnGUI()
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
EditorGUI.BeginChangeCheck(); EditorGUI.BeginChangeCheck();
rt = (RectTransform)EditorGUILayout.ObjectField("", rt, typeof(RectTransform), true, GUILayout.Width(200)); rt = (RectTransform)EditorGUILayout.ObjectField("", rt, typeof(RectTransform), true, GUILayout.Width(200));
GUILayout.Space(6); GUILayout.Space(6);
if (EditorGUI.EndChangeCheck()) if (EditorGUI.EndChangeCheck())
{ {
if (raycastHelper != null) if (raycastHelper != null)
DestroyImmediate(raycastHelper); DestroyImmediate(raycastHelper);
if (rt != null) if (rt != null)
{ {
raycastHelper = rt.GetComponent<ShowRaycast>(); raycastHelper = rt.GetComponent<ShowRaycast>();
if (raycastHelper == null) if (raycastHelper == null)
raycastHelper = rt.gameObject.AddComponent<ShowRaycast>(); raycastHelper = rt.gameObject.AddComponent<ShowRaycast>();
raycastHelper.SetEditorWindowMode(true); raycastHelper.SetEditorWindowMode(true);
} }
} }
if (raycastHelper != null) if (raycastHelper != null)
{ {
GUILayout.Label(string.Format("raycastTarget组件一共有 {0} 个", raycastHelper.GetTotalCount())); GUILayout.Label(string.Format("raycastTarget组件一共有 {0} 个", raycastHelper.GetTotalCount()));
GUILayout.Label("(红色)image " + raycastHelper.GetImageCount() + GUILayout.Label("(红色)image " + raycastHelper.GetImageCount() +
" (绿色)text " + raycastHelper.GetTextCount()); " (绿色)text " + raycastHelper.GetTextCount());
GUILayout.Label("(黄色)emptyRaycast " + raycastHelper.GetEmptyCount() + GUILayout.Label("(黄色)emptyRaycast " + raycastHelper.GetEmptyCount() +
" (蓝色)rawImage " + raycastHelper.GetRawImageCount()); " (蓝色)rawImage " + raycastHelper.GetRawImageCount());
GUILayout.Space(6); GUILayout.Space(6);
scrollPos = GUILayout.BeginScrollView(scrollPos, GUILayout.Width(400), GUILayout.Height(270)); scrollPos = GUILayout.BeginScrollView(scrollPos, GUILayout.Width(400), GUILayout.Height(270));
List<string> pathList = raycastHelper.GetImagePathList(); List<string> pathList = raycastHelper.GetImagePathList();
int i = 0; int i = 0;
if (pathList.Count > 0) if (pathList.Count > 0)
{ {
GUILayout.Label("image路径:"); GUILayout.Label("image路径:");
for (; i < pathList.Count; i++) for (; i < pathList.Count; i++)
GUILayout.Label(pathList[i]); GUILayout.Label(pathList[i]);
} }
pathList = raycastHelper.GetTextPathList(); pathList = raycastHelper.GetTextPathList();
i = 0; i = 0;
if (pathList.Count > 0) if (pathList.Count > 0)
{ {
GUILayout.Label("text路径:"); GUILayout.Label("text路径:");
for (; i < pathList.Count; i++) for (; i < pathList.Count; i++)
GUILayout.Label(pathList[i]); GUILayout.Label(pathList[i]);
} }
pathList = raycastHelper.GetEmptyPathList(); pathList = raycastHelper.GetEmptyPathList();
i = 0; i = 0;
if (pathList.Count > 0) if (pathList.Count > 0)
{ {
GUILayout.Label("emptyRaycast路径:"); GUILayout.Label("emptyRaycast路径:");
for (; i < pathList.Count; i++) for (; i < pathList.Count; i++)
GUILayout.Label(pathList[i]); GUILayout.Label(pathList[i]);
} }
pathList = raycastHelper.GetRawImagePathList(); pathList = raycastHelper.GetRawImagePathList();
i = 0; i = 0;
if (pathList.Count > 0) if (pathList.Count > 0)
{ {
GUILayout.Label("rawImage路径:"); GUILayout.Label("rawImage路径:");
for (; i < pathList.Count; i++) for (; i < pathList.Count; i++)
GUILayout.Label(pathList[i]); GUILayout.Label(pathList[i]);
} }
GUILayout.EndScrollView(); GUILayout.EndScrollView();
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
void OnDestroy() void OnDestroy()
{ {
if (raycastHelper != null) if (raycastHelper != null)
DestroyImmediate(raycastHelper); DestroyImmediate(raycastHelper);
} }
//[MenuItem("资源工具/资源检查/检查RaycastTarget", false, 401)] //[MenuItem("资源工具/资源检查/检查RaycastTarget", false, 401)]
public static void OpenWindow() public static void OpenWindow()
{ {
CheckRaycastTargetWindow window = (CheckRaycastTargetWindow)GetWindowWithRect(typeof(CheckRaycastTargetWindow), CheckRaycastTargetWindow window = (CheckRaycastTargetWindow)GetWindowWithRect(typeof(CheckRaycastTargetWindow),
new Rect(Screen.width / 2, Screen.height / 2, 400, 400), true); new Rect(Screen.width / 2, Screen.height / 2, 400, 400), true);
window.Show(); window.Show();
} }
} }
} }

View File

@ -1,206 +1,206 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEditor; using UnityEditor;
using TMPro; using TMPro;
using BFEditor.Resource; using BFEditor.Resource;
using BF; using BF;
namespace BFEditor namespace BFEditor
{ {
public class GameObjectEditer : Editor public class GameObjectEditer : Editor
{ {
static Material CustomUIDefault; static Material CustomUIDefault;
// 重写Text菜单默认取消raycastTarget // 重写Text菜单默认取消raycastTarget
[MenuItem("GameObject/UI/Text", true)] [MenuItem("GameObject/UI/Text", true)]
static bool ValidateUITextMenu() static bool ValidateUITextMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/Text", false)] [MenuItem("GameObject/UI/Text", false)]
static void CreateUIText() static void CreateUIText()
{ {
GameObject go = new GameObject("Text", typeof(UnityEngine.UI.Text)); GameObject go = new GameObject("Text", typeof(UnityEngine.UI.Text));
UnityEngine.UI.Text text = go.GetComponent<UnityEngine.UI.Text>(); UnityEngine.UI.Text text = go.GetComponent<UnityEngine.UI.Text>();
text.raycastTarget = false; text.raycastTarget = false;
text.material = GetCustomDefaultUIMat(); text.material = GetCustomDefaultUIMat();
CheckAndSetUIParent(go.transform); CheckAndSetUIParent(go.transform);
} }
[MenuItem("GameObject/UI/TextMeshPro - Text", true)] [MenuItem("GameObject/UI/TextMeshPro - Text", true)]
static bool ValidateUITextMeshProMenu() static bool ValidateUITextMeshProMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/TextMeshPro - Text", false)] [MenuItem("GameObject/UI/TextMeshPro - Text", false)]
static void CreateUITextMeshPro() static void CreateUITextMeshPro()
{ {
Debug.LogError("请在UI/BF通用控件里创建Text"); Debug.LogError("请在UI/BF通用控件里创建Text");
} }
// 重写Image菜单默认取消raycastTarget // 重写Image菜单默认取消raycastTarget
[MenuItem("GameObject/UI/Image", true)] [MenuItem("GameObject/UI/Image", true)]
static bool ValidateUIImageMenu() static bool ValidateUIImageMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/Image", false)] [MenuItem("GameObject/UI/Image", false)]
static void CreateUIImage() static void CreateUIImage()
{ {
GameObject go = new GameObject("Image", typeof(UnityEngine.UI.Image)); GameObject go = new GameObject("Image", typeof(UnityEngine.UI.Image));
UnityEngine.UI.Image image = go.GetComponent<UnityEngine.UI.Image>(); UnityEngine.UI.Image image = go.GetComponent<UnityEngine.UI.Image>();
image.raycastTarget = false; image.raycastTarget = false;
image.material = GetCustomDefaultUIMat(); image.material = GetCustomDefaultUIMat();
CheckAndSetUIParent(go.transform); CheckAndSetUIParent(go.transform);
} }
[MenuItem("GameObject/UI/BFSlider", false)] [MenuItem("GameObject/UI/BFSlider", false)]
static void CreateBFSlider() static void CreateBFSlider()
{ {
GameObject go = new GameObject("BFSlider", typeof(BFSlider)); GameObject go = new GameObject("BFSlider", typeof(BFSlider));
BFSlider slider = go.GetComponent<BFSlider>(); BFSlider slider = go.GetComponent<BFSlider>();
slider.raycastTarget = false; slider.raycastTarget = false;
slider.material = GetCustomDefaultUIMat(); slider.material = GetCustomDefaultUIMat();
CheckAndSetUIParent(go.transform); CheckAndSetUIParent(go.transform);
} }
[MenuItem("GameObject/UI/Raw Image", true)] [MenuItem("GameObject/UI/Raw Image", true)]
static bool ValidateUIRawImageMenu() static bool ValidateUIRawImageMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/Raw Image", false)] [MenuItem("GameObject/UI/Raw Image", false)]
static void CreateUIRawImage() static void CreateUIRawImage()
{ {
GameObject go = new GameObject("RawImage", typeof(UnityEngine.UI.RawImage)); GameObject go = new GameObject("RawImage", typeof(UnityEngine.UI.RawImage));
UnityEngine.UI.RawImage image = go.GetComponent<UnityEngine.UI.RawImage>(); UnityEngine.UI.RawImage image = go.GetComponent<UnityEngine.UI.RawImage>();
image.raycastTarget = false; image.raycastTarget = false;
image.material = GetCustomDefaultUIMat(); image.material = GetCustomDefaultUIMat();
CheckAndSetUIParent(go.transform); CheckAndSetUIParent(go.transform);
} }
static void CheckAndSetUIParent(Transform uiTransform) static void CheckAndSetUIParent(Transform uiTransform)
{ {
if (Selection.activeTransform) // 当前有选择一个父节点 if (Selection.activeTransform) // 当前有选择一个父节点
{ {
uiTransform.SetParent(Selection.activeTransform, false); uiTransform.SetParent(Selection.activeTransform, false);
} }
else else
{ {
var currentPrefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); var currentPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
if (currentPrefabStage != null) //当前处于prefab编辑模式 if (currentPrefabStage != null) //当前处于prefab编辑模式
{ {
var prefabRoot = currentPrefabStage.prefabContentsRoot; var prefabRoot = currentPrefabStage.prefabContentsRoot;
uiTransform.SetParent(prefabRoot.transform, false); uiTransform.SetParent(prefabRoot.transform, false);
} }
} }
Selection.activeTransform = uiTransform; Selection.activeTransform = uiTransform;
} }
static Material GetCustomDefaultUIMat() static Material GetCustomDefaultUIMat()
{ {
if (CustomUIDefault == null) if (CustomUIDefault == null)
CustomUIDefault = AssetDatabase.LoadAssetAtPath<Material>(ResourceProcessConfig.CUSTOM_DEFAULT_UI_MAT_PATH); CustomUIDefault = AssetDatabase.LoadAssetAtPath<Material>(ResourceProcessConfig.CUSTOM_DEFAULT_UI_MAT_PATH);
return CustomUIDefault; return CustomUIDefault;
} }
[MenuItem("GameObject/UI/Button", true)] [MenuItem("GameObject/UI/Button", true)]
static bool ValidateUIButtonMenu() static bool ValidateUIButtonMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/Button", false)] [MenuItem("GameObject/UI/Button", false)]
static void CreateUIButton() static void CreateUIButton()
{ {
Debug.LogError("请在UI/BF通用控件里创建Button"); Debug.LogError("请在UI/BF通用控件里创建Button");
} }
[MenuItem("GameObject/UI/Button - TextMeshPro", true)] [MenuItem("GameObject/UI/Button - TextMeshPro", true)]
static bool ValidateUIButtonTMPMenu() static bool ValidateUIButtonTMPMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/Button - TextMeshPro", false)] [MenuItem("GameObject/UI/Button - TextMeshPro", false)]
static void CreateUIButtonTMP() static void CreateUIButtonTMP()
{ {
Debug.LogError("请在UI/BF通用控件里创建Button"); Debug.LogError("请在UI/BF通用控件里创建Button");
} }
[MenuItem("GameObject/UI/Text - TextMeshPro", true)] [MenuItem("GameObject/UI/Text - TextMeshPro", true)]
static bool ValidateUITextTMPMenu() static bool ValidateUITextTMPMenu()
{ {
return true; return true;
} }
[MenuItem("GameObject/UI/Text - TextMeshPro", false)] [MenuItem("GameObject/UI/Text - TextMeshPro", false)]
static void CreateUITextTMP() static void CreateUITextTMP()
{ {
Debug.LogError("请在UI/BF通用控件里创建Text"); Debug.LogError("请在UI/BF通用控件里创建Text");
} }
[MenuItem("GameObject/UI/BF通用控件/Button")] [MenuItem("GameObject/UI/BF通用控件/Button")]
static void CreateBFCommonButton() static void CreateBFCommonButton()
{ {
GameObject go = new GameObject("Button", typeof(UnityEngine.UI.Image)); GameObject go = new GameObject("Button", typeof(UnityEngine.UI.Image));
UnityEngine.UI.Image image = go.GetComponent<UnityEngine.UI.Image>(); UnityEngine.UI.Image image = go.GetComponent<UnityEngine.UI.Image>();
image.material = GetCustomDefaultUIMat(); image.material = GetCustomDefaultUIMat();
go.AddComponent<BF.UITouchEvent>(); go.AddComponent<BF.UITouchEvent>();
CheckAndSetUIParent(go.transform); CheckAndSetUIParent(go.transform);
} }
[MenuItem("GameObject/UI/BF通用控件/Text")] [MenuItem("GameObject/UI/BF通用控件/Text")]
static void CreateBFCommonText() static void CreateBFCommonText()
{ {
if (TMP_Settings.defaultFontAsset == null) if (TMP_Settings.defaultFontAsset == null)
{ {
var tmpSettings = TMP_Settings.instance; var tmpSettings = TMP_Settings.instance;
var type = tmpSettings.GetType(); var type = tmpSettings.GetType();
var fontAssetField = type.GetField("m_defaultFontAsset", System.Reflection.BindingFlags.Instance | var fontAssetField = type.GetField("m_defaultFontAsset", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic); System.Reflection.BindingFlags.NonPublic);
var fontAssets = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(ResourceProcessConfig.DEFAULT_TMP_FONTASSET_PATH); var fontAssets = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(ResourceProcessConfig.DEFAULT_TMP_FONTASSET_PATH);
fontAssetField.SetValue(tmpSettings, fontAssets); fontAssetField.SetValue(tmpSettings, fontAssets);
AssetDatabase.Refresh(); AssetDatabase.Refresh();
} }
GameObject go = new GameObject("TextMeshPro", typeof(TMPro.TextMeshProUGUI)); GameObject go = new GameObject("TextMeshPro", typeof(TMPro.TextMeshProUGUI));
TMPro.TextMeshProUGUI textMeshPro = go.GetComponent<TMPro.TextMeshProUGUI>(); TMPro.TextMeshProUGUI textMeshPro = go.GetComponent<TMPro.TextMeshProUGUI>();
textMeshPro.raycastTarget = false; textMeshPro.raycastTarget = false;
var font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>( var font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(
"Assets/arts/fonts/tmpfonts/default/tmpfont/font_sdf.asset"); "Assets/arts/fonts/tmpfonts/default/tmpfont/font_sdf.asset");
textMeshPro.font = font; textMeshPro.font = font;
textMeshPro.material = GetCustomDefaultUIMat(); textMeshPro.material = GetCustomDefaultUIMat();
textMeshPro.enableWordWrapping = false; textMeshPro.enableWordWrapping = false;
CheckAndSetUIParent(go.transform); CheckAndSetUIParent(go.transform);
if (TMP_Settings.defaultFontAsset != null) if (TMP_Settings.defaultFontAsset != null)
{ {
var tmpSettings = TMP_Settings.instance; var tmpSettings = TMP_Settings.instance;
var type = tmpSettings.GetType(); var type = tmpSettings.GetType();
var fontAssetField = type.GetField("m_defaultFontAsset", System.Reflection.BindingFlags.Instance | var fontAssetField = type.GetField("m_defaultFontAsset", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic); System.Reflection.BindingFlags.NonPublic);
fontAssetField.SetValue(tmpSettings, null); fontAssetField.SetValue(tmpSettings, null);
AssetDatabase.Refresh(); AssetDatabase.Refresh();
} }
} }
[MenuItem("GameObject/UI/创建序列帧")] [MenuItem("GameObject/UI/创建序列帧")]
static void CreateFrameAnimation() static void CreateFrameAnimation()
{ {
FrameAnimationTools.CreateFrameAnimation(); FrameAnimationTools.CreateFrameAnimation();
} }
[MenuItem("GameObject/UI/创建序列帧(父节点)")] [MenuItem("GameObject/UI/创建序列帧(父节点)")]
static void CreateFrameAnimationInParent() static void CreateFrameAnimationInParent()
{ {
FrameAnimationTools.CreateFrameAnimation(true); FrameAnimationTools.CreateFrameAnimation(true);
} }
} }
} }

View File

@ -1,93 +1,93 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using BFEditor.Build; using BFEditor.Build;
public class JenkinsAdapter { public class JenkinsAdapter {
/// <summary> /// <summary>
/// 构建版本号 /// 构建版本号
/// </summary> /// </summary>
private static string BuildVersion = (int.Parse(DateTime.Now.ToString("yyMMddHH"))).ToString(); private static string BuildVersion = (int.Parse(DateTime.Now.ToString("yyMMddHH"))).ToString();
private static int versionCode = 10; private static int versionCode = 10;
private static string versionName = "1.4.0"; private static string versionName = "1.4.0";
[MenuItem("Jenkins/JenkinsBuildIos")] [MenuItem("Jenkins/JenkinsBuildIos")]
public static void CommandLineBuildIos() { public static void CommandLineBuildIos() {
var buildInfo = new BuildInfo(); var buildInfo = new BuildInfo();
buildInfo.version = versionName; buildInfo.version = versionName;
buildInfo.mode = "publish_release"; buildInfo.mode = "publish_release";
buildInfo.bundleName = "com.combo.heroes.puzzle.rpg"; buildInfo.bundleName = "com.combo.heroes.puzzle.rpg";
buildInfo.skipVersion = false; buildInfo.skipVersion = false;
BuildProjectTools.BuildResources(buildInfo, Application.streamingAssetsPath, true); BuildProjectTools.BuildResources(buildInfo, Application.streamingAssetsPath, true);
// 重新生成XLua // 重新生成XLua
CompileScriptsUtils.RegenerateXLuaCode(true); CompileScriptsUtils.RegenerateXLuaCode(true);
// 设置版本号 // 设置版本号
PlayerSettings.bundleVersion = buildInfo.version; PlayerSettings.bundleVersion = buildInfo.version;
//SDK要求 //SDK要求
PlayerSettings.iOS.targetOSVersionString = "12.0"; PlayerSettings.iOS.targetOSVersionString = "12.0";
//设置Build每次需要增加 //设置Build每次需要增加
PlayerSettings.iOS.buildNumber = versionCode.ToString(); PlayerSettings.iOS.buildNumber = versionCode.ToString();
// 隐藏ios的横条 // 隐藏ios的横条
PlayerSettings.iOS.hideHomeButton = false; PlayerSettings.iOS.hideHomeButton = false;
// 禁止在所有边缘上延迟手势 // 禁止在所有边缘上延迟手势
PlayerSettings.iOS.deferSystemGesturesMode = UnityEngine.iOS.SystemGestureDeferMode.All; PlayerSettings.iOS.deferSystemGesturesMode = UnityEngine.iOS.SystemGestureDeferMode.All;
// 设置竖屏 // 设置竖屏
PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait; PlayerSettings.defaultInterfaceOrientation = UIOrientation.Portrait;
PlayerSettings.allowedAutorotateToPortrait = false; PlayerSettings.allowedAutorotateToPortrait = false;
PlayerSettings.allowedAutorotateToPortraitUpsideDown = false; PlayerSettings.allowedAutorotateToPortraitUpsideDown = false;
PlayerSettings.allowedAutorotateToLandscapeLeft = false; PlayerSettings.allowedAutorotateToLandscapeLeft = false;
PlayerSettings.allowedAutorotateToLandscapeRight = false; PlayerSettings.allowedAutorotateToLandscapeRight = false;
// 关闭启动动画 // 关闭启动动画
PlayerSettings.SplashScreen.show = false; PlayerSettings.SplashScreen.show = false;
// 设置包名 // 设置包名
PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.iOS, buildInfo.bundleName); PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.iOS, buildInfo.bundleName);
// 是否跳过版本控制 // 是否跳过版本控制
var symbols = "THREAD_SAFE;USE_AB"; var symbols = "THREAD_SAFE;USE_AB";
if (buildInfo.skipVersion) if (buildInfo.skipVersion)
{ {
symbols = symbols + ";SKIP_VERSION;"; symbols = symbols + ";SKIP_VERSION;";
} }
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, symbols); PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, symbols);
// 商品名称 // 商品名称
PlayerSettings.productName = "Knights Combo"; PlayerSettings.productName = "Knights Combo";
// BuildType设置dev/release // BuildType设置dev/release
EditorUserBuildSettings.iOSBuildConfigType = iOSBuildType.Release; EditorUserBuildSettings.iOSXcodeBuildConfig = XcodeBuildConfig.Release;
EditorUserBuildSettings.development = false; EditorUserBuildSettings.development = false;
// 使用IL2CPP // 使用IL2CPP
var scriptImp = ScriptingImplementation.IL2CPP; var scriptImp = ScriptingImplementation.IL2CPP;
PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, scriptImp); PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, scriptImp);
// 目标平台架构目前支持ARM64 // 目标平台架构目前支持ARM64
PlayerSettings.SetArchitecture(BuildTargetGroup.iOS, 1); PlayerSettings.SetArchitecture(BuildTargetGroup.iOS, 1);
// 开始打包 // 开始打包
BuildPipeline.BuildPlayer(GetBuildScenes(), GetIosBuildPath(), BuildTarget.iOS, BuildOptions.None); BuildPipeline.BuildPlayer(GetBuildScenes(), GetIosBuildPath(), BuildTarget.iOS, BuildOptions.None);
Console.WriteLine("Build Complete Path:" + GetIosBuildPath()); Console.WriteLine("Build Complete Path:" + GetIosBuildPath());
} }
/// <summary> /// <summary>
/// 获取build Setting 列表里的打勾场景 /// 获取build Setting 列表里的打勾场景
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private static string[] GetBuildScenes() { private static string[] GetBuildScenes() {
List<string> names = new List<string>(); List<string> names = new List<string>();
foreach (var x in EditorBuildSettings.scenes) { foreach (var x in EditorBuildSettings.scenes) {
if (!x.enabled) continue; if (!x.enabled) continue;
names.Add(x.path); names.Add(x.path);
} }
return names.ToArray(); return names.ToArray();
} }
#region Get Build Path #region Get Build Path
private static string GetIosBuildPath() { private static string GetIosBuildPath() {
return "build/iOS"; return "build/iOS";
} }
#endregion #endregion
} }

File diff suppressed because it is too large Load Diff

View File

@ -14,19 +14,26 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
defaultScale: 0.01 defaultScale: 0.01
defaultMix: 0.2 defaultMix: 0.2
defaultShader: BF/Spine/Skeleton defaultShader: Spine/Skeleton
defaultZSpacing: 0 defaultZSpacing: 0
defaultInstantiateLoop: 1 defaultInstantiateLoop: 1
defaultPhysicsPositionInheritance: {x: 1, y: 1}
defaultPhysicsRotationInheritance: 1
showHierarchyIcons: 1 showHierarchyIcons: 1
reloadAfterPlayMode: 1
setTextureImporterSettings: 1 setTextureImporterSettings: 1
textureSettingsReference: Assets/ThirdParty/Spine/Editor/spine-unity/Editor/ImporterPresets/PMATexturePreset.preset textureSettingsReference: Assets/ThirdParty/Spine/Editor/spine-unity/Editor/ImporterPresets/PMATexturePreset.preset
fixPrefabOverrideViaMeshFilter: 0
removePrefabPreviewMeshes: 0
blendModeMaterialMultiply: {fileID: 0} blendModeMaterialMultiply: {fileID: 0}
blendModeMaterialScreen: {fileID: 0} blendModeMaterialScreen: {fileID: 0}
blendModeMaterialAdditive: {fileID: 0} blendModeMaterialAdditive: {fileID: 0}
atlasTxtImportWarning: 1 atlasTxtImportWarning: 1
textureImporterWarning: 1 textureImporterWarning: 1
componentMaterialWarning: 1 componentMaterialWarning: 1
skeletonDataAssetNoFileError: 1
autoReloadSceneSkeletons: 1 autoReloadSceneSkeletons: 1
handleScale: 1 handleScale: 1
mecanimEventIncludeFolderName: 1 mecanimEventIncludeFolderName: 1
timelineDefaultMixDuration: 0
timelineUseBlendDuration: 1 timelineUseBlendDuration: 1

View File

@ -78,6 +78,7 @@ namespace BFEditor
psi.RedirectStandardOutput = true; //由调用程序获取输出信息 psi.RedirectStandardOutput = true; //由调用程序获取输出信息
psi.RedirectStandardError = true; //重定向标准错误输出 psi.RedirectStandardError = true; //重定向标准错误输出
psi.CreateNoWindow = true; //不显示程序窗口 psi.CreateNoWindow = true; //不显示程序窗口
psi.StandardOutputEncoding = System.Text.Encoding.UTF8; // 核心指定UTF-8解码
p.StartInfo = psi; p.StartInfo = psi;
p.Start(); p.Start();

View File

@ -23,7 +23,8 @@ namespace AudienceNetwork
public partial class AdManager : BF.MonoSingleton<AdManager> public partial class AdManager : BF.MonoSingleton<AdManager>
{ {
private const string Tag = "AdManager:"; private const string Tag = "AdManager:";
private const string Key = "9uHgeBwag3NXva9MC23ToO3q11Ve59bF1uwg4qGltdGmCQ7OSByFZ_3b1ZF7krMlkHQo5gXzIokVDsvg1rwbr-"; // private const string Key = "9uHgeBwag3NXva9MC23ToO3q11Ve59bF1uwg4qGltdGmCQ7OSByFZ_3b1ZF7krMlkHQo5gXzIokVDsvg1rwbr-";
private const string Key = "9uHgeBwag3NXva9MC23ToO3q11Ve59bF1uwg4qGltdGmCQ7OSByFZ_3b1ZF7krMlkHQo5gXzIokVDsvg1rwbr-11";
string bannerAdUnitId = "YOUR_BANNER_AD_UNIT_ID"; // Retrieve the ID from your account string bannerAdUnitId = "YOUR_BANNER_AD_UNIT_ID"; // Retrieve the ID from your account
string adInterstitialUnitId = "YOUR_AD_UNIT_ID"; string adInterstitialUnitId = "YOUR_AD_UNIT_ID";
string adRewardUnitId = "e54f27e345da90df"; string adRewardUnitId = "e54f27e345da90df";

View File

@ -9,9 +9,9 @@ namespace BF
{ {
public class BFThirdReportSDKManager : MonoBehaviour public class BFThirdReportSDKManager : MonoBehaviour
{ {
private ThinkingAnalyticsSdk TASdk = new ThinkingAnalyticsSdk(); // private ThinkingAnalyticsSdk TASdk = new ThinkingAnalyticsSdk();
private AppsFlyerSdk AFSdk = new AppsFlyerSdk(); // private AppsFlyerSdk AFSdk = new AppsFlyerSdk();
private bool isInitAFAdRevenue = false; // private bool isInitAFAdRevenue = false;
void Start() void Start()
{ {
@ -21,147 +21,147 @@ namespace BF
public void Init() public void Init()
{ {
BFLog.Log("TASdk.Init"); BFLog.Log("TASdk.Init");
TASdk.Init(); // TASdk.Init();
AFSdk.Init(); // AFSdk.Init();
} }
// 设置账户id // 设置账户id
public void SetThinkingAnalyticsAccountId(string id) public void SetThinkingAnalyticsAccountId(string id)
{ {
TASdk.SetAccountId(id); // TASdk.SetAccountId(id);
AFSdk.SetTaAccountId(id); // AFSdk.SetTaAccountId(id);
} }
public void InitAppsFlyerAdRevenue() public void InitAppsFlyerAdRevenue()
{ {
if (isInitAFAdRevenue) // if (isInitAFAdRevenue)
{ // {
return; // return;
} // }
isInitAFAdRevenue = true; // isInitAFAdRevenue = true;
AppsFlyerAdRevenue.start(); // AppsFlyerAdRevenue.start();
} }
// 清除账户id // 清除账户id
public void ClearThinkingAnalyticsAccountId() public void ClearThinkingAnalyticsAccountId()
{ {
TASdk.ClearAccountId(); // TASdk.ClearAccountId();
} }
// 数数科技上报 // 数数科技上报
// lua端使用 // lua端使用
public void PostThinkingAnalyticsEvent(string eventName, string data = "") public void PostThinkingAnalyticsEvent(string eventName, string data = "")
{ {
if (string.IsNullOrEmpty(data)) // if (string.IsNullOrEmpty(data))
{ // {
TASdk.Track(eventName, null); // TASdk.Track(eventName, null);
} // }
else // else
{ // {
var properties = JsonConvert.DeserializeObject<Dictionary<string, object>>(data); // var properties = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
TASdk.Track(eventName, properties); // TASdk.Track(eventName, properties);
} // }
} }
// 数数科技上报 // 数数科技上报
// c#端使用,只上报事件名 // c#端使用,只上报事件名
public void PostThinkingAnalyticsEventName(string eventName) public void PostThinkingAnalyticsEventName(string eventName)
{ {
TASdk.Track(eventName, null); // TASdk.Track(eventName, null);
} }
// 数数科技上报 // 数数科技上报
// c#端使用,上报事件名和参数 // c#端使用,上报事件名和参数
public void PostThinkingAnalyticsEventProperties(string eventName, Dictionary<string, object> properties) public void PostThinkingAnalyticsEventProperties(string eventName, Dictionary<string, object> properties)
{ {
TASdk.Track(eventName, properties); // TASdk.Track(eventName, properties);
} }
public void PostAppsflyerEvent(string eventName, string data = "") public void PostAppsflyerEvent(string eventName, string data = "")
{ {
if (string.IsNullOrEmpty(data)) // if (string.IsNullOrEmpty(data))
{ // {
AFSdk.SendEvent(eventName, null); // AFSdk.SendEvent(eventName, null);
} // }
else // else
{ // {
var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); // var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
AFSdk.SendEvent(eventName, properties); // AFSdk.SendEvent(eventName, properties);
} // }
} }
public void PostFireBaseEvent(string eventName, string data = "") public void PostFireBaseEvent(string eventName, string data = "")
{ {
if (string.IsNullOrEmpty(data)) // if (string.IsNullOrEmpty(data))
{ // {
return; // return;
} // }
else // else
{ // {
BFMain.Instance.SDKMgr.BFNativeSDKMgr.LogEvent(eventName, data); // BFMain.Instance.SDKMgr.BFNativeSDKMgr.LogEvent(eventName, data);
} // }
} }
// 设置账户id // 设置账户id
public void PostAdjustSimpleTrackEvent(string key) public void PostAdjustSimpleTrackEvent(string key)
{ {
AdjustEvent adjustEvent = new AdjustEvent(key); // AdjustEvent adjustEvent = new AdjustEvent(key);
// BFLog.Log("PostAdjustSimpleTrackEvent"); // // BFLog.Log("PostAdjustSimpleTrackEvent");
Adjust.trackEvent(adjustEvent); // Adjust.trackEvent(adjustEvent);
} }
public void PostAdjustRevenueTrackEvent(string key, double currency, string currencyCode) public void PostAdjustRevenueTrackEvent(string key, double currency, string currencyCode)
{ {
AdjustEvent adjustEvent = new AdjustEvent(key); // AdjustEvent adjustEvent = new AdjustEvent(key);
adjustEvent.setRevenue(currency, currencyCode); // adjustEvent.setRevenue(currency, currencyCode);
// BFLog.Log("PostAdjustRevenueTrackEvent"); // // BFLog.Log("PostAdjustRevenueTrackEvent");
Adjust.trackEvent(adjustEvent); // Adjust.trackEvent(adjustEvent);
} }
public void PostAdjustCallbackTrackEvent(string key, string data = "") public void PostAdjustCallbackTrackEvent(string key, string data = "")
{ {
var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); // var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
AdjustEvent adjustEvent = new AdjustEvent(key); // AdjustEvent adjustEvent = new AdjustEvent(key);
foreach (var item in properties) // foreach (var item in properties)
{ // {
adjustEvent.addCallbackParameter(item.Key, item.Value); // adjustEvent.addCallbackParameter(item.Key, item.Value);
} // }
// BFLog.Log("PostAdjustCallbackTrackEvent"); // // BFLog.Log("PostAdjustCallbackTrackEvent");
Adjust.trackEvent(adjustEvent); // Adjust.trackEvent(adjustEvent);
} }
public void PostAdjustPartnerTrackEvent(string key, string data = "") public void PostAdjustPartnerTrackEvent(string key, string data = "")
{ {
var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); // var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
AdjustEvent adjustEvent = new AdjustEvent(key); // AdjustEvent adjustEvent = new AdjustEvent(key);
foreach (var item in properties) // foreach (var item in properties)
{ // {
adjustEvent.addPartnerParameter(item.Key, item.Value); // adjustEvent.addPartnerParameter(item.Key, item.Value);
} // }
// BFLog.Log("PostAdjustPartnerTrackEvent"); // // BFLog.Log("PostAdjustPartnerTrackEvent");
Adjust.trackEvent(adjustEvent); // Adjust.trackEvent(adjustEvent);
} }
public void PostAdjustAdRevenueAppLovinMAX(double revenue, string networkName, string adUnitIdentifier, string placement) public void PostAdjustAdRevenueAppLovinMAX(double revenue, string networkName, string adUnitIdentifier, string placement)
{ {
var adRevenue = new AdjustAdRevenue(AdjustConfig.AdjustAdRevenueSourceAppLovinMAX); // var adRevenue = new AdjustAdRevenue(AdjustConfig.AdjustAdRevenueSourceAppLovinMAX);
adRevenue.setRevenue(revenue, "USD"); // adRevenue.setRevenue(revenue, "USD");
adRevenue.setAdRevenueNetwork(networkName); // adRevenue.setAdRevenueNetwork(networkName);
adRevenue.setAdRevenueUnit(adUnitIdentifier); // adRevenue.setAdRevenueUnit(adUnitIdentifier);
adRevenue.setAdRevenuePlacement(placement); // adRevenue.setAdRevenuePlacement(placement);
Adjust.trackAdRevenue(adRevenue); // Adjust.trackAdRevenue(adRevenue);
} }
public void AdjustSetDeviceToken(string token) public void AdjustSetDeviceToken(string token)
{ {
Adjust.setDeviceToken(token); // Adjust.setDeviceToken(token);
} }
public void LogAppsFlyerAdRevenue(int mediationNetwork, string monetizationNetwork, double eventRevenue, string data) public void LogAppsFlyerAdRevenue(int mediationNetwork, string monetizationNetwork, double eventRevenue, string data)
{ {
var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); // var properties = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
var mediationNetworkType = (AppsFlyerAdRevenueMediationNetworkType)mediationNetwork; // var mediationNetworkType = (AppsFlyerAdRevenueMediationNetworkType)mediationNetwork;
AppsFlyerAdRevenue.logAdRevenue(monetizationNetwork, mediationNetworkType, eventRevenue, "USD", properties); // AppsFlyerAdRevenue.logAdRevenue(monetizationNetwork, mediationNetworkType, eventRevenue, "USD", properties);
} }
} }
} }

View File

@ -62,7 +62,7 @@ namespace BF
public BFPaySDKManager BFPaySDKMgr { get; private set; } public BFPaySDKManager BFPaySDKMgr { get; private set; }
public IAPManager IosPaySDKMgr { get; private set; } public IAPManager IosPaySDKMgr { get; private set; }
// public BFAdmobSDKManager BFAdmobSDKMgr { get; private set; } // public BFAdmobSDKManager BFAdmobSDKMgr { get; private set; }
public BFIronSourceSDKManager BFIronSourceSDKMgr { get; private set; } // public BFIronSourceSDKManager BFIronSourceSDKMgr { get; private set; }
public BFNativeSDKManager BFNativeSDKMgr { get; private set; } public BFNativeSDKManager BFNativeSDKMgr { get; private set; }
public BFThirdReportSDKManager BFThirdReportSDKMgr { get; private set; } public BFThirdReportSDKManager BFThirdReportSDKMgr { get; private set; }
@ -91,12 +91,12 @@ namespace BF
BFPaySDKMgr = sdkGo.AddComponent<BFPaySDKManager>(); BFPaySDKMgr = sdkGo.AddComponent<BFPaySDKManager>();
// 广告 // 广告
// BFAdmobSDKMgr = sdkGo.AddComponent<BFAdmobSDKManager>(); // BFAdmobSDKMgr = sdkGo.AddComponent<BFAdmobSDKManager>();
BFIronSourceSDKMgr = sdkGo.AddComponent<BFIronSourceSDKManager>(); // BFIronSourceSDKMgr = sdkGo.AddComponent<BFIronSourceSDKManager>();
// 三方上报 // // 三方上报
BFThirdReportSDKMgr = sdkGo.AddComponent<BFThirdReportSDKManager>(); BFThirdReportSDKMgr = sdkGo.AddComponent<BFThirdReportSDKManager>();
// native交互管理 // native交互管理
BFNativeSDKMgr = sdkGo.AddComponent<BFNativeSDKManager>(); BFNativeSDKMgr = sdkGo.AddComponent<BFNativeSDKManager>();
IosPaySDKMgr = IAPManager.Instance; // IosPaySDKMgr = IAPManager.Instance;
GameObject.DontDestroyOnLoad(sdkGo); GameObject.DontDestroyOnLoad(sdkGo);
} }

View File

@ -0,0 +1,53 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BF
{
public class BattleControlBg : MonoBehaviour
{
public float speed = 0.0f;
public float endX = 0.0f;
public float resetX = 0.0f;
public int type = 0;
public bool canMove = true;
public void SetPositionByTime(float time)
{
var transformRect = GetComponent<RectTransform>();
transformRect.anchoredPosition = new Vector2(transformRect.anchoredPosition.x + speed * time, transformRect.anchoredPosition.y);
}
void FixedUpdate()
{
if (!canMove) return;
var transformRect = GetComponent<RectTransform>();
if (transformRect.anchoredPosition.x <= endX)
{
transformRect.anchoredPosition = new Vector2(resetX, transformRect.anchoredPosition.y);
}
// if (type == 1)
// {
// speed = BF.BFMain.Instance.BattleMgr.SceneSpeedC;
// }
// else if (type == 2)
// {
// speed = BF.BFMain.Instance.BattleMgr.SceneSpeedM;
// }
// else if (type == 3)
// {
// speed = BF.BFMain.Instance.BattleMgr.SceneSpeedF;
// }
// else if (type == 4)
// {
// speed = BF.BFMain.Instance.BattleMgr.SceneSpeedCould;
// }
// else if (type == 5)
// {
// speed = BF.BFMain.Instance.BattleMgr.SceneSpeedBg;
// }
// transform.Translate(speed * Time.fixedDeltaTime, 0.0f, 0.0f);
transformRect.anchoredPosition = new Vector2(transformRect.anchoredPosition.x + speed * Time.fixedDeltaTime, transformRect.anchoredPosition.y);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1025633752bc248dc9665067e756f919
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -64,12 +64,12 @@ namespace BF
public partial class BFPlatform public partial class BFPlatform
{ {
const String LoginCenterURL = "https://entrance.bigfoot-studio.link"; const String LoginCenterURL = "https://entrance.wdd817.link";
static Dictionary<string, string> BFLoginCenterURLDict = new Dictionary<string, string>() static Dictionary<string, string> BFLoginCenterURLDict = new Dictionary<string, string>()
{ {
// dev // dev
{"com.juzu.b6.dev", "http://game.juzugame.com:3000"}, {"com.juzu.b6.dev", "https://entrance.wdd817.link"},
{"com.juzu.b6.dev.android", "http://game.juzugame.com:3000"}, {"com.juzu.b6.dev.android", "https://entrance.wdd817.link"},
{"com.juzu.b6.dev.ios", "http://game.juzugame.com:3000"}, {"com.juzu.b6.dev.ios", "http://game.juzugame.com:3000"},
// release // release
@ -77,7 +77,7 @@ namespace BF
{"com.juzu.b6.release.ios", "http://game.juzugame.com:3000"}, {"com.juzu.b6.release.ios", "http://game.juzugame.com:3000"},
// gp // gp
{"com.combo.heroes.puzzle.rpg", "https://entrance.bigfoot-studio.link"}, {"com.combo.heroes.puzzle.rpg", "https://entrance.wdd817.link"},
}; };
//combine url解析的数据 //combine url解析的数据

View File

@ -37,6 +37,20 @@ namespace BF
public const bool SKIP_VERSION = false; public const bool SKIP_VERSION = false;
#endif #endif
#if BF_APP_DEV
public const bool BF_APP_DEV = true;
public const bool BF_APP_TEST = false;
public const bool BF_APP_PUBLISH = false;
#elif BF_APP_TEST
public const bool BF_APP_DEV = false;
public const bool BF_APP_TEST = true;
public const bool BF_APP_PUBLISH = false;
#else
public const bool BF_APP_DEV = false;
public const bool BF_APP_TEST = false;
public const bool BF_APP_PUBLISH = true;
#endif
public static char[] C_FREE_CHAR = new char[16] { public static char[] C_FREE_CHAR = new char[16] {
(char)('g' ^ (0x29 - 0)), (char)('g' ^ (0x29 - 0)),
(char)('w' ^ (0x29 - 1)), (char)('w' ^ (0x29 - 1)),

View File

@ -1,108 +1,103 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: de1fb4dac677a6d45ae2ad12a49091c0 guid: de1fb4dac677a6d45ae2ad12a49091c0
TextureImporter: TextureImporter:
internalIDToNameTable: [] internalIDToNameTable: []
externalObjects: {} externalObjects: {}
serializedVersion: 11 serializedVersion: 10
mipmaps: mipmaps:
mipMapMode: 0 mipMapMode: 0
enableMipMap: 0 enableMipMap: 0
sRGBTexture: 1 sRGBTexture: 1
linearTexture: 0 linearTexture: 0
fadeOut: 0 fadeOut: 0
borderMipMap: 0 borderMipMap: 0
mipMapsPreserveCoverage: 0 mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5 alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1 mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3 mipMapFadeDistanceEnd: 3
bumpmap: bumpmap:
convertToNormalMap: 0 convertToNormalMap: 0
externalNormalMap: 0 externalNormalMap: 0
heightScale: 0.25 heightScale: 0.25
normalMapFilter: 0 normalMapFilter: 0
isReadable: 0 isReadable: 0
streamingMipmaps: 0 streamingMipmaps: 0
streamingMipmapsPriority: 0 streamingMipmapsPriority: 0
vTOnly: 0 grayScaleToAlpha: 0
grayScaleToAlpha: 0 generateCubemap: 6
generateCubemap: 6 cubemapConvolution: 0
cubemapConvolution: 0 seamlessCubemap: 0
seamlessCubemap: 0 textureFormat: 1
textureFormat: 1 maxTextureSize: 2048
maxTextureSize: 2048 textureSettings:
textureSettings: serializedVersion: 2
serializedVersion: 2 filterMode: -1
filterMode: 1 aniso: -1
aniso: 1 mipBias: -100
mipBias: 0 wrapU: 1
wrapU: 1 wrapV: 1
wrapV: 1 wrapW: -1
wrapW: 0 nPOTScale: 0
nPOTScale: 0 lightmap: 0
lightmap: 0 compressionQuality: 50
compressionQuality: 50 spriteMode: 1
spriteMode: 1 spriteExtrude: 1
spriteExtrude: 1 spriteMeshType: 1
spriteMeshType: 1 alignment: 0
alignment: 0 spritePivot: {x: 0.5, y: 0.5}
spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100
spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1
spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1
alphaUsage: 1 alphaIsTransparency: 1
alphaIsTransparency: 1 spriteTessellationDetail: -1
spriteTessellationDetail: -1 textureType: 8
textureType: 8 textureShape: 1
textureShape: 1 singleChannelComponent: 0
singleChannelComponent: 0 maxTextureSizeSet: 0
flipbookRows: 1 compressionQualitySet: 0
flipbookColumns: 1 textureFormatSet: 0
maxTextureSizeSet: 0 platformSettings:
compressionQualitySet: 0 - serializedVersion: 3
textureFormatSet: 0 buildTarget: DefaultTexturePlatform
ignorePngGamma: 0 maxTextureSize: 2048
applyGammaDecoding: 1 resizeAlgorithm: 0
platformSettings: textureFormat: -1
- serializedVersion: 3 textureCompression: 1
buildTarget: DefaultTexturePlatform compressionQuality: 50
maxTextureSize: 2048 crunchedCompression: 0
resizeAlgorithm: 0 allowsAlphaSplitting: 0
textureFormat: -1 overridden: 0
textureCompression: 1 androidETC2FallbackOverride: 0
compressionQuality: 50 forceMaximumCompressionQuality_BC6H_BC7: 0
crunchedCompression: 0 - serializedVersion: 3
allowsAlphaSplitting: 0 buildTarget: Standalone
overridden: 0 maxTextureSize: 2048
androidETC2FallbackOverride: 0 resizeAlgorithm: 0
forceMaximumCompressionQuality_BC6H_BC7: 0 textureFormat: -1
- serializedVersion: 3 textureCompression: 1
buildTarget: Standalone compressionQuality: 50
maxTextureSize: 2048 crunchedCompression: 0
resizeAlgorithm: 0 allowsAlphaSplitting: 0
textureFormat: -1 overridden: 0
textureCompression: 1 androidETC2FallbackOverride: 0
compressionQuality: 50 forceMaximumCompressionQuality_BC6H_BC7: 0
crunchedCompression: 0 spriteSheet:
allowsAlphaSplitting: 0 serializedVersion: 2
overridden: 0 sprites: []
androidETC2FallbackOverride: 0 outline: []
forceMaximumCompressionQuality_BC6H_BC7: 0 physicsShape: []
spriteSheet: bones: []
serializedVersion: 2 spriteID: 5e97eb03825dee720800000000000000
sprites: [] internalID: 0
outline: [] vertices: []
physicsShape: [] indices:
bones: [] edges: []
spriteID: 5e97eb03825dee720800000000000000 weights: []
internalID: 0 secondaryTextures: []
vertices: [] spritePackingTag:
indices: pSDRemoveMatte: 0
edges: [] pSDShowRemoveMatteOption: 0
weights: [] userData:
secondaryTextures: [] assetBundleName:
spritePackingTag: assetBundleVariant:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,162 +1,162 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpineAnimationTesterTool : MonoBehaviour, IHasSkeletonDataAsset, IHasSkeletonComponent { public class SpineAnimationTesterTool : MonoBehaviour, IHasSkeletonDataAsset, IHasSkeletonComponent {
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
public SkeletonDataAsset SkeletonDataAsset { get { return skeletonAnimation.SkeletonDataAsset; } } public SkeletonDataAsset SkeletonDataAsset { get { return skeletonAnimation.SkeletonDataAsset; } }
public ISkeletonComponent SkeletonComponent { get { return skeletonAnimation; } } public ISkeletonComponent SkeletonComponent { get { return skeletonAnimation; } }
public bool useOverrideMixDuration; public bool useOverrideMixDuration;
public float overrideMixDuration = 0.2f; public float overrideMixDuration = 0.2f;
public bool useOverrideAttachmentThreshold = true; public bool useOverrideAttachmentThreshold = true;
[Range(0f, 1f)] [Range(0f, 1f)]
public float attachmentThreshold = 0.5f; public float attachmentThreshold = 0.5f;
public bool useOverrideDrawOrderThreshold; public bool useOverrideDrawOrderThreshold;
[Range(0f, 1f)] [Range(0f, 1f)]
public float drawOrderThreshold = 0.5f; public float drawOrderThreshold = 0.5f;
[System.Serializable] [System.Serializable]
public struct AnimationControl { public struct AnimationControl {
[SpineAnimation] [SpineAnimation]
public string animationName; public string animationName;
public bool loop; public bool loop;
public KeyCode key; public KeyCode key;
[Space] [Space]
public bool useCustomMixDuration; public bool useCustomMixDuration;
public float mixDuration; public float mixDuration;
//public bool useChainToControl; //public bool useChainToControl;
//public int chainToControl; //public int chainToControl;
} }
[System.Serializable] [System.Serializable]
public class ControlledTrack { public class ControlledTrack {
public List<AnimationControl> controls = new List<AnimationControl>(); public List<AnimationControl> controls = new List<AnimationControl>();
} }
[Space] [Space]
public List<ControlledTrack> trackControls = new List<ControlledTrack>(); public List<ControlledTrack> trackControls = new List<ControlledTrack>();
[Header("UI")] [Header("UI")]
public UnityEngine.UI.Text boundAnimationsText; public UnityEngine.UI.Text boundAnimationsText;
public UnityEngine.UI.Text skeletonNameText; public UnityEngine.UI.Text skeletonNameText;
void OnValidate () { void OnValidate () {
// Fill in the SkeletonData asset name // Fill in the SkeletonData asset name
if (skeletonNameText != null) { if (skeletonNameText != null) {
if (skeletonAnimation != null && skeletonAnimation.skeletonDataAsset != null) { if (skeletonAnimation != null && skeletonAnimation.skeletonDataAsset != null) {
skeletonNameText.text = SkeletonDataAsset.name.Replace("_SkeletonData", ""); skeletonNameText.text = SkeletonDataAsset.name.Replace("_SkeletonData", "");
} }
} }
// Fill in the control list. // Fill in the control list.
if (boundAnimationsText != null) { if (boundAnimationsText != null) {
StringBuilder boundAnimationsStringBuilder = new StringBuilder(); StringBuilder boundAnimationsStringBuilder = new StringBuilder();
boundAnimationsStringBuilder.AppendLine("Animation Controls:"); boundAnimationsStringBuilder.AppendLine("Animation Controls:");
for (int trackIndex = 0; trackIndex < trackControls.Count; trackIndex++) { for (int trackIndex = 0; trackIndex < trackControls.Count; trackIndex++) {
if (trackIndex > 0) if (trackIndex > 0)
boundAnimationsStringBuilder.AppendLine(); boundAnimationsStringBuilder.AppendLine();
boundAnimationsStringBuilder.AppendFormat("---- Track {0} ---- \n", trackIndex); boundAnimationsStringBuilder.AppendFormat("---- Track {0} ---- \n", trackIndex);
foreach (AnimationControl ba in trackControls[trackIndex].controls) { foreach (AnimationControl ba in trackControls[trackIndex].controls) {
string animationName = ba.animationName; string animationName = ba.animationName;
if (string.IsNullOrEmpty(animationName)) if (string.IsNullOrEmpty(animationName))
animationName = "SetEmptyAnimation"; animationName = "SetEmptyAnimation";
boundAnimationsStringBuilder.AppendFormat("[{0}] {1}\n", ba.key.ToString(), animationName); boundAnimationsStringBuilder.AppendFormat("[{0}] {1}\n", ba.key.ToString(), animationName);
} }
} }
boundAnimationsText.text = boundAnimationsStringBuilder.ToString(); boundAnimationsText.text = boundAnimationsStringBuilder.ToString();
} }
} }
void Start () { void Start () {
if (useOverrideMixDuration) { if (useOverrideMixDuration) {
skeletonAnimation.AnimationState.Data.DefaultMix = overrideMixDuration; skeletonAnimation.AnimationState.Data.DefaultMix = overrideMixDuration;
} }
} }
void Update () { void Update () {
AnimationState animationState = skeletonAnimation.AnimationState; AnimationState animationState = skeletonAnimation.AnimationState;
// For each track // For each track
for (int trackIndex = 0; trackIndex < trackControls.Count; trackIndex++) { for (int trackIndex = 0; trackIndex < trackControls.Count; trackIndex++) {
// For each control in the track // For each control in the track
foreach (AnimationControl control in trackControls[trackIndex].controls) { foreach (AnimationControl control in trackControls[trackIndex].controls) {
// Check each control, and play the appropriate animation. // Check each control, and play the appropriate animation.
if (Input.GetKeyDown(control.key)) { if (Input.GetKeyDown(control.key)) {
TrackEntry trackEntry; TrackEntry trackEntry;
if (!string.IsNullOrEmpty(control.animationName)) { if (!string.IsNullOrEmpty(control.animationName)) {
trackEntry = animationState.SetAnimation(trackIndex, control.animationName, control.loop); trackEntry = animationState.SetAnimation(trackIndex, control.animationName, control.loop);
} else { } else {
float mix = control.useCustomMixDuration ? control.mixDuration : animationState.Data.DefaultMix; float mix = control.useCustomMixDuration ? control.mixDuration : animationState.Data.DefaultMix;
trackEntry = animationState.SetEmptyAnimation(trackIndex, mix); trackEntry = animationState.SetEmptyAnimation(trackIndex, mix);
} }
if (trackEntry != null) { if (trackEntry != null) {
if (control.useCustomMixDuration) if (control.useCustomMixDuration)
trackEntry.MixDuration = control.mixDuration; trackEntry.SetMixDuration(control.mixDuration, 0f); // use SetMixDuration(mixDuration, delay) to update delay correctly
if (useOverrideAttachmentThreshold) if (useOverrideAttachmentThreshold)
trackEntry.AttachmentThreshold = attachmentThreshold; trackEntry.MixAttachmentThreshold = attachmentThreshold;
if (useOverrideDrawOrderThreshold) if (useOverrideDrawOrderThreshold)
trackEntry.DrawOrderThreshold = drawOrderThreshold; trackEntry.MixDrawOrderThreshold = drawOrderThreshold;
} }
// Don't parse more than one animation per track. // Don't parse more than one animation per track.
break; break;
} }
} }
} }
} }
} }
} }

View File

@ -13,7 +13,7 @@ OcclusionCullingSettings:
--- !u!104 &2 --- !u!104 &2
RenderSettings: RenderSettings:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
serializedVersion: 8 serializedVersion: 10
m_Fog: 0 m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3 m_FogMode: 3
@ -39,37 +39,33 @@ RenderSettings:
m_CustomReflection: {fileID: 0} m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0} m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3 --- !u!157 &3
LightmapSettings: LightmapSettings:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
serializedVersion: 11 serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings: m_GISettings:
serializedVersion: 2 serializedVersion: 2
m_BounceScale: 1 m_BounceScale: 1
m_IndirectOutputScale: 1 m_IndirectOutputScale: 1
m_AlbedoBoost: 1 m_AlbedoBoost: 1
m_TemporalCoherenceThreshold: 1
m_EnvironmentLightingMode: 0 m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 0 m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0 m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings: m_LightmapEditorSettings:
serializedVersion: 9 serializedVersion: 12
m_Resolution: 2 m_Resolution: 2
m_BakeResolution: 40 m_BakeResolution: 40
m_TextureWidth: 1024 m_AtlasSize: 1024
m_TextureHeight: 1024
m_AO: 0 m_AO: 0
m_AOMaxDistance: 1 m_AOMaxDistance: 1
m_CompAOExponent: 1 m_CompAOExponent: 1
m_CompAOExponentDirect: 0 m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2 m_Padding: 2
m_LightmapParameters: {fileID: 0} m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1 m_LightmapsBakeMode: 1
m_TextureCompression: 1 m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2 m_ReflectionCompression: 2
m_MixedBakeMode: 2 m_MixedBakeMode: 2
m_BakeBackend: 0 m_BakeBackend: 0
@ -77,23 +73,34 @@ LightmapSettings:
m_PVRDirectSampleCount: 32 m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500 m_PVRSampleCount: 500
m_PVRBounces: 2 m_PVRBounces: 2
m_PVRFiltering: 0 m_PVREnvironmentSampleCount: 500
m_PVRFilteringMode: 1 m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1 m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousColorSigma: 1 m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousNormalSigma: 1 m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigma: 1 m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0} m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1 m_LightingSettings: {fileID: 1506007501}
--- !u!196 &4 --- !u!196 &4
NavMeshSettings: NavMeshSettings:
serializedVersion: 2 serializedVersion: 2
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_BuildSettings: m_BuildSettings:
serializedVersion: 2 serializedVersion: 3
agentTypeID: 0 agentTypeID: 0
agentRadius: 0.5 agentRadius: 0.5
agentHeight: 2 agentHeight: 2
@ -106,20 +113,25 @@ NavMeshSettings:
cellSize: 0.16666667 cellSize: 0.16666667
manualTileSize: 0 manualTileSize: 0
tileSize: 256 tileSize: 256
accuratePlacement: 0 buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0} m_NavMeshData: {fileID: 0}
--- !u!1 &92207858 --- !u!1 &92207858
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
serializedVersion: 5 m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 92207862} - component: {fileID: 92207862}
- component: {fileID: 92207861} - component: {fileID: 92207861}
- component: {fileID: 92207860} - component: {fileID: 92207860}
m_Layer: 5 m_Layer: 5
m_Name: 3 Canvas - Spawn SkeletonGraphic Sample m_Name: 2 Canvas - Spawn SkeletonGraphic Sample
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -128,12 +140,13 @@ GameObject:
--- !u!114 &92207860 --- !u!114 &92207860
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 92207858} m_GameObject: {fileID: 92207858}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3} m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_UiScaleMode: 1 m_UiScaleMode: 1
@ -146,11 +159,13 @@ MonoBehaviour:
m_FallbackScreenDPI: 96 m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96 m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1 m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &92207861 --- !u!223 &92207861
Canvas: Canvas:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 92207858} m_GameObject: {fileID: 92207858}
m_Enabled: 1 m_Enabled: 1
serializedVersion: 3 serializedVersion: 3
@ -162,35 +177,122 @@ Canvas:
m_OverrideSorting: 0 m_OverrideSorting: 0
m_OverridePixelPerfect: 0 m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0 m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0 m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0 m_SortingLayerID: 0
m_SortingOrder: 0 m_SortingOrder: 0
m_TargetDisplay: 0 m_TargetDisplay: 0
--- !u!224 &92207862 --- !u!224 &92207862
RectTransform: RectTransform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 92207858} m_GameObject: {fileID: 92207858}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 1691562007} - {fileID: 1691562007}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0} m_Pivot: {x: 0, y: 0}
--- !u!1 &191860306
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 191860307}
- component: {fileID: 191860309}
- component: {fileID: 191860308}
m_Layer: 0
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &191860307
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 191860306}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1200587070}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!114 &191860308
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 191860306}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 1
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 1920, y: 1080}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &191860309
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 191860306}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!1 &433620963 --- !u!1 &433620963
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
serializedVersion: 5 m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 433620968} - component: {fileID: 433620968}
- component: {fileID: 433620967} - component: {fileID: 433620967}
@ -206,27 +308,44 @@ GameObject:
--- !u!81 &433620964 --- !u!81 &433620964
AudioListener: AudioListener:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 433620963} m_GameObject: {fileID: 433620963}
m_Enabled: 1 m_Enabled: 1
--- !u!124 &433620965 --- !u!124 &433620965
Behaviour: Behaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 433620963} m_GameObject: {fileID: 433620963}
m_Enabled: 1 m_Enabled: 1
--- !u!20 &433620967 --- !u!20 &433620967
Camera: Camera:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 433620963} m_GameObject: {fileID: 433620963}
m_Enabled: 1 m_Enabled: 1
serializedVersion: 2 serializedVersion: 2
m_ClearFlags: 1 m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect: m_NormalizedViewPortRect:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
@ -248,35 +367,38 @@ Camera:
m_TargetEye: 3 m_TargetEye: 3
m_HDR: 1 m_HDR: 1
m_AllowMSAA: 1 m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0 m_ForceIntoRT: 0
m_OcclusionCulling: 1 m_OcclusionCulling: 1
m_StereoConvergence: 10 m_StereoConvergence: 10
m_StereoSeparation: 0.022 m_StereoSeparation: 0.022
m_StereoMirrorMode: 0
--- !u!4 &433620968 --- !u!4 &433620968
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 433620963} m_GameObject: {fileID: 433620963}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10} m_LocalPosition: {x: 0, y: 0, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &651278528 --- !u!1 &651278528
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
serializedVersion: 5 m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 651278530} - component: {fileID: 651278530}
- component: {fileID: 651278529} - component: {fileID: 651278529}
m_Layer: 0 m_Layer: 0
m_Name: 2 RuntimeLoadFromExports m_Name: 3 RuntimeLoadFromExports
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -285,8 +407,9 @@ GameObject:
--- !u!114 &651278529 --- !u!114 &651278529
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 651278528} m_GameObject: {fileID: 651278528}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
@ -297,27 +420,251 @@ MonoBehaviour:
atlasText: {fileID: 4900000, guid: 5c0a5c36970a46e4d8378760ab4a4cfc, type: 3} atlasText: {fileID: 4900000, guid: 5c0a5c36970a46e4d8378760ab4a4cfc, type: 3}
textures: textures:
- {fileID: 2800000, guid: 49bb65eefe08e424bbf7a38bc98ec638, type: 3} - {fileID: 2800000, guid: 49bb65eefe08e424bbf7a38bc98ec638, type: 3}
materialPropertySource: {fileID: 2100000, guid: 1455e88fdb81ccc45bdeaedd657bad4d, materialPropertySource: {fileID: 2100000, guid: 1455e88fdb81ccc45bdeaedd657bad4d, type: 2}
type: 2} delay: 0
skinName:
animationName:
blendModeMaterials: 0
applyAdditiveMaterial: 0
blendModeTemplateMaterials:
additiveTemplate: {fileID: 0}
multiplyTemplate: {fileID: 0}
screenTemplate: {fileID: 0}
graphicBlendModeMaterials:
additiveTemplate: {fileID: 0}
multiplyTemplate: {fileID: 0}
screenTemplate: {fileID: 0}
skeletonGraphicMaterial: {fileID: 2100000, guid: b66cf7a186d13054989b33a5c90044e4, type: 2}
--- !u!4 &651278530 --- !u!4 &651278530
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 651278528} m_GameObject: {fileID: 651278528}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: [] m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1025308469}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1025308468
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1025308469}
- component: {fileID: 1025308472}
- component: {fileID: 1025308471}
m_Layer: 0
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1025308469
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1025308468}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 651278530}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!114 &1025308471
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1025308468}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 1
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 1920, y: 1080}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &1025308472
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1025308468}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!1 &1200587068
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1200587070}
- component: {fileID: 1200587069}
m_Layer: 0
m_Name: 4 Runtime BlendModes from Exports
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1200587069
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1200587068}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bb0837af7345d504db63d0c662fd12dc, type: 3}
m_Name:
m_EditorClassIdentifier:
skeletonJson: {fileID: 4900000, guid: 1a6f51aad0fef5a40aeedfeec5c0b8b2, type: 3}
atlasText: {fileID: 4900000, guid: 188756a89517d7649a67fb53606220f5, type: 3}
textures:
- {fileID: 2800000, guid: dc1b9f9665c8aa74799404a1d2038e3d, type: 3}
materialPropertySource: {fileID: 2100000, guid: 1455e88fdb81ccc45bdeaedd657bad4d, type: 2}
delay: 0
skinName:
animationName:
blendModeMaterials: 1
applyAdditiveMaterial: 0
blendModeTemplateMaterials:
additiveTemplate: {fileID: 2100000, guid: 4deba332d47209e4780b3c5fcf0e3745, type: 2}
multiplyTemplate: {fileID: 2100000, guid: 53bf0ab317d032d418cf1252d68f51df, type: 2}
screenTemplate: {fileID: 2100000, guid: 73f0f46d3177c614baf0fa48d646a9be, type: 2}
graphicBlendModeMaterials:
additiveTemplate: {fileID: 2100000, guid: 2e8245019faeb8c43b75f9ca3ac8ee34, type: 2}
multiplyTemplate: {fileID: 2100000, guid: e74a1f8978a7da348a721508d0d58834, type: 2}
screenTemplate: {fileID: 2100000, guid: bab24c479f34eec45be6ea8595891569, type: 2}
skeletonGraphicMaterial: {fileID: 2100000, guid: b66cf7a186d13054989b33a5c90044e4, type: 2}
--- !u!4 &1200587070
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1200587068}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 191860307}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!850595691 &1506007501
LightingSettings:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Settings.lighting
serializedVersion: 8
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_RealtimeEnvironmentLighting: 1
m_BounceScale: 1
m_AlbedoBoost: 1
m_IndirectOutputScale: 1
m_UsingShadowmask: 1
m_BakeBackend: 1
m_LightmapMaxSize: 1024
m_LightmapSizeFixed: 0
m_UseMipmapLimits: 1
m_BakeResolution: 40
m_Padding: 2
m_LightmapCompression: 3
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAO: 0
m_MixedBakeMode: 2
m_LightmapsBakeMode: 1
m_FilterMode: 1
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_RealtimeResolution: 2
m_ForceWhiteAlbedo: 0
m_ForceUpdates: 0
m_PVRCulling: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVREnvironmentSampleCount: 512
m_PVREnvironmentReferencePointCount: 2048
m_LightProbeSampleCountMultiplier: 4
m_PVRBounces: 2
m_PVRMinBounces: 2
m_PVREnvironmentImportanceSampling: 0
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_RespectSceneVisibilityWhenBakingGI: 0
--- !u!1 &1691562006 --- !u!1 &1691562006
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
serializedVersion: 5 m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 1691562007} - component: {fileID: 1691562007}
- component: {fileID: 1691562008} - component: {fileID: 1691562008}
@ -331,15 +678,16 @@ GameObject:
--- !u!224 &1691562007 --- !u!224 &1691562007
RectTransform: RectTransform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1691562006} m_GameObject: {fileID: 1691562006}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 92207862} m_Father: {fileID: 92207862}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5}
@ -349,8 +697,9 @@ RectTransform:
--- !u!114 &1691562008 --- !u!114 &1691562008
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1691562006} m_GameObject: {fileID: 1691562006}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
@ -360,14 +709,14 @@ MonoBehaviour:
skeletonDataAsset: {fileID: 11400000, guid: a467507a4ffb1d542a558739b2fede77, type: 2} skeletonDataAsset: {fileID: 11400000, guid: a467507a4ffb1d542a558739b2fede77, type: 2}
startingAnimation: run startingAnimation: run
startingSkin: base startingSkin: base
skeletonGraphicMaterial: {fileID: 2100000, guid: 1455e88fdb81ccc45bdeaedd657bad4d, skeletonGraphicMaterial: {fileID: 2100000, guid: b66cf7a186d13054989b33a5c90044e4, type: 2}
type: 2}
--- !u!1 &1807176298 --- !u!1 &1807176298
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
serializedVersion: 5 m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 1807176300} - component: {fileID: 1807176300}
- component: {fileID: 1807176299} - component: {fileID: 1807176299}
@ -381,8 +730,9 @@ GameObject:
--- !u!114 &1807176299 --- !u!114 &1807176299
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1807176298} m_GameObject: {fileID: 1807176298}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
@ -395,13 +745,93 @@ MonoBehaviour:
--- !u!4 &1807176300 --- !u!4 &1807176300
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1807176298} m_GameObject: {fileID: 1807176298}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1924218899
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1924218902}
- component: {fileID: 1924218901}
- component: {fileID: 1924218900}
m_Layer: 0
m_Name: EventSystem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1924218900
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1924218899}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SendPointerHoverToParent: 1
m_HorizontalAxis: Horizontal
m_VerticalAxis: Vertical
m_SubmitButton: Submit
m_CancelButton: Cancel
m_InputActionsPerSecond: 10
m_RepeatDelay: 0.5
m_ForceModuleActive: 0
--- !u!114 &1924218901
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1924218899}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
m_Name:
m_EditorClassIdentifier:
m_FirstSelected: {fileID: 0}
m_sendNavigationEvents: 1
m_DragThreshold: 10
--- !u!4 &1924218902
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1924218899}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 433620968}
- {fileID: 1807176300}
- {fileID: 92207862}
- {fileID: 651278530}
- {fileID: 1200587070}
- {fileID: 1924218902}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e08ce2e2ca315ea4a8e8d3a90681a14c
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -151,6 +151,7 @@ RectTransform:
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 592567554} m_Father: {fileID: 592567554}
m_RootOrder: 1 m_RootOrder: 1
@ -256,6 +257,9 @@ MonoBehaviour:
materialsInsideMask: [] materialsInsideMask: []
materialsOutsideMask: [] materialsOutsideMask: []
disableRenderingOnOverride: 1 disableRenderingOnOverride: 1
physicsPositionInheritanceFactor: {x: 1, y: 1}
physicsRotationInheritanceFactor: 1
physicsMovementRelativeTo: {fileID: 0}
updateTiming: 1 updateTiming: 1
unscaledTime: 0 unscaledTime: 0
_animationName: run _animationName: run
@ -272,6 +276,7 @@ MeshRenderer:
m_CastShadows: 1 m_CastShadows: 1
m_ReceiveShadows: 1 m_ReceiveShadows: 1
m_DynamicOccludee: 1 m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1 m_MotionVectors: 1
m_LightProbeUsage: 1 m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1 m_ReflectionProbeUsage: 1
@ -320,6 +325,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -7.83, y: 0, z: 5.66} m_LocalPosition: {x: -7.83, y: 0, z: 5.66}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 3 m_RootOrder: 3
@ -352,6 +358,7 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 592567554} m_Father: {fileID: 592567554}
m_RootOrder: 2 m_RootOrder: 2
@ -434,6 +441,7 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 1911967440} - {fileID: 1911967440}
- {fileID: 71621967} - {fileID: 71621967}
@ -489,6 +497,7 @@ Canvas:
m_OverridePixelPerfect: 0 m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0 m_SortingBucketNormalizedSize: 0
m_AdditionalShaderChannelsFlag: 0 m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0 m_SortingLayerID: 0
m_SortingOrder: 0 m_SortingOrder: 0
m_TargetDisplay: 0 m_TargetDisplay: 0
@ -518,6 +527,7 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 1911967440} m_Father: {fileID: 1911967440}
m_RootOrder: 0 m_RootOrder: 0
@ -554,6 +564,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -3.7153435, y: -0.0017910004, z: 5.9292965} m_LocalPosition: {x: -3.7153435, y: -0.0017910004, z: 5.9292965}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 2 m_RootOrder: 2
@ -583,6 +594,7 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 1369381601} - component: {fileID: 1369381601}
- component: {fileID: 1369381600} - component: {fileID: 1369381600}
- component: {fileID: 1369381602}
m_Layer: 0 m_Layer: 0
m_Name: Directional Light m_Name: Directional Light
m_TagString: Untagged m_TagString: Untagged
@ -662,10 +674,31 @@ Transform:
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 1 m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!114 &1369381602
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1369381599}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Version: 1
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_LightLayerMask: 1
m_CustomShadowLayers: 0
m_ShadowLayerMask: 1
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
--- !u!1 &1407691187 --- !u!1 &1407691187
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -745,6 +778,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 4.8, z: -10} m_LocalPosition: {x: 0, y: 4.8, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 0 m_RootOrder: 0
@ -811,6 +845,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 5 m_RootOrder: 5
@ -843,6 +878,7 @@ RectTransform:
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 592567554} m_Father: {fileID: 592567554}
m_RootOrder: 3 m_RootOrder: 3
@ -930,6 +966,7 @@ RectTransform:
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 592567554} m_Father: {fileID: 592567554}
m_RootOrder: 4 m_RootOrder: 4
@ -1019,9 +1056,10 @@ MonoBehaviour:
color: {r: 1, g: 1, b: 1, a: 1} color: {r: 1, g: 1, b: 1, a: 1}
maxRenderTextureSize: 1024 maxRenderTextureSize: 1024
quad: {fileID: 0} quad: {fileID: 0}
quadMaterial: {fileID: 2100000, guid: 4c507f887c6274a44a603d96e0eabf2a, type: 2}
renderTexture: {fileID: 0} renderTexture: {fileID: 0}
targetCamera: {fileID: 0} targetCamera: {fileID: 0}
quadMaterial: {fileID: 2100000, guid: 4c507f887c6274a44a603d96e0eabf2a, type: 2} shaderPasses: 00000000
--- !u!114 &1786065615 --- !u!114 &1786065615
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1057,6 +1095,9 @@ MonoBehaviour:
materialsInsideMask: [] materialsInsideMask: []
materialsOutsideMask: [] materialsOutsideMask: []
disableRenderingOnOverride: 1 disableRenderingOnOverride: 1
physicsPositionInheritanceFactor: {x: 1, y: 1}
physicsRotationInheritanceFactor: 1
physicsMovementRelativeTo: {fileID: 0}
updateTiming: 1 updateTiming: 1
unscaledTime: 0 unscaledTime: 0
_animationName: run _animationName: run
@ -1073,6 +1114,7 @@ MeshRenderer:
m_CastShadows: 1 m_CastShadows: 1
m_ReceiveShadows: 1 m_ReceiveShadows: 1
m_DynamicOccludee: 1 m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1 m_MotionVectors: 1
m_LightProbeUsage: 1 m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1 m_ReflectionProbeUsage: 1
@ -1121,6 +1163,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 2.38, y: 0, z: 5.66} m_LocalPosition: {x: 2.38, y: 0, z: 5.66}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 4 m_RootOrder: 4
@ -1164,6 +1207,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -4.7074776, y: 0.042612553, z: 0} m_LocalPosition: {x: -4.7074776, y: 0.042612553, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 592567554} - {fileID: 592567554}
m_Father: {fileID: 0} m_Father: {fileID: 0}
@ -1199,6 +1243,7 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} m_LocalScale: {x: 0.3, y: 0.3, z: 0.3}
m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 1089682727} - {fileID: 1089682727}
m_Father: {fileID: 592567554} m_Father: {fileID: 592567554}
@ -1233,6 +1278,7 @@ MonoBehaviour:
additiveMaterial: {fileID: 2100000, guid: 2e8245019faeb8c43b75f9ca3ac8ee34, type: 2} additiveMaterial: {fileID: 2100000, guid: 2e8245019faeb8c43b75f9ca3ac8ee34, type: 2}
multiplyMaterial: {fileID: 2100000, guid: e74a1f8978a7da348a721508d0d58834, type: 2} multiplyMaterial: {fileID: 2100000, guid: e74a1f8978a7da348a721508d0d58834, type: 2}
screenMaterial: {fileID: 2100000, guid: bab24c479f34eec45be6ea8595891569, type: 2} screenMaterial: {fileID: 2100000, guid: bab24c479f34eec45be6ea8595891569, type: 2}
m_SkeletonColor: {r: 1, g: 1, b: 1, a: 1}
initialSkinName: default initialSkinName: default
initialFlipX: 0 initialFlipX: 0
initialFlipY: 0 initialFlipY: 0
@ -1240,6 +1286,14 @@ MonoBehaviour:
startingLoop: 1 startingLoop: 1
timeScale: 1 timeScale: 1
freeze: 0 freeze: 0
layoutScaleMode: 0
referenceSize: {x: 2145.5999, y: 1302.059}
referencePivot: {x: 0.63858336, y: 0.010301443}
referencePivotOffset: {x: 1370.1444, y: 13.413086}
referenceScale: 1
rectTransformSize: {x: 2145.5999, y: 1302.059}
rectTransformPivot: {x: 0, y: 0}
editReferenceRect: 0
updateWhenInvisible: 3 updateWhenInvisible: 3
allowMultipleCanvasRenderers: 0 allowMultipleCanvasRenderers: 0
canvasRenderers: [] canvasRenderers: []
@ -1247,16 +1301,20 @@ MonoBehaviour:
enableSeparatorSlots: 0 enableSeparatorSlots: 0
separatorParts: [] separatorParts: []
updateSeparatorPartLocation: 1 updateSeparatorPartLocation: 1
updateSeparatorPartScale: 0
disableMeshAssignmentOnOverride: 1 disableMeshAssignmentOnOverride: 1
physicsPositionInheritanceFactor: {x: 1, y: 1}
physicsRotationInheritanceFactor: 1
physicsMovementRelativeTo: {fileID: 0}
meshGenerator: meshGenerator:
settings: settings:
useClipping: 1 useClipping: 1
zSpacing: 0 zSpacing: 0
pmaVertexColors: 1
tintBlack: 0 tintBlack: 0
canvasGroupTintBlack: 0 canvasGroupCompatible: 0
calculateTangents: 0 pmaVertexColors: 1
addNormals: 0 addNormals: 0
calculateTangents: 0
immutableTriangles: 0 immutableTriangles: 0
updateTiming: 1 updateTiming: 1
unscaledTime: 0 unscaledTime: 0
@ -1296,8 +1354,10 @@ MonoBehaviour:
color: {r: 1, g: 1, b: 1, a: 1} color: {r: 1, g: 1, b: 1, a: 1}
maxRenderTextureSize: 1024 maxRenderTextureSize: 1024
quad: {fileID: 0} quad: {fileID: 0}
quadMaterial: {fileID: 2100000, guid: afeb0ae2ea2cda94796515bf8d1b3cb1, type: 2}
renderTexture: {fileID: 0} renderTexture: {fileID: 0}
targetCamera: {fileID: 0} targetCamera: {fileID: 0}
shaderPasses: 00000000
customRenderRect: {fileID: 1089682727} customRenderRect: {fileID: 1089682727}
meshRendererMaterialForTexture: meshRendererMaterialForTexture:
- texture: {fileID: 2800000, guid: 4ea2c33e839afb34c98f66e892b3b2d2, type: 3} - texture: {fileID: 2800000, guid: 4ea2c33e839afb34c98f66e892b3b2d2, type: 3}

View File

@ -1,71 +1,71 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class AttackSpineboy : MonoBehaviour { public class AttackSpineboy : MonoBehaviour {
public SkeletonAnimation spineboy; public SkeletonAnimation spineboy;
public SkeletonAnimation attackerSpineboy; public SkeletonAnimation attackerSpineboy;
public SpineGauge gauge; public SpineGauge gauge;
public Text healthText; public Text healthText;
int currentHealth = 100; int currentHealth = 100;
const int maxHealth = 100; const int maxHealth = 100;
public AnimationReferenceAsset shoot, hit, idle, death; public AnimationReferenceAsset shoot, hit, idle, death;
public UnityEngine.Events.UnityEvent onAttack; public UnityEngine.Events.UnityEvent onAttack;
void Update () { void Update () {
if (Input.GetKeyDown(KeyCode.Space)) { if (Input.GetKeyDown(KeyCode.Space)) {
currentHealth -= 10; currentHealth -= 10;
healthText.text = currentHealth + "/" + maxHealth; healthText.text = currentHealth + "/" + maxHealth;
attackerSpineboy.AnimationState.SetAnimation(1, shoot, false); attackerSpineboy.AnimationState.SetAnimation(1, shoot, false);
attackerSpineboy.AnimationState.AddEmptyAnimation(1, 0.5f, 2f); attackerSpineboy.AnimationState.AddEmptyAnimation(1, 0.5f, 2f);
if (currentHealth > 0) { if (currentHealth > 0) {
spineboy.AnimationState.SetAnimation(0, hit, false); spineboy.AnimationState.SetAnimation(0, hit, false);
spineboy.AnimationState.AddAnimation(0, idle, true, 0); spineboy.AnimationState.AddAnimation(0, idle, true, 0);
gauge.fillPercent = (float)currentHealth / (float)maxHealth; gauge.fillPercent = (float)currentHealth / (float)maxHealth;
onAttack.Invoke(); onAttack.Invoke();
} else { } else {
if (currentHealth >= 0) { if (currentHealth >= 0) {
gauge.fillPercent = 0; gauge.fillPercent = 0;
spineboy.AnimationState.SetAnimation(0, death, false).TrackEnd = float.PositiveInfinity; spineboy.AnimationState.SetAnimation(0, death, false).TrackEnd = float.PositiveInfinity;
} }
} }
} }
} }
} }
} }

View File

@ -1,56 +1,56 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class DraggableTransform : MonoBehaviour { public class DraggableTransform : MonoBehaviour {
Vector2 mousePreviousWorld, mouseDeltaWorld; Vector2 mousePreviousWorld, mouseDeltaWorld;
Camera mainCamera; Camera mainCamera;
void Start () { void Start () {
mainCamera = Camera.main; mainCamera = Camera.main;
} }
void Update () { void Update () {
Vector2 mouseCurrent = Input.mousePosition; Vector2 mouseCurrent = Input.mousePosition;
Vector2 mouseCurrentWorld = mainCamera.ScreenToWorldPoint(new Vector3(mouseCurrent.x, mouseCurrent.y, -mainCamera.transform.position.z)); Vector2 mouseCurrentWorld = mainCamera.ScreenToWorldPoint(new Vector3(mouseCurrent.x, mouseCurrent.y, -mainCamera.transform.position.z));
mouseDeltaWorld = mouseCurrentWorld - mousePreviousWorld; mouseDeltaWorld = mouseCurrentWorld - mousePreviousWorld;
mousePreviousWorld = mouseCurrentWorld; mousePreviousWorld = mouseCurrentWorld;
} }
void OnMouseDrag () { void OnMouseDrag () {
transform.Translate(mouseDeltaWorld); transform.Translate(mouseDeltaWorld);
} }
} }
} }

View File

@ -1,103 +1,103 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class FootSoldierExample : MonoBehaviour { public class FootSoldierExample : MonoBehaviour {
[SpineAnimation("Idle")] [SpineAnimation("Idle")]
public string idleAnimation; public string idleAnimation;
[SpineAnimation] [SpineAnimation]
public string attackAnimation; public string attackAnimation;
[SpineAnimation] [SpineAnimation]
public string moveAnimation; public string moveAnimation;
[SpineSlot] [SpineSlot]
public string eyesSlot; public string eyesSlot;
[SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")] [SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")]
public string eyesOpenAttachment; public string eyesOpenAttachment;
[SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")] [SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")]
public string blinkAttachment; public string blinkAttachment;
[Range(0, 0.2f)] [Range(0, 0.2f)]
public float blinkDuration = 0.05f; public float blinkDuration = 0.05f;
public KeyCode attackKey = KeyCode.Mouse0; public KeyCode attackKey = KeyCode.Mouse0;
public KeyCode rightKey = KeyCode.D; public KeyCode rightKey = KeyCode.D;
public KeyCode leftKey = KeyCode.A; public KeyCode leftKey = KeyCode.A;
public float moveSpeed = 3; public float moveSpeed = 3;
SkeletonAnimation skeletonAnimation; SkeletonAnimation skeletonAnimation;
void Awake () { void Awake () {
skeletonAnimation = GetComponent<SkeletonAnimation>(); skeletonAnimation = GetComponent<SkeletonAnimation>();
skeletonAnimation.OnRebuild += Apply; skeletonAnimation.OnRebuild += Apply;
} }
void Apply (SkeletonRenderer skeletonRenderer) { void Apply (SkeletonRenderer skeletonRenderer) {
StartCoroutine(Blink()); StartCoroutine(Blink());
} }
void Update () { void Update () {
if (Input.GetKey(attackKey)) { if (Input.GetKey(attackKey)) {
skeletonAnimation.AnimationName = attackAnimation; skeletonAnimation.AnimationName = attackAnimation;
} else { } else {
if (Input.GetKey(rightKey)) { if (Input.GetKey(rightKey)) {
skeletonAnimation.AnimationName = moveAnimation; skeletonAnimation.AnimationName = moveAnimation;
skeletonAnimation.Skeleton.ScaleX = 1; skeletonAnimation.Skeleton.ScaleX = 1;
transform.Translate(moveSpeed * Time.deltaTime, 0, 0); transform.Translate(moveSpeed * Time.deltaTime, 0, 0);
} else if (Input.GetKey(leftKey)) { } else if (Input.GetKey(leftKey)) {
skeletonAnimation.AnimationName = moveAnimation; skeletonAnimation.AnimationName = moveAnimation;
skeletonAnimation.Skeleton.ScaleX = -1; skeletonAnimation.Skeleton.ScaleX = -1;
transform.Translate(-moveSpeed * Time.deltaTime, 0, 0); transform.Translate(-moveSpeed * Time.deltaTime, 0, 0);
} else { } else {
skeletonAnimation.AnimationName = idleAnimation; skeletonAnimation.AnimationName = idleAnimation;
} }
} }
} }
IEnumerator Blink () { IEnumerator Blink () {
while (true) { while (true) {
yield return new WaitForSeconds(Random.Range(0.25f, 3f)); yield return new WaitForSeconds(Random.Range(0.25f, 3f));
skeletonAnimation.Skeleton.SetAttachment(eyesSlot, blinkAttachment); skeletonAnimation.Skeleton.SetAttachment(eyesSlot, blinkAttachment);
yield return new WaitForSeconds(blinkDuration); yield return new WaitForSeconds(blinkDuration);
skeletonAnimation.Skeleton.SetAttachment(eyesSlot, eyesOpenAttachment); skeletonAnimation.Skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
} }
} }
} }
} }

View File

@ -1,220 +1,220 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
[RequireComponent(typeof(CharacterController))] [RequireComponent(typeof(CharacterController))]
public class BasicPlatformerController : MonoBehaviour { public class BasicPlatformerController : MonoBehaviour {
public enum CharacterState { public enum CharacterState {
None, None,
Idle, Idle,
Walk, Walk,
Run, Run,
Crouch, Crouch,
Rise, Rise,
Fall, Fall,
Attack Attack
} }
[Header("Components")] [Header("Components")]
public CharacterController controller; public CharacterController controller;
[Header("Controls")] [Header("Controls")]
public string XAxis = "Horizontal"; public string XAxis = "Horizontal";
public string YAxis = "Vertical"; public string YAxis = "Vertical";
public string JumpButton = "Jump"; public string JumpButton = "Jump";
[Header("Moving")] [Header("Moving")]
public float walkSpeed = 1.5f; public float walkSpeed = 1.5f;
public float runSpeed = 7f; public float runSpeed = 7f;
public float gravityScale = 6.6f; public float gravityScale = 6.6f;
[Header("Jumping")] [Header("Jumping")]
public float jumpSpeed = 25; public float jumpSpeed = 25;
public float minimumJumpDuration = 0.5f; public float minimumJumpDuration = 0.5f;
public float jumpInterruptFactor = 0.5f; public float jumpInterruptFactor = 0.5f;
public float forceCrouchVelocity = 25; public float forceCrouchVelocity = 25;
public float forceCrouchDuration = 0.5f; public float forceCrouchDuration = 0.5f;
[Header("Animation")] [Header("Animation")]
public SkeletonAnimationHandleExample animationHandle; public SkeletonAnimationHandleExample animationHandle;
// Events // Events
public event UnityAction OnJump, OnLand, OnHardLand; public event UnityAction OnJump, OnLand, OnHardLand;
Vector2 input = default(Vector2); Vector2 input = default(Vector2);
Vector3 velocity = default(Vector3); Vector3 velocity = default(Vector3);
float minimumJumpEndTime = 0; float minimumJumpEndTime = 0;
float forceCrouchEndTime; float forceCrouchEndTime;
bool wasGrounded = false; bool wasGrounded = false;
CharacterState previousState, currentState; CharacterState previousState, currentState;
void Update () { void Update () {
float dt = Time.deltaTime; float dt = Time.deltaTime;
bool isGrounded = controller.isGrounded; bool isGrounded = controller.isGrounded;
bool landed = !wasGrounded && isGrounded; bool landed = !wasGrounded && isGrounded;
// Dummy input. // Dummy input.
input.x = Input.GetAxis(XAxis); input.x = Input.GetAxis(XAxis);
input.y = Input.GetAxis(YAxis); input.y = Input.GetAxis(YAxis);
bool inputJumpStop = Input.GetButtonUp(JumpButton); bool inputJumpStop = Input.GetButtonUp(JumpButton);
bool inputJumpStart = Input.GetButtonDown(JumpButton); bool inputJumpStart = Input.GetButtonDown(JumpButton);
bool doCrouch = (isGrounded && input.y < -0.5f) || (forceCrouchEndTime > Time.time); bool doCrouch = (isGrounded && input.y < -0.5f) || (forceCrouchEndTime > Time.time);
bool doJumpInterrupt = false; bool doJumpInterrupt = false;
bool doJump = false; bool doJump = false;
bool hardLand = false; bool hardLand = false;
if (landed) { if (landed) {
if (-velocity.y > forceCrouchVelocity) { if (-velocity.y > forceCrouchVelocity) {
hardLand = true; hardLand = true;
doCrouch = true; doCrouch = true;
forceCrouchEndTime = Time.time + forceCrouchDuration; forceCrouchEndTime = Time.time + forceCrouchDuration;
} }
} }
if (!doCrouch) { if (!doCrouch) {
if (isGrounded) { if (isGrounded) {
if (inputJumpStart) { if (inputJumpStart) {
doJump = true; doJump = true;
} }
} else { } else {
doJumpInterrupt = inputJumpStop && Time.time < minimumJumpEndTime; doJumpInterrupt = inputJumpStop && Time.time < minimumJumpEndTime;
} }
} }
// Dummy physics and controller using UnityEngine.CharacterController. // Dummy physics and controller using UnityEngine.CharacterController.
Vector3 gravityDeltaVelocity = Physics.gravity * gravityScale * dt; Vector3 gravityDeltaVelocity = Physics.gravity * gravityScale * dt;
if (doJump) { if (doJump) {
velocity.y = jumpSpeed; velocity.y = jumpSpeed;
minimumJumpEndTime = Time.time + minimumJumpDuration; minimumJumpEndTime = Time.time + minimumJumpDuration;
} else if (doJumpInterrupt) { } else if (doJumpInterrupt) {
if (velocity.y > 0) if (velocity.y > 0)
velocity.y *= jumpInterruptFactor; velocity.y *= jumpInterruptFactor;
} }
velocity.x = 0; velocity.x = 0;
if (!doCrouch) { if (!doCrouch) {
if (input.x != 0) { if (input.x != 0) {
velocity.x = Mathf.Abs(input.x) > 0.6f ? runSpeed : walkSpeed; velocity.x = Mathf.Abs(input.x) > 0.6f ? runSpeed : walkSpeed;
velocity.x *= Mathf.Sign(input.x); velocity.x *= Mathf.Sign(input.x);
} }
} }
if (!isGrounded) { if (!isGrounded) {
if (wasGrounded) { if (wasGrounded) {
if (velocity.y < 0) if (velocity.y < 0)
velocity.y = 0; velocity.y = 0;
} else { } else {
velocity += gravityDeltaVelocity; velocity += gravityDeltaVelocity;
} }
} }
controller.Move(velocity * dt); controller.Move(velocity * dt);
wasGrounded = isGrounded; wasGrounded = isGrounded;
// Determine and store character state // Determine and store character state
if (isGrounded) { if (isGrounded) {
if (doCrouch) { if (doCrouch) {
currentState = CharacterState.Crouch; currentState = CharacterState.Crouch;
} else { } else {
if (input.x == 0) if (input.x == 0)
currentState = CharacterState.Idle; currentState = CharacterState.Idle;
else else
currentState = Mathf.Abs(input.x) > 0.6f ? CharacterState.Run : CharacterState.Walk; currentState = Mathf.Abs(input.x) > 0.6f ? CharacterState.Run : CharacterState.Walk;
} }
} else { } else {
currentState = velocity.y > 0 ? CharacterState.Rise : CharacterState.Fall; currentState = velocity.y > 0 ? CharacterState.Rise : CharacterState.Fall;
} }
bool stateChanged = previousState != currentState; bool stateChanged = previousState != currentState;
previousState = currentState; previousState = currentState;
// Animation // Animation
// Do not modify character parameters or state in this phase. Just read them. // Do not modify character parameters or state in this phase. Just read them.
// Detect changes in state, and communicate with animation handle if it changes. // Detect changes in state, and communicate with animation handle if it changes.
if (stateChanged) if (stateChanged)
HandleStateChanged(); HandleStateChanged();
if (input.x != 0) if (input.x != 0)
animationHandle.SetFlip(input.x); animationHandle.SetFlip(input.x);
// Fire events. // Fire events.
if (doJump) { if (doJump) {
OnJump.Invoke(); OnJump.Invoke();
} }
if (landed) { if (landed) {
if (hardLand) { if (hardLand) {
OnHardLand.Invoke(); OnHardLand.Invoke();
} else { } else {
OnLand.Invoke(); OnLand.Invoke();
} }
} }
} }
void HandleStateChanged () { void HandleStateChanged () {
// When the state changes, notify the animation handle of the new state. // When the state changes, notify the animation handle of the new state.
string stateName = null; string stateName = null;
switch (currentState) { switch (currentState) {
case CharacterState.Idle: case CharacterState.Idle:
stateName = "idle"; stateName = "idle";
break; break;
case CharacterState.Walk: case CharacterState.Walk:
stateName = "walk"; stateName = "walk";
break; break;
case CharacterState.Run: case CharacterState.Run:
stateName = "run"; stateName = "run";
break; break;
case CharacterState.Crouch: case CharacterState.Crouch:
stateName = "crouch"; stateName = "crouch";
break; break;
case CharacterState.Rise: case CharacterState.Rise:
stateName = "rise"; stateName = "rise";
break; break;
case CharacterState.Fall: case CharacterState.Fall:
stateName = "fall"; stateName = "fall";
break; break;
case CharacterState.Attack: case CharacterState.Attack:
stateName = "attack"; stateName = "attack";
break; break;
default: default:
break; break;
} }
animationHandle.PlayAnimationForState(stateName, 0); animationHandle.PlayAnimationForState(stateName, 0);
} }
} }
} }

View File

@ -1,52 +1,52 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class ConstrainedCamera : MonoBehaviour { public class ConstrainedCamera : MonoBehaviour {
public Transform target; public Transform target;
public Vector3 offset; public Vector3 offset;
public Vector3 min; public Vector3 min;
public Vector3 max; public Vector3 max;
public float smoothing = 5f; public float smoothing = 5f;
// Update is called once per frame // Update is called once per frame
void LateUpdate () { void LateUpdate () {
Vector3 goalPoint = target.position + offset; Vector3 goalPoint = target.position + offset;
goalPoint.x = Mathf.Clamp(goalPoint.x, min.x, max.x); goalPoint.x = Mathf.Clamp(goalPoint.x, min.x, max.x);
goalPoint.y = Mathf.Clamp(goalPoint.y, min.y, max.y); goalPoint.y = Mathf.Clamp(goalPoint.y, min.y, max.y);
goalPoint.z = Mathf.Clamp(goalPoint.z, min.z, max.z); goalPoint.z = Mathf.Clamp(goalPoint.z, min.z, max.z);
transform.position = Vector3.Lerp(transform.position, goalPoint, smoothing * Time.deltaTime); transform.position = Vector3.Lerp(transform.position, goalPoint, smoothing * Time.deltaTime);
} }
} }
} }

View File

@ -1,66 +1,66 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class Raptor : MonoBehaviour { public class Raptor : MonoBehaviour {
#region Inspector #region Inspector
public AnimationReferenceAsset walk; public AnimationReferenceAsset walk;
public AnimationReferenceAsset gungrab; public AnimationReferenceAsset gungrab;
public AnimationReferenceAsset gunkeep; public AnimationReferenceAsset gunkeep;
#endregion #endregion
SkeletonAnimation skeletonAnimation; SkeletonAnimation skeletonAnimation;
void Start () { void Start () {
skeletonAnimation = GetComponent<SkeletonAnimation>(); skeletonAnimation = GetComponent<SkeletonAnimation>();
StartCoroutine(GunGrabRoutine()); StartCoroutine(GunGrabRoutine());
} }
IEnumerator GunGrabRoutine () { IEnumerator GunGrabRoutine () {
// Play the walk animation on track 0. // Play the walk animation on track 0.
skeletonAnimation.AnimationState.SetAnimation(0, walk, true); skeletonAnimation.AnimationState.SetAnimation(0, walk, true);
// Repeatedly play the gungrab and gunkeep animation on track 1. // Repeatedly play the gungrab and gunkeep animation on track 1.
while (true) { while (true) {
yield return new WaitForSeconds(Random.Range(0.5f, 3f)); yield return new WaitForSeconds(Random.Range(0.5f, 3f));
skeletonAnimation.AnimationState.SetAnimation(1, gungrab, false); skeletonAnimation.AnimationState.SetAnimation(1, gungrab, false);
yield return new WaitForSeconds(Random.Range(0.5f, 3f)); yield return new WaitForSeconds(Random.Range(0.5f, 3f));
skeletonAnimation.AnimationState.SetAnimation(1, gunkeep, false); skeletonAnimation.AnimationState.SetAnimation(1, gunkeep, false);
} }
} }
} }
} }

View File

@ -1,109 +1,109 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpineBeginnerTwo : MonoBehaviour { public class SpineBeginnerTwo : MonoBehaviour {
#region Inspector #region Inspector
// [SpineAnimation] attribute allows an Inspector dropdown of Spine animation names coming form SkeletonAnimation. // [SpineAnimation] attribute allows an Inspector dropdown of Spine animation names coming form SkeletonAnimation.
[SpineAnimation] [SpineAnimation]
public string runAnimationName; public string runAnimationName;
[SpineAnimation] [SpineAnimation]
public string idleAnimationName; public string idleAnimationName;
[SpineAnimation] [SpineAnimation]
public string walkAnimationName; public string walkAnimationName;
[SpineAnimation] [SpineAnimation]
public string shootAnimationName; public string shootAnimationName;
[Header("Transitions")] [Header("Transitions")]
[SpineAnimation] [SpineAnimation]
public string idleTurnAnimationName; public string idleTurnAnimationName;
[SpineAnimation] [SpineAnimation]
public string runToIdleAnimationName; public string runToIdleAnimationName;
public float runWalkDuration = 1.5f; public float runWalkDuration = 1.5f;
#endregion #endregion
SkeletonAnimation skeletonAnimation; SkeletonAnimation skeletonAnimation;
// Spine.AnimationState and Spine.Skeleton are not Unity-serialized objects. You will not see them as fields in the inspector. // Spine.AnimationState and Spine.Skeleton are not Unity-serialized objects. You will not see them as fields in the inspector.
public Spine.AnimationState spineAnimationState; public Spine.AnimationState spineAnimationState;
public Spine.Skeleton skeleton; public Spine.Skeleton skeleton;
void Start () { void Start () {
// Make sure you get these AnimationState and Skeleton references in Start or Later. // Make sure you get these AnimationState and Skeleton references in Start or Later.
// Getting and using them in Awake is not guaranteed by default execution order. // Getting and using them in Awake is not guaranteed by default execution order.
skeletonAnimation = GetComponent<SkeletonAnimation>(); skeletonAnimation = GetComponent<SkeletonAnimation>();
spineAnimationState = skeletonAnimation.AnimationState; spineAnimationState = skeletonAnimation.AnimationState;
skeleton = skeletonAnimation.Skeleton; skeleton = skeletonAnimation.Skeleton;
StartCoroutine(DoDemoRoutine()); StartCoroutine(DoDemoRoutine());
} }
/// This is an infinitely repeating Unity Coroutine. Read the Unity documentation on Coroutines to learn more. /// This is an infinitely repeating Unity Coroutine. Read the Unity documentation on Coroutines to learn more.
IEnumerator DoDemoRoutine () { IEnumerator DoDemoRoutine () {
while (true) { while (true) {
// SetAnimation is the basic way to set an animation. // SetAnimation is the basic way to set an animation.
// SetAnimation sets the animation and starts playing it from the beginning. // SetAnimation sets the animation and starts playing it from the beginning.
// Common Mistake: If you keep calling it in Update, it will keep showing the first pose of the animation, do don't do that. // Common Mistake: If you keep calling it in Update, it will keep showing the first pose of the animation, do don't do that.
spineAnimationState.SetAnimation(0, walkAnimationName, true); spineAnimationState.SetAnimation(0, walkAnimationName, true);
yield return new WaitForSeconds(runWalkDuration); yield return new WaitForSeconds(runWalkDuration);
spineAnimationState.SetAnimation(0, runAnimationName, true); spineAnimationState.SetAnimation(0, runAnimationName, true);
yield return new WaitForSeconds(runWalkDuration); yield return new WaitForSeconds(runWalkDuration);
// AddAnimation queues up an animation to play after the previous one ends. // AddAnimation queues up an animation to play after the previous one ends.
spineAnimationState.SetAnimation(0, runToIdleAnimationName, false); spineAnimationState.SetAnimation(0, runToIdleAnimationName, false);
spineAnimationState.AddAnimation(0, idleAnimationName, true, 0); spineAnimationState.AddAnimation(0, idleAnimationName, true, 0);
yield return new WaitForSeconds(1f); yield return new WaitForSeconds(1f);
skeleton.ScaleX = -1; // skeleton allows you to flip the skeleton. skeleton.ScaleX = -1; // skeleton allows you to flip the skeleton.
spineAnimationState.SetAnimation(0, idleTurnAnimationName, false); spineAnimationState.SetAnimation(0, idleTurnAnimationName, false);
spineAnimationState.AddAnimation(0, idleAnimationName, true, 0); spineAnimationState.AddAnimation(0, idleAnimationName, true, 0);
yield return new WaitForSeconds(0.5f); yield return new WaitForSeconds(0.5f);
skeleton.ScaleX = 1; skeleton.ScaleX = 1;
spineAnimationState.SetAnimation(0, idleTurnAnimationName, false); spineAnimationState.SetAnimation(0, idleTurnAnimationName, false);
spineAnimationState.AddAnimation(0, idleAnimationName, true, 0); spineAnimationState.AddAnimation(0, idleAnimationName, true, 0);
yield return new WaitForSeconds(0.5f); yield return new WaitForSeconds(0.5f);
} }
} }
} }
} }

View File

@ -1,52 +1,52 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpineBlinkPlayer : MonoBehaviour { public class SpineBlinkPlayer : MonoBehaviour {
const int BlinkTrack = 1; const int BlinkTrack = 1;
public AnimationReferenceAsset blinkAnimation; public AnimationReferenceAsset blinkAnimation;
public float minimumDelay = 0.15f; public float minimumDelay = 0.15f;
public float maximumDelay = 3f; public float maximumDelay = 3f;
IEnumerator Start () { IEnumerator Start () {
SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>(); SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>();
if (skeletonAnimation == null) yield break; if (skeletonAnimation == null) yield break;
while (true) { while (true) {
skeletonAnimation.AnimationState.SetAnimation(SpineBlinkPlayer.BlinkTrack, blinkAnimation, false); skeletonAnimation.AnimationState.SetAnimation(SpineBlinkPlayer.BlinkTrack, blinkAnimation, false);
yield return new WaitForSeconds(Random.Range(minimumDelay, maximumDelay)); yield return new WaitForSeconds(Random.Range(minimumDelay, maximumDelay));
} }
} }
} }
} }

View File

@ -1,68 +1,68 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpineboyBeginnerInput : MonoBehaviour { public class SpineboyBeginnerInput : MonoBehaviour {
#region Inspector #region Inspector
public string horizontalAxis = "Horizontal"; public string horizontalAxis = "Horizontal";
public string attackButton = "Fire1"; public string attackButton = "Fire1";
public string aimButton = "Fire2"; public string aimButton = "Fire2";
public string jumpButton = "Jump"; public string jumpButton = "Jump";
public SpineboyBeginnerModel model; public SpineboyBeginnerModel model;
void OnValidate () { void OnValidate () {
if (model == null) if (model == null)
model = GetComponent<SpineboyBeginnerModel>(); model = GetComponent<SpineboyBeginnerModel>();
} }
#endregion #endregion
void Update () { void Update () {
if (model == null) return; if (model == null) return;
float currentHorizontal = Input.GetAxisRaw(horizontalAxis); float currentHorizontal = Input.GetAxisRaw(horizontalAxis);
model.TryMove(currentHorizontal); model.TryMove(currentHorizontal);
if (Input.GetButton(attackButton)) if (Input.GetButton(attackButton))
model.TryShoot(); model.TryShoot();
if (Input.GetButtonDown(aimButton)) if (Input.GetButtonDown(aimButton))
model.StartAim(); model.StartAim();
if (Input.GetButtonUp(aimButton)) if (Input.GetButtonUp(aimButton))
model.StopAim(); model.StopAim();
if (Input.GetButtonDown(jumpButton)) if (Input.GetButtonDown(jumpButton))
model.TryJump(); model.TryJump();
} }
} }
} }

View File

@ -1,124 +1,124 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
[SelectionBase] [SelectionBase]
public class SpineboyBeginnerModel : MonoBehaviour { public class SpineboyBeginnerModel : MonoBehaviour {
#region Inspector #region Inspector
[Header("Current State")] [Header("Current State")]
public SpineBeginnerBodyState state; public SpineBeginnerBodyState state;
public bool facingLeft; public bool facingLeft;
[Range(-1f, 1f)] [Range(-1f, 1f)]
public float currentSpeed; public float currentSpeed;
[Header("Balance")] [Header("Balance")]
public float shootInterval = 0.12f; public float shootInterval = 0.12f;
#endregion #endregion
float lastShootTime; float lastShootTime;
public event System.Action ShootEvent; // Lets other scripts know when Spineboy is shooting. Check C# Documentation to learn more about events and delegates. public event System.Action ShootEvent; // Lets other scripts know when Spineboy is shooting. Check C# Documentation to learn more about events and delegates.
public event System.Action StartAimEvent; // Lets other scripts know when Spineboy is aiming. public event System.Action StartAimEvent; // Lets other scripts know when Spineboy is aiming.
public event System.Action StopAimEvent; // Lets other scripts know when Spineboy is no longer aiming. public event System.Action StopAimEvent; // Lets other scripts know when Spineboy is no longer aiming.
#region API #region API
public void TryJump () { public void TryJump () {
StartCoroutine(JumpRoutine()); StartCoroutine(JumpRoutine());
} }
public void TryShoot () { public void TryShoot () {
float currentTime = Time.time; float currentTime = Time.time;
if (currentTime - lastShootTime > shootInterval) { if (currentTime - lastShootTime > shootInterval) {
lastShootTime = currentTime; lastShootTime = currentTime;
if (ShootEvent != null) ShootEvent(); // Fire the "ShootEvent" event. if (ShootEvent != null) ShootEvent(); // Fire the "ShootEvent" event.
} }
} }
public void StartAim () { public void StartAim () {
if (StartAimEvent != null) StartAimEvent(); // Fire the "StartAimEvent" event. if (StartAimEvent != null) StartAimEvent(); // Fire the "StartAimEvent" event.
} }
public void StopAim () { public void StopAim () {
if (StopAimEvent != null) StopAimEvent(); // Fire the "StopAimEvent" event. if (StopAimEvent != null) StopAimEvent(); // Fire the "StopAimEvent" event.
} }
public void TryMove (float speed) { public void TryMove (float speed) {
currentSpeed = speed; // show the "speed" in the Inspector. currentSpeed = speed; // show the "speed" in the Inspector.
if (speed != 0) { if (speed != 0) {
bool speedIsNegative = (speed < 0f); bool speedIsNegative = (speed < 0f);
facingLeft = speedIsNegative; // Change facing direction whenever speed is not 0. facingLeft = speedIsNegative; // Change facing direction whenever speed is not 0.
} }
if (state != SpineBeginnerBodyState.Jumping) { if (state != SpineBeginnerBodyState.Jumping) {
state = (speed == 0) ? SpineBeginnerBodyState.Idle : SpineBeginnerBodyState.Running; state = (speed == 0) ? SpineBeginnerBodyState.Idle : SpineBeginnerBodyState.Running;
} }
} }
#endregion #endregion
IEnumerator JumpRoutine () { IEnumerator JumpRoutine () {
if (state == SpineBeginnerBodyState.Jumping) yield break; // Don't jump when already jumping. if (state == SpineBeginnerBodyState.Jumping) yield break; // Don't jump when already jumping.
state = SpineBeginnerBodyState.Jumping; state = SpineBeginnerBodyState.Jumping;
// Fake jumping. // Fake jumping.
{ {
Vector3 pos = transform.localPosition; Vector3 pos = transform.localPosition;
const float jumpTime = 1.2f; const float jumpTime = 1.2f;
const float half = jumpTime * 0.5f; const float half = jumpTime * 0.5f;
const float jumpPower = 20f; const float jumpPower = 20f;
for (float t = 0; t < half; t += Time.deltaTime) { for (float t = 0; t < half; t += Time.deltaTime) {
float d = jumpPower * (half - t); float d = jumpPower * (half - t);
transform.Translate((d * Time.deltaTime) * Vector3.up); transform.Translate((d * Time.deltaTime) * Vector3.up);
yield return null; yield return null;
} }
for (float t = 0; t < half; t += Time.deltaTime) { for (float t = 0; t < half; t += Time.deltaTime) {
float d = jumpPower * t; float d = jumpPower * t;
transform.Translate((d * Time.deltaTime) * Vector3.down); transform.Translate((d * Time.deltaTime) * Vector3.down);
yield return null; yield return null;
} }
transform.localPosition = pos; transform.localPosition = pos;
} }
state = SpineBeginnerBodyState.Idle; state = SpineBeginnerBodyState.Idle;
} }
} }
public enum SpineBeginnerBodyState { public enum SpineBeginnerBodyState {
Idle, Idle,
Running, Running,
Jumping Jumping
} }
} }

View File

@ -1,167 +1,167 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpineboyBeginnerView : MonoBehaviour { public class SpineboyBeginnerView : MonoBehaviour {
#region Inspector #region Inspector
[Header("Components")] [Header("Components")]
public SpineboyBeginnerModel model; public SpineboyBeginnerModel model;
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
public AnimationReferenceAsset run, idle, aim, shoot, jump; public AnimationReferenceAsset run, idle, aim, shoot, jump;
public EventDataReferenceAsset footstepEvent; public EventDataReferenceAsset footstepEvent;
[Header("Audio")] [Header("Audio")]
public float footstepPitchOffset = 0.2f; public float footstepPitchOffset = 0.2f;
public float gunsoundPitchOffset = 0.13f; public float gunsoundPitchOffset = 0.13f;
public AudioSource footstepSource, gunSource, jumpSource; public AudioSource footstepSource, gunSource, jumpSource;
[Header("Effects")] [Header("Effects")]
public ParticleSystem gunParticles; public ParticleSystem gunParticles;
#endregion #endregion
SpineBeginnerBodyState previousViewState; SpineBeginnerBodyState previousViewState;
void Start () { void Start () {
if (skeletonAnimation == null) return; if (skeletonAnimation == null) return;
model.ShootEvent += PlayShoot; model.ShootEvent += PlayShoot;
model.StartAimEvent += StartPlayingAim; model.StartAimEvent += StartPlayingAim;
model.StopAimEvent += StopPlayingAim; model.StopAimEvent += StopPlayingAim;
skeletonAnimation.AnimationState.Event += HandleEvent; skeletonAnimation.AnimationState.Event += HandleEvent;
} }
void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) { void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
if (e.Data == footstepEvent.EventData) if (e.Data == footstepEvent.EventData)
PlayFootstepSound(); PlayFootstepSound();
} }
void Update () { void Update () {
if (skeletonAnimation == null) return; if (skeletonAnimation == null) return;
if (model == null) return; if (model == null) return;
if ((skeletonAnimation.skeleton.ScaleX < 0) != model.facingLeft) { // Detect changes in model.facingLeft if ((skeletonAnimation.skeleton.ScaleX < 0) != model.facingLeft) { // Detect changes in model.facingLeft
Turn(model.facingLeft); Turn(model.facingLeft);
} }
// Detect changes in model.state // Detect changes in model.state
SpineBeginnerBodyState currentModelState = model.state; SpineBeginnerBodyState currentModelState = model.state;
if (previousViewState != currentModelState) { if (previousViewState != currentModelState) {
PlayNewStableAnimation(); PlayNewStableAnimation();
} }
previousViewState = currentModelState; previousViewState = currentModelState;
} }
void PlayNewStableAnimation () { void PlayNewStableAnimation () {
SpineBeginnerBodyState newModelState = model.state; SpineBeginnerBodyState newModelState = model.state;
Animation nextAnimation; Animation nextAnimation;
// Add conditionals to not interrupt transient animations. // Add conditionals to not interrupt transient animations.
if (previousViewState == SpineBeginnerBodyState.Jumping && newModelState != SpineBeginnerBodyState.Jumping) { if (previousViewState == SpineBeginnerBodyState.Jumping && newModelState != SpineBeginnerBodyState.Jumping) {
PlayFootstepSound(); PlayFootstepSound();
} }
if (newModelState == SpineBeginnerBodyState.Jumping) { if (newModelState == SpineBeginnerBodyState.Jumping) {
jumpSource.Play(); jumpSource.Play();
nextAnimation = jump; nextAnimation = jump;
} else { } else {
if (newModelState == SpineBeginnerBodyState.Running) { if (newModelState == SpineBeginnerBodyState.Running) {
nextAnimation = run; nextAnimation = run;
} else { } else {
nextAnimation = idle; nextAnimation = idle;
} }
} }
skeletonAnimation.AnimationState.SetAnimation(0, nextAnimation, true); skeletonAnimation.AnimationState.SetAnimation(0, nextAnimation, true);
} }
void PlayFootstepSound () { void PlayFootstepSound () {
footstepSource.Play(); footstepSource.Play();
footstepSource.pitch = GetRandomPitch(footstepPitchOffset); footstepSource.pitch = GetRandomPitch(footstepPitchOffset);
} }
[ContextMenu("Check Tracks")] [ContextMenu("Check Tracks")]
void CheckTracks () { void CheckTracks () {
AnimationState state = skeletonAnimation.AnimationState; AnimationState state = skeletonAnimation.AnimationState;
Debug.Log(state.GetCurrent(0)); Debug.Log(state.GetCurrent(0));
Debug.Log(state.GetCurrent(1)); Debug.Log(state.GetCurrent(1));
} }
#region Transient Actions #region Transient Actions
public void PlayShoot () { public void PlayShoot () {
// Play the shoot animation on track 1. // Play the shoot animation on track 1.
TrackEntry shootTrack = skeletonAnimation.AnimationState.SetAnimation(1, shoot, false); TrackEntry shootTrack = skeletonAnimation.AnimationState.SetAnimation(1, shoot, false);
shootTrack.AttachmentThreshold = 1f; shootTrack.MixAttachmentThreshold = 1f;
shootTrack.MixDuration = 0f; shootTrack.SetMixDuration(0f, 0f);
skeletonAnimation.state.AddEmptyAnimation(1, 0.5f, 0.1f); skeletonAnimation.state.AddEmptyAnimation(1, 0.5f, 0.1f);
// Play the aim animation on track 2 to aim at the mouse target. // Play the aim animation on track 2 to aim at the mouse target.
TrackEntry aimTrack = skeletonAnimation.AnimationState.SetAnimation(2, aim, false); TrackEntry aimTrack = skeletonAnimation.AnimationState.SetAnimation(2, aim, false);
aimTrack.AttachmentThreshold = 1f; aimTrack.MixAttachmentThreshold = 1f;
aimTrack.MixDuration = 0f; aimTrack.SetMixDuration(0f, 0f);
skeletonAnimation.state.AddEmptyAnimation(2, 0.5f, 0.1f); skeletonAnimation.state.AddEmptyAnimation(2, 0.5f, 0.1f);
gunSource.pitch = GetRandomPitch(gunsoundPitchOffset); gunSource.pitch = GetRandomPitch(gunsoundPitchOffset);
gunSource.Play(); gunSource.Play();
//gunParticles.randomSeed = (uint)Random.Range(0, 100); //gunParticles.randomSeed = (uint)Random.Range(0, 100);
gunParticles.Play(); gunParticles.Play();
} }
public void StartPlayingAim () { public void StartPlayingAim () {
// Play the aim animation on track 2 to aim at the mouse target. // Play the aim animation on track 2 to aim at the mouse target.
TrackEntry aimTrack = skeletonAnimation.AnimationState.SetAnimation(2, aim, true); TrackEntry aimTrack = skeletonAnimation.AnimationState.SetAnimation(2, aim, true);
aimTrack.AttachmentThreshold = 1f; aimTrack.MixAttachmentThreshold = 1f;
aimTrack.MixDuration = 0f; aimTrack.SetMixDuration(0f, 0f); // use SetMixDuration(mixDuration, delay) to update delay correctly
} }
public void StopPlayingAim () { public void StopPlayingAim () {
skeletonAnimation.state.AddEmptyAnimation(2, 0.5f, 0.1f); skeletonAnimation.state.AddEmptyAnimation(2, 0.5f, 0.1f);
} }
public void Turn (bool facingLeft) { public void Turn (bool facingLeft) {
skeletonAnimation.Skeleton.ScaleX = facingLeft ? -1f : 1f; skeletonAnimation.Skeleton.ScaleX = facingLeft ? -1f : 1f;
// Maybe play a transient turning animation too, then call ChangeStableAnimation. // Maybe play a transient turning animation too, then call ChangeStableAnimation.
} }
#endregion #endregion
#region Utility #region Utility
public float GetRandomPitch (float maxPitchOffset) { public float GetRandomPitch (float maxPitchOffset) {
return 1f + Random.Range(-maxPitchOffset, maxPitchOffset); return 1f + Random.Range(-maxPitchOffset, maxPitchOffset);
} }
#endregion #endregion
} }
} }

View File

@ -0,0 +1,167 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
* otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
using Spine.Unity;
using System.Collections;
using UnityEngine;
namespace Spine.Unity.Examples {
public class SpineboyBeginnerViewGraphic : MonoBehaviour {
#region Inspector
[Header("Components")]
public SpineboyBeginnerModel model;
public SkeletonGraphic skeletonGraphic;
public AnimationReferenceAsset run, idle, aim, shoot, jump;
public EventDataReferenceAsset footstepEvent;
[Header("Audio")]
public float footstepPitchOffset = 0.2f;
public float gunsoundPitchOffset = 0.13f;
public AudioSource footstepSource, gunSource, jumpSource;
[Header("Effects")]
public ParticleSystem gunParticles;
#endregion
SpineBeginnerBodyState previousViewState;
void Start () {
if (skeletonGraphic == null) return;
model.ShootEvent += PlayShoot;
model.StartAimEvent += StartPlayingAim;
model.StopAimEvent += StopPlayingAim;
skeletonGraphic.AnimationState.Event += HandleEvent;
}
void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
if (e.Data == footstepEvent.EventData)
PlayFootstepSound();
}
void Update () {
if (skeletonGraphic == null) return;
if (model == null) return;
if ((skeletonGraphic.Skeleton.ScaleX < 0) != model.facingLeft) { // Detect changes in model.facingLeft
Turn(model.facingLeft);
}
// Detect changes in model.state
SpineBeginnerBodyState currentModelState = model.state;
if (previousViewState != currentModelState) {
PlayNewStableAnimation();
}
previousViewState = currentModelState;
}
void PlayNewStableAnimation () {
SpineBeginnerBodyState newModelState = model.state;
Animation nextAnimation;
// Add conditionals to not interrupt transient animations.
if (previousViewState == SpineBeginnerBodyState.Jumping && newModelState != SpineBeginnerBodyState.Jumping) {
PlayFootstepSound();
}
if (newModelState == SpineBeginnerBodyState.Jumping) {
jumpSource.Play();
nextAnimation = jump;
} else {
if (newModelState == SpineBeginnerBodyState.Running) {
nextAnimation = run;
} else {
nextAnimation = idle;
}
}
skeletonGraphic.AnimationState.SetAnimation(0, nextAnimation, true);
}
void PlayFootstepSound () {
footstepSource.Play();
footstepSource.pitch = GetRandomPitch(footstepPitchOffset);
}
[ContextMenu("Check Tracks")]
void CheckTracks () {
AnimationState state = skeletonGraphic.AnimationState;
Debug.Log(state.GetCurrent(0));
Debug.Log(state.GetCurrent(1));
}
#region Transient Actions
public void PlayShoot () {
// Play the shoot animation on track 1.
TrackEntry shootTrack = skeletonGraphic.AnimationState.SetAnimation(1, shoot, false);
shootTrack.MixAttachmentThreshold = 1f;
shootTrack.SetMixDuration(0f, 0f);
skeletonGraphic.AnimationState.AddEmptyAnimation(1, 0.5f, 0.1f);
// Play the aim animation on track 2 to aim at the mouse target.
TrackEntry aimTrack = skeletonGraphic.AnimationState.SetAnimation(2, aim, false);
aimTrack.MixAttachmentThreshold = 1f;
aimTrack.SetMixDuration(0f, 0f);
skeletonGraphic.AnimationState.AddEmptyAnimation(2, 0.5f, 0.1f);
gunSource.pitch = GetRandomPitch(gunsoundPitchOffset);
gunSource.Play();
//gunParticles.randomSeed = (uint)Random.Range(0, 100);
gunParticles.Play();
}
public void StartPlayingAim () {
// Play the aim animation on track 2 to aim at the mouse target.
TrackEntry aimTrack = skeletonGraphic.AnimationState.SetAnimation(2, aim, true);
aimTrack.MixAttachmentThreshold = 1f;
aimTrack.SetMixDuration(0f, 0f); // use SetMixDuration(mixDuration, delay) to update delay correctly
}
public void StopPlayingAim () {
skeletonGraphic.AnimationState.AddEmptyAnimation(2, 0.5f, 0.1f);
}
public void Turn (bool facingLeft) {
skeletonGraphic.Skeleton.ScaleX = facingLeft ? -1f : 1f;
// Maybe play a transient turning animation too, then call ChangeStableAnimation.
}
#endregion
#region Utility
public float GetRandomPitch (float maxPitchOffset) {
return 1f + Random.Range(-maxPitchOffset, maxPitchOffset);
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 795971ea6ab1f214eac09ad8814226e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,61 +1,61 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpineboyTargetController : MonoBehaviour { public class SpineboyTargetController : MonoBehaviour {
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
[SpineBone(dataField: "skeletonAnimation")] [SpineBone(dataField: "skeletonAnimation")]
public string boneName; public string boneName;
public Camera cam; public Camera cam;
Bone bone; Bone bone;
void OnValidate () { void OnValidate () {
if (skeletonAnimation == null) skeletonAnimation = GetComponent<SkeletonAnimation>(); if (skeletonAnimation == null) skeletonAnimation = GetComponent<SkeletonAnimation>();
} }
void Start () { void Start () {
bone = skeletonAnimation.Skeleton.FindBone(boneName); bone = skeletonAnimation.Skeleton.FindBone(boneName);
} }
void Update () { void Update () {
Vector3 mousePosition = Input.mousePosition; Vector3 mousePosition = Input.mousePosition;
Vector3 worldMousePosition = cam.ScreenToWorldPoint(mousePosition); Vector3 worldMousePosition = cam.ScreenToWorldPoint(mousePosition);
Vector3 skeletonSpacePoint = skeletonAnimation.transform.InverseTransformPoint(worldMousePosition); Vector3 skeletonSpacePoint = skeletonAnimation.transform.InverseTransformPoint(worldMousePosition);
skeletonSpacePoint.x *= skeletonAnimation.Skeleton.ScaleX; skeletonSpacePoint.x *= skeletonAnimation.Skeleton.ScaleX;
skeletonSpacePoint.y *= skeletonAnimation.Skeleton.ScaleY; skeletonSpacePoint.y *= skeletonAnimation.Skeleton.ScaleY;
bone.SetLocalPosition(skeletonSpacePoint); bone.SetLocalPosition(skeletonSpacePoint);
} }
} }
} }

View File

@ -0,0 +1,64 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
* otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
using UnityEngine;
namespace Spine.Unity.Examples {
public class SpineboyTargetControllerGraphic : MonoBehaviour {
public SkeletonGraphic skeletonGraphic;
[SpineBone(dataField: "skeletonGraphic")]
public string boneName;
public Camera cam;
public Canvas canvas;
Bone bone;
void OnValidate () {
if (skeletonGraphic == null) skeletonGraphic = GetComponent<SkeletonGraphic>();
}
void Start () {
bone = skeletonGraphic.Skeleton.FindBone(boneName);
}
void Update () {
Vector3 mousePosition = Input.mousePosition;
Vector2 localRectPosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
skeletonGraphic.rectTransform, mousePosition, null, out localRectPosition);
Vector3 skeletonSpacePoint = localRectPosition / skeletonGraphic.MeshScale;
skeletonSpacePoint.x *= skeletonGraphic.Skeleton.ScaleX;
skeletonSpacePoint.y *= skeletonGraphic.Skeleton.ScaleY;
bone.SetLocalPosition(skeletonSpacePoint);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e58811512f2bea64988af3798e27f1d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,64 +1,64 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This is an example of how you could store animation transitions for use in your animation system. // This is an example of how you could store animation transitions for use in your animation system.
// More ideally, this would be stored in a ScriptableObject in asset form rather than in a MonoBehaviour. // More ideally, this would be stored in a ScriptableObject in asset form rather than in a MonoBehaviour.
public sealed class TransitionDictionaryExample : MonoBehaviour { public sealed class TransitionDictionaryExample : MonoBehaviour {
[System.Serializable] [System.Serializable]
public struct SerializedEntry { public struct SerializedEntry {
public AnimationReferenceAsset from; public AnimationReferenceAsset from;
public AnimationReferenceAsset to; public AnimationReferenceAsset to;
public AnimationReferenceAsset transition; public AnimationReferenceAsset transition;
} }
[SerializeField] [SerializeField]
List<SerializedEntry> transitions = new List<SerializedEntry>(); List<SerializedEntry> transitions = new List<SerializedEntry>();
readonly Dictionary<AnimationStateData.AnimationPair, Animation> dictionary = new Dictionary<AnimationStateData.AnimationPair, Animation>(); readonly Dictionary<AnimationStateData.AnimationPair, Animation> dictionary = new Dictionary<AnimationStateData.AnimationPair, Animation>();
void Start () { void Start () {
dictionary.Clear(); dictionary.Clear();
foreach (SerializedEntry e in transitions) { foreach (SerializedEntry e in transitions) {
dictionary.Add(new AnimationStateData.AnimationPair(e.from.Animation, e.to.Animation), e.transition.Animation); dictionary.Add(new AnimationStateData.AnimationPair(e.from.Animation, e.to.Animation), e.transition.Animation);
} }
} }
public Animation GetTransition (Animation from, Animation to) { public Animation GetTransition (Animation from, Animation to) {
Animation result; Animation result;
dictionary.TryGetValue(new AnimationStateData.AnimationPair(from, to), out result); dictionary.TryGetValue(new AnimationStateData.AnimationPair(from, to), out result);
return result; return result;
} }
} }
} }

View File

@ -1,67 +1,67 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class Goblins : MonoBehaviour { public class Goblins : MonoBehaviour {
SkeletonAnimation skeletonAnimation; SkeletonAnimation skeletonAnimation;
Bone headBone; Bone headBone;
bool girlSkin; bool girlSkin;
[Range(-360, 360)] [Range(-360, 360)]
public float extraRotation; public float extraRotation;
public void Start () { public void Start () {
skeletonAnimation = GetComponent<SkeletonAnimation>(); skeletonAnimation = GetComponent<SkeletonAnimation>();
headBone = skeletonAnimation.Skeleton.FindBone("head"); headBone = skeletonAnimation.Skeleton.FindBone("head");
skeletonAnimation.UpdateLocal += UpdateLocal; skeletonAnimation.UpdateLocal += UpdateLocal;
} }
// This is called after the animation is applied to the skeleton and can be used to adjust the bones dynamically. // This is called after the animation is applied to the skeleton and can be used to adjust the bones dynamically.
public void UpdateLocal (ISkeletonAnimation skeletonRenderer) { public void UpdateLocal (ISkeletonAnimation skeletonRenderer) {
headBone.Rotation += extraRotation; headBone.Rotation += extraRotation;
} }
public void OnMouseDown () { public void OnMouseDown () {
skeletonAnimation.Skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl"); skeletonAnimation.Skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl");
skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.Skeleton.SetSlotsToSetupPose();
girlSkin = !girlSkin; girlSkin = !girlSkin;
if (girlSkin) { if (girlSkin) {
skeletonAnimation.Skeleton.SetAttachment("right-hand-item", null); skeletonAnimation.Skeleton.SetAttachment("right-hand-item", null);
skeletonAnimation.Skeleton.SetAttachment("left-hand-item", "spear"); skeletonAnimation.Skeleton.SetAttachment("left-hand-item", "spear");
} else } else
skeletonAnimation.Skeleton.SetAttachment("left-hand-item", "dagger"); skeletonAnimation.Skeleton.SetAttachment("left-hand-item", "dagger");
} }
} }
} }

View File

@ -1,83 +1,83 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class HandleEventWithAudioExample : MonoBehaviour { public class HandleEventWithAudioExample : MonoBehaviour {
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
[SpineEvent(dataField: "skeletonAnimation", fallbackToTextField: true)] [SpineEvent(dataField: "skeletonAnimation", fallbackToTextField: true)]
public string eventName; public string eventName;
[Space] [Space]
public AudioSource audioSource; public AudioSource audioSource;
public AudioClip audioClip; public AudioClip audioClip;
public float basePitch = 1f; public float basePitch = 1f;
public float randomPitchOffset = 0.1f; public float randomPitchOffset = 0.1f;
[Space] [Space]
public bool logDebugMessage = false; public bool logDebugMessage = false;
Spine.EventData eventData; Spine.EventData eventData;
void OnValidate () { void OnValidate () {
if (skeletonAnimation == null) GetComponent<SkeletonAnimation>(); if (skeletonAnimation == null) GetComponent<SkeletonAnimation>();
if (audioSource == null) GetComponent<AudioSource>(); if (audioSource == null) GetComponent<AudioSource>();
} }
void Start () { void Start () {
if (audioSource == null) return; if (audioSource == null) return;
if (skeletonAnimation == null) return; if (skeletonAnimation == null) return;
skeletonAnimation.Initialize(false); skeletonAnimation.Initialize(false);
if (!skeletonAnimation.valid) return; if (!skeletonAnimation.valid) return;
eventData = skeletonAnimation.Skeleton.Data.FindEvent(eventName); eventData = skeletonAnimation.Skeleton.Data.FindEvent(eventName);
skeletonAnimation.AnimationState.Event += HandleAnimationStateEvent; skeletonAnimation.AnimationState.Event += HandleAnimationStateEvent;
} }
private void HandleAnimationStateEvent (TrackEntry trackEntry, Event e) { private void HandleAnimationStateEvent (TrackEntry trackEntry, Event e) {
if (logDebugMessage) Debug.Log("Event fired! " + e.Data.Name); if (logDebugMessage) Debug.Log("Event fired! " + e.Data.Name);
//bool eventMatch = string.Equals(e.Data.Name, eventName, System.StringComparison.Ordinal); // Testing recommendation: String compare. //bool eventMatch = string.Equals(e.Data.Name, eventName, System.StringComparison.Ordinal); // Testing recommendation: String compare.
bool eventMatch = (eventData == e.Data); // Performance recommendation: Match cached reference instead of string. bool eventMatch = (eventData == e.Data); // Performance recommendation: Match cached reference instead of string.
if (eventMatch) { if (eventMatch) {
Play(); Play();
} }
} }
public void Play () { public void Play () {
audioSource.pitch = basePitch + Random.Range(-randomPitchOffset, randomPitchOffset); audioSource.pitch = basePitch + Random.Range(-randomPitchOffset, randomPitchOffset);
audioSource.clip = audioClip; audioSource.clip = audioClip;
audioSource.Play(); audioSource.Play();
} }
} }
} }

View File

@ -1,47 +1,47 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class HeroEffectsHandlerExample : MonoBehaviour { public class HeroEffectsHandlerExample : MonoBehaviour {
public BasicPlatformerController eventSource; public BasicPlatformerController eventSource;
public UnityEvent OnJump, OnLand, OnHardLand; public UnityEvent OnJump, OnLand, OnHardLand;
public void Awake () { public void Awake () {
if (eventSource == null) if (eventSource == null)
return; return;
eventSource.OnLand += OnLand.Invoke; eventSource.OnLand += OnLand.Invoke;
eventSource.OnJump += OnJump.Invoke; eventSource.OnJump += OnJump.Invoke;
eventSource.OnHardLand += OnHardLand.Invoke; eventSource.OnHardLand += OnHardLand.Invoke;
} }
} }
} }

View File

@ -1,77 +1,77 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class HurtFlashEffect : MonoBehaviour { public class HurtFlashEffect : MonoBehaviour {
const int DefaultFlashCount = 3; const int DefaultFlashCount = 3;
public int flashCount = DefaultFlashCount; public int flashCount = DefaultFlashCount;
public Color flashColor = Color.white; public Color flashColor = Color.white;
[Range(1f / 120f, 1f / 15f)] [Range(1f / 120f, 1f / 15f)]
public float interval = 1f / 60f; public float interval = 1f / 60f;
public string fillPhaseProperty = "_FillPhase"; public string fillPhaseProperty = "_FillPhase";
public string fillColorProperty = "_FillColor"; public string fillColorProperty = "_FillColor";
MaterialPropertyBlock mpb; MaterialPropertyBlock mpb;
MeshRenderer meshRenderer; MeshRenderer meshRenderer;
public void Flash () { public void Flash () {
if (mpb == null) mpb = new MaterialPropertyBlock(); if (mpb == null) mpb = new MaterialPropertyBlock();
if (meshRenderer == null) meshRenderer = GetComponent<MeshRenderer>(); if (meshRenderer == null) meshRenderer = GetComponent<MeshRenderer>();
meshRenderer.GetPropertyBlock(mpb); meshRenderer.GetPropertyBlock(mpb);
StartCoroutine(FlashRoutine()); StartCoroutine(FlashRoutine());
} }
IEnumerator FlashRoutine () { IEnumerator FlashRoutine () {
if (flashCount < 0) flashCount = DefaultFlashCount; if (flashCount < 0) flashCount = DefaultFlashCount;
int fillPhase = Shader.PropertyToID(fillPhaseProperty); int fillPhase = Shader.PropertyToID(fillPhaseProperty);
int fillColor = Shader.PropertyToID(fillColorProperty); int fillColor = Shader.PropertyToID(fillColorProperty);
WaitForSeconds wait = new WaitForSeconds(interval); WaitForSeconds wait = new WaitForSeconds(interval);
for (int i = 0; i < flashCount; i++) { for (int i = 0; i < flashCount; i++) {
mpb.SetColor(fillColor, flashColor); mpb.SetColor(fillColor, flashColor);
mpb.SetFloat(fillPhase, 1f); mpb.SetFloat(fillPhase, 1f);
meshRenderer.SetPropertyBlock(mpb); meshRenderer.SetPropertyBlock(mpb);
yield return wait; yield return wait;
mpb.SetFloat(fillPhase, 0f); mpb.SetFloat(fillPhase, 0f);
meshRenderer.SetPropertyBlock(mpb); meshRenderer.SetPropertyBlock(mpb);
yield return wait; yield return wait;
} }
yield return null; yield return null;
} }
} }

View File

@ -1,62 +1,62 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class MaterialPropertyBlockExample : MonoBehaviour { public class MaterialPropertyBlockExample : MonoBehaviour {
public float timeInterval = 1f; public float timeInterval = 1f;
public Gradient randomColors = new Gradient(); public Gradient randomColors = new Gradient();
public string colorPropertyName = "_FillColor"; public string colorPropertyName = "_FillColor";
MaterialPropertyBlock mpb; MaterialPropertyBlock mpb;
float timeToNextColor = 0; float timeToNextColor = 0;
void Start () { void Start () {
mpb = new MaterialPropertyBlock(); mpb = new MaterialPropertyBlock();
} }
void Update () { void Update () {
if (timeToNextColor <= 0) { if (timeToNextColor <= 0) {
timeToNextColor = timeInterval; timeToNextColor = timeInterval;
Color newColor = randomColors.Evaluate(UnityEngine.Random.value); Color newColor = randomColors.Evaluate(UnityEngine.Random.value);
mpb.SetColor(colorPropertyName, newColor); mpb.SetColor(colorPropertyName, newColor);
GetComponent<MeshRenderer>().SetPropertyBlock(mpb); GetComponent<MeshRenderer>().SetPropertyBlock(mpb);
} }
timeToNextColor -= Time.deltaTime; timeToNextColor -= Time.deltaTime;
} }
} }
} }

View File

@ -1,82 +1,82 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class MaterialReplacementExample : MonoBehaviour { public class MaterialReplacementExample : MonoBehaviour {
public Material originalMaterial; public Material originalMaterial;
public Material replacementMaterial; public Material replacementMaterial;
public bool replacementEnabled = true; public bool replacementEnabled = true;
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
[Space] [Space]
public string phasePropertyName = "_FillPhase"; public string phasePropertyName = "_FillPhase";
[Range(0f, 1f)] public float phase = 1f; [Range(0f, 1f)] public float phase = 1f;
bool previousEnabled; bool previousEnabled;
MaterialPropertyBlock mpb; MaterialPropertyBlock mpb;
void Start () { void Start () {
// Use the code below to programmatically query the original material. // Use the code below to programmatically query the original material.
// Note: using MeshRenderer.material will fail since it creates an instance copy of the Material, // Note: using MeshRenderer.material will fail since it creates an instance copy of the Material,
// MeshRenderer.sharedMaterial might also fail when called too early or when no Attachments // MeshRenderer.sharedMaterial might also fail when called too early or when no Attachments
// are visible in the initial first frame. // are visible in the initial first frame.
if (originalMaterial == null) if (originalMaterial == null)
originalMaterial = skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial; originalMaterial = skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial;
previousEnabled = replacementEnabled; previousEnabled = replacementEnabled;
SetReplacementEnabled(replacementEnabled); SetReplacementEnabled(replacementEnabled);
mpb = new MaterialPropertyBlock(); mpb = new MaterialPropertyBlock();
} }
void Update () { void Update () {
mpb.SetFloat(phasePropertyName, phase); mpb.SetFloat(phasePropertyName, phase);
GetComponent<MeshRenderer>().SetPropertyBlock(mpb); GetComponent<MeshRenderer>().SetPropertyBlock(mpb);
if (previousEnabled != replacementEnabled) if (previousEnabled != replacementEnabled)
SetReplacementEnabled(replacementEnabled); SetReplacementEnabled(replacementEnabled);
previousEnabled = replacementEnabled; previousEnabled = replacementEnabled;
} }
void SetReplacementEnabled (bool active) { void SetReplacementEnabled (bool active) {
if (replacementEnabled) { if (replacementEnabled) {
skeletonAnimation.CustomMaterialOverride[originalMaterial] = replacementMaterial; skeletonAnimation.CustomMaterialOverride[originalMaterial] = replacementMaterial;
} else { } else {
skeletonAnimation.CustomMaterialOverride.Remove(originalMaterial); skeletonAnimation.CustomMaterialOverride.Remove(originalMaterial);
} }
} }
} }
} }

View File

@ -1,104 +1,104 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class DummyMecanimControllerExample : MonoBehaviour { public class DummyMecanimControllerExample : MonoBehaviour {
public Animator logicAnimator; public Animator logicAnimator;
public SkeletonAnimationHandleExample animationHandle; public SkeletonAnimationHandleExample animationHandle;
[Header("Controls")] [Header("Controls")]
public KeyCode walkButton = KeyCode.LeftShift; public KeyCode walkButton = KeyCode.LeftShift;
public KeyCode jumpButton = KeyCode.Space; public KeyCode jumpButton = KeyCode.Space;
[Header("Animator Properties")] [Header("Animator Properties")]
public string horizontalSpeedProperty = "Speed"; public string horizontalSpeedProperty = "Speed";
public string verticalSpeedProperty = "VerticalSpeed"; public string verticalSpeedProperty = "VerticalSpeed";
public string groundedProperty = "Grounded"; public string groundedProperty = "Grounded";
[Header("Fake Physics")] [Header("Fake Physics")]
public float jumpDuration = 1.5f; public float jumpDuration = 1.5f;
public Vector2 speed; public Vector2 speed;
public bool isGrounded; public bool isGrounded;
void Awake () { void Awake () {
isGrounded = true; isGrounded = true;
} }
void Update () { void Update () {
float x = Input.GetAxisRaw("Horizontal"); float x = Input.GetAxisRaw("Horizontal");
if (Input.GetKey(walkButton)) { if (Input.GetKey(walkButton)) {
x *= 0.4f; x *= 0.4f;
} }
speed.x = x; speed.x = x;
// Flip skeleton. // Flip skeleton.
if (x != 0) { if (x != 0) {
animationHandle.SetFlip(x); animationHandle.SetFlip(x);
} }
if (Input.GetKeyDown(jumpButton)) { if (Input.GetKeyDown(jumpButton)) {
if (isGrounded) if (isGrounded)
StartCoroutine(FakeJump()); StartCoroutine(FakeJump());
} }
logicAnimator.SetFloat(horizontalSpeedProperty, Mathf.Abs(speed.x)); logicAnimator.SetFloat(horizontalSpeedProperty, Mathf.Abs(speed.x));
logicAnimator.SetFloat(verticalSpeedProperty, speed.y); logicAnimator.SetFloat(verticalSpeedProperty, speed.y);
logicAnimator.SetBool(groundedProperty, isGrounded); logicAnimator.SetBool(groundedProperty, isGrounded);
} }
IEnumerator FakeJump () { IEnumerator FakeJump () {
// Rise // Rise
isGrounded = false; isGrounded = false;
speed.y = 10f; speed.y = 10f;
float durationLeft = jumpDuration * 0.5f; float durationLeft = jumpDuration * 0.5f;
while (durationLeft > 0) { while (durationLeft > 0) {
durationLeft -= Time.deltaTime; durationLeft -= Time.deltaTime;
if (!Input.GetKey(jumpButton)) break; if (!Input.GetKey(jumpButton)) break;
yield return null; yield return null;
} }
// Fall // Fall
speed.y = -10f; speed.y = -10f;
float fallDuration = (jumpDuration * 0.5f) - durationLeft; float fallDuration = (jumpDuration * 0.5f) - durationLeft;
yield return new WaitForSeconds(fallDuration); yield return new WaitForSeconds(fallDuration);
// Land // Land
speed.y = 0f; speed.y = 0f;
isGrounded = true; isGrounded = true;
yield return null; yield return null;
} }
} }
} }

View File

@ -1,51 +1,51 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This StateMachineBehaviour handles sending the Mecanim state information to the component that handles playing the Spine animations. // This StateMachineBehaviour handles sending the Mecanim state information to the component that handles playing the Spine animations.
public class MecanimToAnimationHandleExample : StateMachineBehaviour { public class MecanimToAnimationHandleExample : StateMachineBehaviour {
SkeletonAnimationHandleExample animationHandle; SkeletonAnimationHandleExample animationHandle;
bool initialized; bool initialized;
override public void OnStateEnter (Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { override public void OnStateEnter (Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
if (!initialized) { if (!initialized) {
animationHandle = animator.GetComponent<SkeletonAnimationHandleExample>(); animationHandle = animator.GetComponent<SkeletonAnimationHandleExample>();
initialized = true; initialized = true;
} }
animationHandle.PlayAnimationForState(stateInfo.shortNameHash, layerIndex); animationHandle.PlayAnimationForState(stateInfo.shortNameHash, layerIndex);
} }
} }
} }

View File

@ -1,164 +1,164 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This is an example of an animation handle. This is implemented with strings as state names. // This is an example of an animation handle. This is implemented with strings as state names.
// Strings can serve as the identifier when Mecanim is used as the state machine and state source. // Strings can serve as the identifier when Mecanim is used as the state machine and state source.
// If you don't use Mecanim, using custom ScriptableObjects may be a more efficient way to store information about the state and its connection with specific Spine animations. // If you don't use Mecanim, using custom ScriptableObjects may be a more efficient way to store information about the state and its connection with specific Spine animations.
// This animation handle implementation also comes with a dummy implementation of transition-handling. // This animation handle implementation also comes with a dummy implementation of transition-handling.
public class SkeletonAnimationHandleExample : MonoBehaviour { public class SkeletonAnimationHandleExample : MonoBehaviour {
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
public List<StateNameToAnimationReference> statesAndAnimations = new List<StateNameToAnimationReference>(); public List<StateNameToAnimationReference> statesAndAnimations = new List<StateNameToAnimationReference>();
public List<AnimationTransition> transitions = new List<AnimationTransition>(); // Alternately, an AnimationPair-Animation Dictionary (commented out) can be used for more efficient lookups. public List<AnimationTransition> transitions = new List<AnimationTransition>(); // Alternately, an AnimationPair-Animation Dictionary (commented out) can be used for more efficient lookups.
[System.Serializable] [System.Serializable]
public class StateNameToAnimationReference { public class StateNameToAnimationReference {
public string stateName; public string stateName;
public AnimationReferenceAsset animation; public AnimationReferenceAsset animation;
} }
[System.Serializable] [System.Serializable]
public class AnimationTransition { public class AnimationTransition {
public AnimationReferenceAsset from; public AnimationReferenceAsset from;
public AnimationReferenceAsset to; public AnimationReferenceAsset to;
public AnimationReferenceAsset transition; public AnimationReferenceAsset transition;
} }
//readonly Dictionary<Spine.AnimationStateData.AnimationPair, Spine.Animation> transitionDictionary = new Dictionary<AnimationStateData.AnimationPair, Animation>(Spine.AnimationStateData.AnimationPairComparer.Instance); //readonly Dictionary<Spine.AnimationStateData.AnimationPair, Spine.Animation> transitionDictionary = new Dictionary<AnimationStateData.AnimationPair, Animation>(Spine.AnimationStateData.AnimationPairComparer.Instance);
public Spine.Animation TargetAnimation { get; private set; } public Spine.Animation TargetAnimation { get; private set; }
void Awake () { void Awake () {
// Initialize AnimationReferenceAssets // Initialize AnimationReferenceAssets
foreach (StateNameToAnimationReference entry in statesAndAnimations) { foreach (StateNameToAnimationReference entry in statesAndAnimations) {
entry.animation.Initialize(); entry.animation.Initialize();
} }
foreach (AnimationTransition entry in transitions) { foreach (AnimationTransition entry in transitions) {
entry.from.Initialize(); entry.from.Initialize();
entry.to.Initialize(); entry.to.Initialize();
entry.transition.Initialize(); entry.transition.Initialize();
} }
// Build Dictionary // Build Dictionary
//foreach (AnimationTransition entry in transitions) { //foreach (AnimationTransition entry in transitions) {
// transitionDictionary.Add(new AnimationStateData.AnimationPair(entry.from.Animation, entry.to.Animation), entry.transition.Animation); // transitionDictionary.Add(new AnimationStateData.AnimationPair(entry.from.Animation, entry.to.Animation), entry.transition.Animation);
//} //}
} }
/// <summary>Sets the horizontal flip state of the skeleton based on a nonzero float. If negative, the skeleton is flipped. If positive, the skeleton is not flipped.</summary> /// <summary>Sets the horizontal flip state of the skeleton based on a nonzero float. If negative, the skeleton is flipped. If positive, the skeleton is not flipped.</summary>
public void SetFlip (float horizontal) { public void SetFlip (float horizontal) {
if (horizontal != 0) { if (horizontal != 0) {
skeletonAnimation.Skeleton.ScaleX = horizontal > 0 ? 1f : -1f; skeletonAnimation.Skeleton.ScaleX = horizontal > 0 ? 1f : -1f;
} }
} }
/// <summary>Plays an animation based on the state name.</summary> /// <summary>Plays an animation based on the state name.</summary>
public void PlayAnimationForState (string stateShortName, int layerIndex) { public void PlayAnimationForState (string stateShortName, int layerIndex) {
PlayAnimationForState(StringToHash(stateShortName), layerIndex); PlayAnimationForState(StringToHash(stateShortName), layerIndex);
} }
/// <summary>Plays an animation based on the hash of the state name.</summary> /// <summary>Plays an animation based on the hash of the state name.</summary>
public void PlayAnimationForState (int shortNameHash, int layerIndex) { public void PlayAnimationForState (int shortNameHash, int layerIndex) {
Animation foundAnimation = GetAnimationForState(shortNameHash); Animation foundAnimation = GetAnimationForState(shortNameHash);
if (foundAnimation == null) if (foundAnimation == null)
return; return;
PlayNewAnimation(foundAnimation, layerIndex); PlayNewAnimation(foundAnimation, layerIndex);
} }
/// <summary>Gets a Spine Animation based on the state name.</summary> /// <summary>Gets a Spine Animation based on the state name.</summary>
public Spine.Animation GetAnimationForState (string stateShortName) { public Spine.Animation GetAnimationForState (string stateShortName) {
return GetAnimationForState(StringToHash(stateShortName)); return GetAnimationForState(StringToHash(stateShortName));
} }
/// <summary>Gets a Spine Animation based on the hash of the state name.</summary> /// <summary>Gets a Spine Animation based on the hash of the state name.</summary>
public Spine.Animation GetAnimationForState (int shortNameHash) { public Spine.Animation GetAnimationForState (int shortNameHash) {
StateNameToAnimationReference foundState = statesAndAnimations.Find(entry => StringToHash(entry.stateName) == shortNameHash); StateNameToAnimationReference foundState = statesAndAnimations.Find(entry => StringToHash(entry.stateName) == shortNameHash);
return (foundState == null) ? null : foundState.animation; return (foundState == null) ? null : foundState.animation;
} }
/// <summary>Play an animation. If a transition animation is defined, the transition is played before the target animation being passed.</summary> /// <summary>Play an animation. If a transition animation is defined, the transition is played before the target animation being passed.</summary>
public void PlayNewAnimation (Spine.Animation target, int layerIndex) { public void PlayNewAnimation (Spine.Animation target, int layerIndex) {
Spine.Animation transition = null; Spine.Animation transition = null;
Spine.Animation current = null; Spine.Animation current = null;
current = GetCurrentAnimation(layerIndex); current = GetCurrentAnimation(layerIndex);
if (current != null) if (current != null)
transition = TryGetTransition(current, target); transition = TryGetTransition(current, target);
if (transition != null) { if (transition != null) {
skeletonAnimation.AnimationState.SetAnimation(layerIndex, transition, false); skeletonAnimation.AnimationState.SetAnimation(layerIndex, transition, false);
skeletonAnimation.AnimationState.AddAnimation(layerIndex, target, true, 0f); skeletonAnimation.AnimationState.AddAnimation(layerIndex, target, true, 0f);
} else { } else {
skeletonAnimation.AnimationState.SetAnimation(layerIndex, target, true); skeletonAnimation.AnimationState.SetAnimation(layerIndex, target, true);
} }
this.TargetAnimation = target; this.TargetAnimation = target;
} }
/// <summary>Play a non-looping animation once then continue playing the state animation.</summary> /// <summary>Play a non-looping animation once then continue playing the state animation.</summary>
public void PlayOneShot (Spine.Animation oneShot, int layerIndex) { public void PlayOneShot (Spine.Animation oneShot, int layerIndex) {
AnimationState state = skeletonAnimation.AnimationState; AnimationState state = skeletonAnimation.AnimationState;
state.SetAnimation(0, oneShot, false); state.SetAnimation(0, oneShot, false);
Animation transition = TryGetTransition(oneShot, TargetAnimation); Animation transition = TryGetTransition(oneShot, TargetAnimation);
if (transition != null) if (transition != null)
state.AddAnimation(0, transition, false, 0f); state.AddAnimation(0, transition, false, 0f);
state.AddAnimation(0, this.TargetAnimation, true, 0f); state.AddAnimation(0, this.TargetAnimation, true, 0f);
} }
Spine.Animation TryGetTransition (Spine.Animation from, Spine.Animation to) { Spine.Animation TryGetTransition (Spine.Animation from, Spine.Animation to) {
foreach (AnimationTransition transition in transitions) { foreach (AnimationTransition transition in transitions) {
if (transition.from.Animation == from && transition.to.Animation == to) { if (transition.from.Animation == from && transition.to.Animation == to) {
return transition.transition.Animation; return transition.transition.Animation;
} }
} }
return null; return null;
//Spine.Animation foundTransition = null; //Spine.Animation foundTransition = null;
//transitionDictionary.TryGetValue(new AnimationStateData.AnimationPair(from, to), out foundTransition); //transitionDictionary.TryGetValue(new AnimationStateData.AnimationPair(from, to), out foundTransition);
//return foundTransition; //return foundTransition;
} }
Spine.Animation GetCurrentAnimation (int layerIndex) { Spine.Animation GetCurrentAnimation (int layerIndex) {
TrackEntry currentTrackEntry = skeletonAnimation.AnimationState.GetCurrent(layerIndex); TrackEntry currentTrackEntry = skeletonAnimation.AnimationState.GetCurrent(layerIndex);
return (currentTrackEntry != null) ? currentTrackEntry.Animation : null; return (currentTrackEntry != null) ? currentTrackEntry.Animation : null;
} }
int StringToHash (string s) { int StringToHash (string s) {
return Animator.StringToHash(s); return Animator.StringToHash(s);
} }
} }
} }

View File

@ -1,237 +1,237 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
//[CreateAssetMenu(menuName = "Spine/SkeletonData Modifiers/Animation Match", order = 200)] //[CreateAssetMenu(menuName = "Spine/SkeletonData Modifiers/Animation Match", order = 200)]
public class AnimationMatchModifierAsset : SkeletonDataModifierAsset { public class AnimationMatchModifierAsset : SkeletonDataModifierAsset {
public bool matchAllAnimations = true; public bool matchAllAnimations = true;
public override void Apply (SkeletonData skeletonData) { public override void Apply (SkeletonData skeletonData) {
if (matchAllAnimations) if (matchAllAnimations)
AnimationTools.MatchAnimationTimelines(skeletonData.Animations, skeletonData); AnimationTools.MatchAnimationTimelines(skeletonData.Animations, skeletonData);
} }
public static class AnimationTools { public static class AnimationTools {
#region Filler Timelines #region Filler Timelines
/// <summary> /// <summary>
/// Matches the animation timelines across the given set of animations. /// Matches the animation timelines across the given set of animations.
/// This allows unkeyed properties to assume setup pose when animations are naively mixed using Animation.Apply. /// This allows unkeyed properties to assume setup pose when animations are naively mixed using Animation.Apply.
/// </summary> /// </summary>
/// <param name="animations">An enumerable collection animations whose timelines will be matched.</param> /// <param name="animations">An enumerable collection animations whose timelines will be matched.</param>
/// <param name="skeletonData">The SkeletonData where the animations belong.</param> /// <param name="skeletonData">The SkeletonData where the animations belong.</param>
public static void MatchAnimationTimelines (IEnumerable<Spine.Animation> animations, SkeletonData skeletonData) { public static void MatchAnimationTimelines (IEnumerable<Spine.Animation> animations, SkeletonData skeletonData) {
if (animations == null) return; if (animations == null) return;
if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "Timelines can't be matched without a SkeletonData source."); if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "Timelines can't be matched without a SkeletonData source.");
// Build a reference collection of timelines to match // Build a reference collection of timelines to match
// and a collection of dummy timelines that can be used to fill-in missing items. // and a collection of dummy timelines that can be used to fill-in missing items.
Dictionary<string, Timeline> timelineDictionary = new Dictionary<string, Spine.Timeline>(); Dictionary<string, Timeline> timelineDictionary = new Dictionary<string, Spine.Timeline>();
foreach (Animation animation in animations) { foreach (Animation animation in animations) {
foreach (Timeline timeline in animation.Timelines) { foreach (Timeline timeline in animation.Timelines) {
if (timeline is EventTimeline) continue; if (timeline is EventTimeline) continue;
foreach (string propertyId in timeline.PropertyIds) { foreach (string propertyId in timeline.PropertyIds) {
if (!timelineDictionary.ContainsKey(propertyId)) { if (!timelineDictionary.ContainsKey(propertyId)) {
timelineDictionary.Add(propertyId, GetFillerTimeline(timeline, skeletonData)); timelineDictionary.Add(propertyId, GetFillerTimeline(timeline, skeletonData));
} }
} }
} }
} }
List<string> idsToMatch = new List<string>(timelineDictionary.Keys); List<string> idsToMatch = new List<string>(timelineDictionary.Keys);
// For each animation in the list, check for and add missing timelines. // For each animation in the list, check for and add missing timelines.
HashSet<string> currentAnimationIDs = new HashSet<string>(); HashSet<string> currentAnimationIDs = new HashSet<string>();
foreach (Animation animation in animations) { foreach (Animation animation in animations) {
currentAnimationIDs.Clear(); currentAnimationIDs.Clear();
foreach (Timeline timeline in animation.Timelines) { foreach (Timeline timeline in animation.Timelines) {
if (timeline is EventTimeline) continue; if (timeline is EventTimeline) continue;
foreach (string propertyId in timeline.PropertyIds) { foreach (string propertyId in timeline.PropertyIds) {
currentAnimationIDs.Add(propertyId); currentAnimationIDs.Add(propertyId);
} }
} }
ExposedList<Timeline> animationTimelines = animation.Timelines; ExposedList<Timeline> animationTimelines = animation.Timelines;
foreach (string propertyId in idsToMatch) { foreach (string propertyId in idsToMatch) {
if (!currentAnimationIDs.Contains(propertyId)) if (!currentAnimationIDs.Contains(propertyId))
animationTimelines.Add(timelineDictionary[propertyId]); animationTimelines.Add(timelineDictionary[propertyId]);
} }
} }
// These are locals, but sometimes Unity's GC does weird stuff. So let's clean up. // These are locals, but sometimes Unity's GC does weird stuff. So let's clean up.
timelineDictionary.Clear(); timelineDictionary.Clear();
timelineDictionary = null; timelineDictionary = null;
idsToMatch.Clear(); idsToMatch.Clear();
idsToMatch = null; idsToMatch = null;
currentAnimationIDs.Clear(); currentAnimationIDs.Clear();
currentAnimationIDs = null; currentAnimationIDs = null;
} }
static Timeline GetFillerTimeline (Timeline timeline, SkeletonData skeletonData) { static Timeline GetFillerTimeline (Timeline timeline, SkeletonData skeletonData) {
if (timeline is RotateTimeline) if (timeline is RotateTimeline)
return GetFillerTimeline((RotateTimeline)timeline, skeletonData); return GetFillerTimeline((RotateTimeline)timeline, skeletonData);
if (timeline is TranslateTimeline) if (timeline is TranslateTimeline)
return GetFillerTimeline((TranslateTimeline)timeline, skeletonData); return GetFillerTimeline((TranslateTimeline)timeline, skeletonData);
if (timeline is ScaleTimeline) if (timeline is ScaleTimeline)
return GetFillerTimeline((ScaleTimeline)timeline, skeletonData); return GetFillerTimeline((ScaleTimeline)timeline, skeletonData);
if (timeline is ShearTimeline) if (timeline is ShearTimeline)
return GetFillerTimeline((ShearTimeline)timeline, skeletonData); return GetFillerTimeline((ShearTimeline)timeline, skeletonData);
if (timeline is AttachmentTimeline) if (timeline is AttachmentTimeline)
return GetFillerTimeline((AttachmentTimeline)timeline, skeletonData); return GetFillerTimeline((AttachmentTimeline)timeline, skeletonData);
if (timeline is RGBATimeline) if (timeline is RGBATimeline)
return GetFillerTimeline((RGBATimeline)timeline, skeletonData); return GetFillerTimeline((RGBATimeline)timeline, skeletonData);
if (timeline is RGBA2Timeline) if (timeline is RGBA2Timeline)
return GetFillerTimeline((RGBA2Timeline)timeline, skeletonData); return GetFillerTimeline((RGBA2Timeline)timeline, skeletonData);
if (timeline is DeformTimeline) if (timeline is DeformTimeline)
return GetFillerTimeline((DeformTimeline)timeline, skeletonData); return GetFillerTimeline((DeformTimeline)timeline, skeletonData);
if (timeline is DrawOrderTimeline) if (timeline is DrawOrderTimeline)
return GetFillerTimeline((DrawOrderTimeline)timeline, skeletonData); return GetFillerTimeline((DrawOrderTimeline)timeline, skeletonData);
if (timeline is IkConstraintTimeline) if (timeline is IkConstraintTimeline)
return GetFillerTimeline((IkConstraintTimeline)timeline, skeletonData); return GetFillerTimeline((IkConstraintTimeline)timeline, skeletonData);
if (timeline is TransformConstraintTimeline) if (timeline is TransformConstraintTimeline)
return GetFillerTimeline((TransformConstraintTimeline)timeline, skeletonData); return GetFillerTimeline((TransformConstraintTimeline)timeline, skeletonData);
if (timeline is PathConstraintPositionTimeline) if (timeline is PathConstraintPositionTimeline)
return GetFillerTimeline((PathConstraintPositionTimeline)timeline, skeletonData); return GetFillerTimeline((PathConstraintPositionTimeline)timeline, skeletonData);
if (timeline is PathConstraintSpacingTimeline) if (timeline is PathConstraintSpacingTimeline)
return GetFillerTimeline((PathConstraintSpacingTimeline)timeline, skeletonData); return GetFillerTimeline((PathConstraintSpacingTimeline)timeline, skeletonData);
if (timeline is PathConstraintMixTimeline) if (timeline is PathConstraintMixTimeline)
return GetFillerTimeline((PathConstraintMixTimeline)timeline, skeletonData); return GetFillerTimeline((PathConstraintMixTimeline)timeline, skeletonData);
return null; return null;
} }
static RotateTimeline GetFillerTimeline (RotateTimeline timeline, SkeletonData skeletonData) { static RotateTimeline GetFillerTimeline (RotateTimeline timeline, SkeletonData skeletonData) {
RotateTimeline t = new RotateTimeline(1, 0, timeline.BoneIndex); RotateTimeline t = new RotateTimeline(1, 0, timeline.BoneIndex);
t.SetFrame(0, 0, 0); t.SetFrame(0, 0, 0);
return t; return t;
} }
static TranslateTimeline GetFillerTimeline (TranslateTimeline timeline, SkeletonData skeletonData) { static TranslateTimeline GetFillerTimeline (TranslateTimeline timeline, SkeletonData skeletonData) {
TranslateTimeline t = new TranslateTimeline(1, 0, timeline.BoneIndex); TranslateTimeline t = new TranslateTimeline(1, 0, timeline.BoneIndex);
t.SetFrame(0, 0, 0, 0); t.SetFrame(0, 0, 0, 0);
return t; return t;
} }
static ScaleTimeline GetFillerTimeline (ScaleTimeline timeline, SkeletonData skeletonData) { static ScaleTimeline GetFillerTimeline (ScaleTimeline timeline, SkeletonData skeletonData) {
ScaleTimeline t = new ScaleTimeline(1, 0, timeline.BoneIndex); ScaleTimeline t = new ScaleTimeline(1, 0, timeline.BoneIndex);
t.SetFrame(0, 0, 0, 0); t.SetFrame(0, 0, 0, 0);
return t; return t;
} }
static ShearTimeline GetFillerTimeline (ShearTimeline timeline, SkeletonData skeletonData) { static ShearTimeline GetFillerTimeline (ShearTimeline timeline, SkeletonData skeletonData) {
ShearTimeline t = new ShearTimeline(1, 0, timeline.BoneIndex); ShearTimeline t = new ShearTimeline(1, 0, timeline.BoneIndex);
t.SetFrame(0, 0, 0, 0); t.SetFrame(0, 0, 0, 0);
return t; return t;
} }
static AttachmentTimeline GetFillerTimeline (AttachmentTimeline timeline, SkeletonData skeletonData) { static AttachmentTimeline GetFillerTimeline (AttachmentTimeline timeline, SkeletonData skeletonData) {
AttachmentTimeline t = new AttachmentTimeline(1, timeline.SlotIndex); AttachmentTimeline t = new AttachmentTimeline(1, timeline.SlotIndex);
SlotData slotData = skeletonData.Slots.Items[t.SlotIndex]; SlotData slotData = skeletonData.Slots.Items[t.SlotIndex];
t.SetFrame(0, 0, slotData.AttachmentName); t.SetFrame(0, 0, slotData.AttachmentName);
return t; return t;
} }
static RGBATimeline GetFillerTimeline (RGBATimeline timeline, SkeletonData skeletonData) { static RGBATimeline GetFillerTimeline (RGBATimeline timeline, SkeletonData skeletonData) {
RGBATimeline t = new RGBATimeline(1, 0, timeline.SlotIndex); RGBATimeline t = new RGBATimeline(1, 0, timeline.SlotIndex);
SlotData slotData = skeletonData.Slots.Items[t.SlotIndex]; SlotData slotData = skeletonData.Slots.Items[t.SlotIndex];
t.SetFrame(0, 0, slotData.R, slotData.G, slotData.B, slotData.A); t.SetFrame(0, 0, slotData.R, slotData.G, slotData.B, slotData.A);
return t; return t;
} }
static RGBA2Timeline GetFillerTimeline (RGBA2Timeline timeline, SkeletonData skeletonData) { static RGBA2Timeline GetFillerTimeline (RGBA2Timeline timeline, SkeletonData skeletonData) {
RGBA2Timeline t = new RGBA2Timeline(1, 0, timeline.SlotIndex); RGBA2Timeline t = new RGBA2Timeline(1, 0, timeline.SlotIndex);
SlotData slotData = skeletonData.Slots.Items[t.SlotIndex]; SlotData slotData = skeletonData.Slots.Items[t.SlotIndex];
t.SetFrame(0, 0, slotData.R, slotData.G, slotData.B, slotData.A, slotData.R2, slotData.G2, slotData.B2); t.SetFrame(0, 0, slotData.R, slotData.G, slotData.B, slotData.A, slotData.R2, slotData.G2, slotData.B2);
return t; return t;
} }
static DeformTimeline GetFillerTimeline (DeformTimeline timeline, SkeletonData skeletonData) { static DeformTimeline GetFillerTimeline (DeformTimeline timeline, SkeletonData skeletonData) {
DeformTimeline t = new DeformTimeline(1, 0, timeline.SlotIndex, timeline.Attachment); DeformTimeline t = new DeformTimeline(1, 0, timeline.SlotIndex, timeline.Attachment);
if (t.Attachment.IsWeighted()) { if (t.Attachment.IsWeighted()) {
t.SetFrame(0, 0, new float[t.Attachment.Vertices.Length]); t.SetFrame(0, 0, new float[t.Attachment.Vertices.Length]);
} else { } else {
t.SetFrame(0, 0, t.Attachment.Vertices.Clone() as float[]); t.SetFrame(0, 0, t.Attachment.Vertices.Clone() as float[]);
} }
return t; return t;
} }
static DrawOrderTimeline GetFillerTimeline (DrawOrderTimeline timeline, SkeletonData skeletonData) { static DrawOrderTimeline GetFillerTimeline (DrawOrderTimeline timeline, SkeletonData skeletonData) {
DrawOrderTimeline t = new DrawOrderTimeline(1); DrawOrderTimeline t = new DrawOrderTimeline(1);
t.SetFrame(0, 0, null); // null means use setup pose in DrawOrderTimeline.Apply. t.SetFrame(0, 0, null); // null means use setup pose in DrawOrderTimeline.Apply.
return t; return t;
} }
static IkConstraintTimeline GetFillerTimeline (IkConstraintTimeline timeline, SkeletonData skeletonData) { static IkConstraintTimeline GetFillerTimeline (IkConstraintTimeline timeline, SkeletonData skeletonData) {
IkConstraintTimeline t = new IkConstraintTimeline(1, 0, timeline.IkConstraintIndex); IkConstraintTimeline t = new IkConstraintTimeline(1, 0, timeline.IkConstraintIndex);
IkConstraintData ikConstraintData = skeletonData.IkConstraints.Items[timeline.IkConstraintIndex]; IkConstraintData ikConstraintData = skeletonData.IkConstraints.Items[timeline.IkConstraintIndex];
t.SetFrame(0, 0, ikConstraintData.Mix, ikConstraintData.Softness, ikConstraintData.BendDirection, ikConstraintData.Compress, ikConstraintData.Stretch); t.SetFrame(0, 0, ikConstraintData.Mix, ikConstraintData.Softness, ikConstraintData.BendDirection, ikConstraintData.Compress, ikConstraintData.Stretch);
return t; return t;
} }
static TransformConstraintTimeline GetFillerTimeline (TransformConstraintTimeline timeline, SkeletonData skeletonData) { static TransformConstraintTimeline GetFillerTimeline (TransformConstraintTimeline timeline, SkeletonData skeletonData) {
TransformConstraintTimeline t = new TransformConstraintTimeline(1, 0, timeline.TransformConstraintIndex); TransformConstraintTimeline t = new TransformConstraintTimeline(1, 0, timeline.TransformConstraintIndex);
TransformConstraintData data = skeletonData.TransformConstraints.Items[timeline.TransformConstraintIndex]; TransformConstraintData data = skeletonData.TransformConstraints.Items[timeline.TransformConstraintIndex];
t.SetFrame(0, 0, data.MixRotate, data.MixX, data.MixY, data.MixScaleX, data.MixScaleY, data.MixShearY); t.SetFrame(0, 0, data.MixRotate, data.MixX, data.MixY, data.MixScaleX, data.MixScaleY, data.MixShearY);
return t; return t;
} }
static PathConstraintPositionTimeline GetFillerTimeline (PathConstraintPositionTimeline timeline, SkeletonData skeletonData) { static PathConstraintPositionTimeline GetFillerTimeline (PathConstraintPositionTimeline timeline, SkeletonData skeletonData) {
PathConstraintPositionTimeline t = new PathConstraintPositionTimeline(1, 0, timeline.PathConstraintIndex); PathConstraintPositionTimeline t = new PathConstraintPositionTimeline(1, 0, timeline.PathConstraintIndex);
PathConstraintData data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex]; PathConstraintData data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex];
t.SetFrame(0, 0, data.Position); t.SetFrame(0, 0, data.Position);
return t; return t;
} }
static PathConstraintSpacingTimeline GetFillerTimeline (PathConstraintSpacingTimeline timeline, SkeletonData skeletonData) { static PathConstraintSpacingTimeline GetFillerTimeline (PathConstraintSpacingTimeline timeline, SkeletonData skeletonData) {
PathConstraintSpacingTimeline t = new PathConstraintSpacingTimeline(1, 0, timeline.PathConstraintIndex); PathConstraintSpacingTimeline t = new PathConstraintSpacingTimeline(1, 0, timeline.PathConstraintIndex);
PathConstraintData data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex]; PathConstraintData data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex];
t.SetFrame(0, 0, data.Spacing); t.SetFrame(0, 0, data.Spacing);
return t; return t;
} }
static PathConstraintMixTimeline GetFillerTimeline (PathConstraintMixTimeline timeline, SkeletonData skeletonData) { static PathConstraintMixTimeline GetFillerTimeline (PathConstraintMixTimeline timeline, SkeletonData skeletonData) {
PathConstraintMixTimeline t = new PathConstraintMixTimeline(1, 0, timeline.PathConstraintIndex); PathConstraintMixTimeline t = new PathConstraintMixTimeline(1, 0, timeline.PathConstraintIndex);
PathConstraintData data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex]; PathConstraintData data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex];
t.SetFrame(0, 0, data.RotateMix, data.MixX, data.MixY); t.SetFrame(0, 0, data.RotateMix, data.MixX, data.MixY);
return t; return t;
} }
#endregion #endregion
} }
} }
} }

View File

@ -1,41 +1,41 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class EquipAssetExample : ScriptableObject { public class EquipAssetExample : ScriptableObject {
public EquipSystemExample.EquipType equipType; public EquipSystemExample.EquipType equipType;
public Sprite sprite; public Sprite sprite;
public string description; public string description;
public int yourStats; public int yourStats;
} }
} }

View File

@ -1,60 +1,60 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class EquipButtonExample : MonoBehaviour { public class EquipButtonExample : MonoBehaviour {
public EquipAssetExample asset; public EquipAssetExample asset;
public EquipSystemExample equipSystem; public EquipSystemExample equipSystem;
public Image inventoryImage; public Image inventoryImage;
void OnValidate () { void OnValidate () {
MatchImage(); MatchImage();
} }
void MatchImage () { void MatchImage () {
if (inventoryImage != null) if (inventoryImage != null)
inventoryImage.sprite = asset.sprite; inventoryImage.sprite = asset.sprite;
} }
void Start () { void Start () {
MatchImage(); MatchImage();
Button button = GetComponent<Button>(); Button button = GetComponent<Button>();
button.onClick.AddListener( button.onClick.AddListener(
delegate { equipSystem.Equip(asset); } delegate { equipSystem.Equip(asset); }
); );
} }
} }
} }

View File

@ -1,107 +1,107 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class EquipSystemExample : MonoBehaviour, IHasSkeletonDataAsset { public class EquipSystemExample : MonoBehaviour, IHasSkeletonDataAsset {
// Implementing IHasSkeletonDataAsset allows Spine attribute drawers to automatically detect this component as a skeleton data source. // Implementing IHasSkeletonDataAsset allows Spine attribute drawers to automatically detect this component as a skeleton data source.
public SkeletonDataAsset skeletonDataAsset; public SkeletonDataAsset skeletonDataAsset;
SkeletonDataAsset IHasSkeletonDataAsset.SkeletonDataAsset { get { return this.skeletonDataAsset; } } SkeletonDataAsset IHasSkeletonDataAsset.SkeletonDataAsset { get { return this.skeletonDataAsset; } }
public Material sourceMaterial; public Material sourceMaterial;
public bool applyPMA = true; public bool applyPMA = true;
public List<EquipHook> equippables = new List<EquipHook>(); public List<EquipHook> equippables = new List<EquipHook>();
public EquipsVisualsComponentExample target; public EquipsVisualsComponentExample target;
public Dictionary<EquipAssetExample, Attachment> cachedAttachments = new Dictionary<EquipAssetExample, Attachment>(); public Dictionary<EquipAssetExample, Attachment> cachedAttachments = new Dictionary<EquipAssetExample, Attachment>();
[System.Serializable] [System.Serializable]
public class EquipHook { public class EquipHook {
public EquipType type; public EquipType type;
[SpineSlot] [SpineSlot]
public string slot; public string slot;
[SpineSkin] [SpineSkin]
public string templateSkin; public string templateSkin;
[SpineAttachment(skinField: "templateSkin")] [SpineAttachment(skinField: "templateSkin")]
public string templateAttachment; public string templateAttachment;
} }
public enum EquipType { public enum EquipType {
Gun, Gun,
Goggles Goggles
} }
public void Equip (EquipAssetExample asset) { public void Equip (EquipAssetExample asset) {
EquipType equipType = asset.equipType; EquipType equipType = asset.equipType;
EquipHook howToEquip = equippables.Find(x => x.type == equipType); EquipHook howToEquip = equippables.Find(x => x.type == equipType);
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true); SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);
int slotIndex = skeletonData.FindSlot(howToEquip.slot).Index; int slotIndex = skeletonData.FindSlot(howToEquip.slot).Index;
Attachment attachment = GenerateAttachmentFromEquipAsset(asset, slotIndex, howToEquip.templateSkin, howToEquip.templateAttachment); Attachment attachment = GenerateAttachmentFromEquipAsset(asset, slotIndex, howToEquip.templateSkin, howToEquip.templateAttachment);
target.Equip(slotIndex, howToEquip.templateAttachment, attachment); target.Equip(slotIndex, howToEquip.templateAttachment, attachment);
} }
Attachment GenerateAttachmentFromEquipAsset (EquipAssetExample asset, int slotIndex, string templateSkinName, string templateAttachmentName) { Attachment GenerateAttachmentFromEquipAsset (EquipAssetExample asset, int slotIndex, string templateSkinName, string templateAttachmentName) {
Attachment attachment; Attachment attachment;
cachedAttachments.TryGetValue(asset, out attachment); cachedAttachments.TryGetValue(asset, out attachment);
if (attachment == null) { if (attachment == null) {
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true); SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);
Skin templateSkin = skeletonData.FindSkin(templateSkinName); Skin templateSkin = skeletonData.FindSkin(templateSkinName);
Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName); Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName);
attachment = templateAttachment.GetRemappedClone(asset.sprite, sourceMaterial, premultiplyAlpha: this.applyPMA); attachment = templateAttachment.GetRemappedClone(asset.sprite, sourceMaterial, premultiplyAlpha: this.applyPMA);
// Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
// a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as shown in the method below. // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as shown in the method below.
cachedAttachments.Add(asset, attachment); // Cache this value for next time this asset is used. cachedAttachments.Add(asset, attachment); // Cache this value for next time this asset is used.
} }
return attachment; return attachment;
} }
public void Done () { public void Done () {
target.OptimizeSkin(); target.OptimizeSkin();
// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
// creates cached Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). // creates cached Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
// You can optionally clear the textures cache after multiple repack operations. // You can optionally clear the textures cache after multiple repack operations.
// Just be aware that while this cleanup frees up memory, it is also a costly operation // Just be aware that while this cleanup frees up memory, it is also a costly operation
// and will likely cause a spike in the framerate. // and will likely cause a spike in the framerate.
//AtlasUtilities.ClearCache(); //AtlasUtilities.ClearCache();
//Resources.UnloadUnusedAssets(); //Resources.UnloadUnusedAssets();
} }
} }
} }

View File

@ -1,100 +1,100 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class EquipsVisualsComponentExample : MonoBehaviour { public class EquipsVisualsComponentExample : MonoBehaviour {
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
[SpineSkin] [SpineSkin]
public string templateSkinName; public string templateSkinName;
Spine.Skin equipsSkin; Spine.Skin equipsSkin;
Spine.Skin collectedSkin; Spine.Skin collectedSkin;
public Material runtimeMaterial; public Material runtimeMaterial;
public Texture2D runtimeAtlas; public Texture2D runtimeAtlas;
void Start () { void Start () {
equipsSkin = new Skin("Equips"); equipsSkin = new Skin("Equips");
// OPTIONAL: Add all the attachments from the template skin. // OPTIONAL: Add all the attachments from the template skin.
Skin templateSkin = skeletonAnimation.Skeleton.Data.FindSkin(templateSkinName); Skin templateSkin = skeletonAnimation.Skeleton.Data.FindSkin(templateSkinName);
if (templateSkin != null) if (templateSkin != null)
equipsSkin.AddSkin(templateSkin); equipsSkin.AddSkin(templateSkin);
skeletonAnimation.Skeleton.Skin = equipsSkin; skeletonAnimation.Skeleton.Skin = equipsSkin;
RefreshSkeletonAttachments(); RefreshSkeletonAttachments();
} }
public void Equip (int slotIndex, string attachmentName, Attachment attachment) { public void Equip (int slotIndex, string attachmentName, Attachment attachment) {
equipsSkin.SetAttachment(slotIndex, attachmentName, attachment); equipsSkin.SetAttachment(slotIndex, attachmentName, attachment);
skeletonAnimation.Skeleton.SetSkin(equipsSkin); skeletonAnimation.Skeleton.SetSkin(equipsSkin);
RefreshSkeletonAttachments(); RefreshSkeletonAttachments();
} }
public void OptimizeSkin () { public void OptimizeSkin () {
// 1. Collect all the attachments of all active skins. // 1. Collect all the attachments of all active skins.
collectedSkin = collectedSkin ?? new Skin("Collected skin"); collectedSkin = collectedSkin ?? new Skin("Collected skin");
collectedSkin.Clear(); collectedSkin.Clear();
collectedSkin.AddSkin(skeletonAnimation.Skeleton.Data.DefaultSkin); collectedSkin.AddSkin(skeletonAnimation.Skeleton.Data.DefaultSkin);
collectedSkin.AddSkin(equipsSkin); collectedSkin.AddSkin(equipsSkin);
// 2. Create a repacked skin. // 2. Create a repacked skin.
// Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed
if (runtimeMaterial) if (runtimeMaterial)
Destroy(runtimeMaterial); Destroy(runtimeMaterial);
if (runtimeAtlas) if (runtimeAtlas)
Destroy(runtimeAtlas); Destroy(runtimeAtlas);
Skin repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, Skin repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial,
out runtimeMaterial, out runtimeAtlas, maxAtlasSize: 1024, clearCache: false); out runtimeMaterial, out runtimeAtlas, maxAtlasSize: 1024, clearCache: false);
collectedSkin.Clear(); collectedSkin.Clear();
// You can optionally clear the textures cache after each ore multiple repack operations are done. // You can optionally clear the textures cache after each ore multiple repack operations are done.
//AtlasUtilities.ClearCache(); //AtlasUtilities.ClearCache();
//Resources.UnloadUnusedAssets(); //Resources.UnloadUnusedAssets();
// 3. Use the repacked skin. // 3. Use the repacked skin.
skeletonAnimation.Skeleton.Skin = repackedSkin; skeletonAnimation.Skeleton.Skin = repackedSkin;
RefreshSkeletonAttachments(); RefreshSkeletonAttachments();
} }
void RefreshSkeletonAttachments () { void RefreshSkeletonAttachments () {
skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.Skeleton.SetSlotsToSetupPose();
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); //skeletonAnimation.Update(0); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); //skeletonAnimation.Update(0);
} }
} }
} }

View File

@ -1,50 +1,50 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class MixAndMatchSkinsButtonExample : MonoBehaviour { public class MixAndMatchSkinsButtonExample : MonoBehaviour {
public SkeletonDataAsset skeletonDataAsset; public SkeletonDataAsset skeletonDataAsset;
public MixAndMatchSkinsExample skinsSystem; public MixAndMatchSkinsExample skinsSystem;
[SpineSkin(dataField: "skeletonDataAsset")] public string itemSkin; [SpineSkin(dataField: "skeletonDataAsset")] public string itemSkin;
public MixAndMatchSkinsExample.ItemType itemType; public MixAndMatchSkinsExample.ItemType itemType;
void Start () { void Start () {
Button button = GetComponent<Button>(); Button button = GetComponent<Button>();
button.onClick.AddListener( button.onClick.AddListener(
delegate { skinsSystem.Equip(itemSkin, itemType); } delegate { skinsSystem.Equip(itemSkin, itemType); }
); );
} }
} }
} }

View File

@ -1,195 +1,195 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class MixAndMatchSkinsExample : MonoBehaviour { public class MixAndMatchSkinsExample : MonoBehaviour {
// character skins // character skins
[SpineSkin] public string baseSkin = "skin-base"; [SpineSkin] public string baseSkin = "skin-base";
[SpineSkin] public string eyelidsSkin = "eyelids/girly"; [SpineSkin] public string eyelidsSkin = "eyelids/girly";
// here we use arrays of strings to be able to cycle between them easily. // here we use arrays of strings to be able to cycle between them easily.
[SpineSkin] public string[] hairSkins = { "hair/brown", "hair/blue", "hair/pink", "hair/short-red", "hair/long-blue-with-scarf" }; [SpineSkin] public string[] hairSkins = { "hair/brown", "hair/blue", "hair/pink", "hair/short-red", "hair/long-blue-with-scarf" };
public int activeHairIndex = 0; public int activeHairIndex = 0;
[SpineSkin] public string[] eyesSkins = { "eyes/violet", "eyes/green", "eyes/yellow" }; [SpineSkin] public string[] eyesSkins = { "eyes/violet", "eyes/green", "eyes/yellow" };
public int activeEyesIndex = 0; public int activeEyesIndex = 0;
[SpineSkin] public string[] noseSkins = { "nose/short", "nose/long" }; [SpineSkin] public string[] noseSkins = { "nose/short", "nose/long" };
public int activeNoseIndex = 0; public int activeNoseIndex = 0;
// equipment skins // equipment skins
public enum ItemType { public enum ItemType {
Cloth, Cloth,
Pants, Pants,
Bag, Bag,
Hat Hat
} }
[SpineSkin] public string clothesSkin = "clothes/hoodie-orange"; [SpineSkin] public string clothesSkin = "clothes/hoodie-orange";
[SpineSkin] public string pantsSkin = "legs/pants-jeans"; [SpineSkin] public string pantsSkin = "legs/pants-jeans";
[SpineSkin] public string bagSkin = ""; [SpineSkin] public string bagSkin = "";
[SpineSkin] public string hatSkin = "accessories/hat-red-yellow"; [SpineSkin] public string hatSkin = "accessories/hat-red-yellow";
SkeletonAnimation skeletonAnimation; SkeletonAnimation skeletonAnimation;
// This "naked body" skin will likely change only once upon character creation, // This "naked body" skin will likely change only once upon character creation,
// so we store this combined set of non-equipment Skins for later re-use. // so we store this combined set of non-equipment Skins for later re-use.
Skin characterSkin; Skin characterSkin;
// for repacking the skin to a new atlas texture // for repacking the skin to a new atlas texture
public Material runtimeMaterial; public Material runtimeMaterial;
public Texture2D runtimeAtlas; public Texture2D runtimeAtlas;
void Awake () { void Awake () {
skeletonAnimation = this.GetComponent<SkeletonAnimation>(); skeletonAnimation = this.GetComponent<SkeletonAnimation>();
} }
void Start () { void Start () {
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void NextHairSkin () { public void NextHairSkin () {
activeHairIndex = (activeHairIndex + 1) % hairSkins.Length; activeHairIndex = (activeHairIndex + 1) % hairSkins.Length;
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void PrevHairSkin () { public void PrevHairSkin () {
activeHairIndex = (activeHairIndex + hairSkins.Length - 1) % hairSkins.Length; activeHairIndex = (activeHairIndex + hairSkins.Length - 1) % hairSkins.Length;
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void NextEyesSkin () { public void NextEyesSkin () {
activeEyesIndex = (activeEyesIndex + 1) % eyesSkins.Length; activeEyesIndex = (activeEyesIndex + 1) % eyesSkins.Length;
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void PrevEyesSkin () { public void PrevEyesSkin () {
activeEyesIndex = (activeEyesIndex + eyesSkins.Length - 1) % eyesSkins.Length; activeEyesIndex = (activeEyesIndex + eyesSkins.Length - 1) % eyesSkins.Length;
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void NextNoseSkin () { public void NextNoseSkin () {
activeNoseIndex = (activeNoseIndex + 1) % noseSkins.Length; activeNoseIndex = (activeNoseIndex + 1) % noseSkins.Length;
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void PrevNoseSkin () { public void PrevNoseSkin () {
activeNoseIndex = (activeNoseIndex + noseSkins.Length - 1) % noseSkins.Length; activeNoseIndex = (activeNoseIndex + noseSkins.Length - 1) % noseSkins.Length;
UpdateCharacterSkin(); UpdateCharacterSkin();
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void Equip (string itemSkin, ItemType itemType) { public void Equip (string itemSkin, ItemType itemType) {
switch (itemType) { switch (itemType) {
case ItemType.Cloth: case ItemType.Cloth:
clothesSkin = itemSkin; clothesSkin = itemSkin;
break; break;
case ItemType.Pants: case ItemType.Pants:
pantsSkin = itemSkin; pantsSkin = itemSkin;
break; break;
case ItemType.Bag: case ItemType.Bag:
bagSkin = itemSkin; bagSkin = itemSkin;
break; break;
case ItemType.Hat: case ItemType.Hat:
hatSkin = itemSkin; hatSkin = itemSkin;
break; break;
default: default:
break; break;
} }
UpdateCombinedSkin(); UpdateCombinedSkin();
} }
public void OptimizeSkin () { public void OptimizeSkin () {
// Create a repacked skin. // Create a repacked skin.
Skin previousSkin = skeletonAnimation.Skeleton.Skin; Skin previousSkin = skeletonAnimation.Skeleton.Skin;
// Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed
if (runtimeMaterial) if (runtimeMaterial)
Destroy(runtimeMaterial); Destroy(runtimeMaterial);
if (runtimeAtlas) if (runtimeAtlas)
Destroy(runtimeAtlas); Destroy(runtimeAtlas);
Skin repackedSkin = previousSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas); Skin repackedSkin = previousSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas);
previousSkin.Clear(); previousSkin.Clear();
// Use the repacked skin. // Use the repacked skin.
skeletonAnimation.Skeleton.Skin = repackedSkin; skeletonAnimation.Skeleton.Skin = repackedSkin;
skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.Skeleton.SetSlotsToSetupPose();
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
// cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
// You can optionally clear the textures cache after multiple repack operations. // You can optionally clear the textures cache after multiple repack operations.
// Just be aware that while this cleanup frees up memory, it is also a costly operation // Just be aware that while this cleanup frees up memory, it is also a costly operation
// and will likely cause a spike in the framerate. // and will likely cause a spike in the framerate.
AtlasUtilities.ClearCache(); AtlasUtilities.ClearCache();
Resources.UnloadUnusedAssets(); Resources.UnloadUnusedAssets();
} }
void UpdateCharacterSkin () { void UpdateCharacterSkin () {
Skeleton skeleton = skeletonAnimation.Skeleton; Skeleton skeleton = skeletonAnimation.Skeleton;
SkeletonData skeletonData = skeleton.Data; SkeletonData skeletonData = skeleton.Data;
characterSkin = new Skin("character-base"); characterSkin = new Skin("character-base");
// Note that the result Skin returned by calls to skeletonData.FindSkin() // Note that the result Skin returned by calls to skeletonData.FindSkin()
// could be cached once in Start() instead of searching for the same skin // could be cached once in Start() instead of searching for the same skin
// every time. For demonstration purposes we keep it simple here. // every time. For demonstration purposes we keep it simple here.
characterSkin.AddSkin(skeletonData.FindSkin(baseSkin)); characterSkin.AddSkin(skeletonData.FindSkin(baseSkin));
characterSkin.AddSkin(skeletonData.FindSkin(noseSkins[activeNoseIndex])); characterSkin.AddSkin(skeletonData.FindSkin(noseSkins[activeNoseIndex]));
characterSkin.AddSkin(skeletonData.FindSkin(eyelidsSkin)); characterSkin.AddSkin(skeletonData.FindSkin(eyelidsSkin));
characterSkin.AddSkin(skeletonData.FindSkin(eyesSkins[activeEyesIndex])); characterSkin.AddSkin(skeletonData.FindSkin(eyesSkins[activeEyesIndex]));
characterSkin.AddSkin(skeletonData.FindSkin(hairSkins[activeHairIndex])); characterSkin.AddSkin(skeletonData.FindSkin(hairSkins[activeHairIndex]));
} }
void AddEquipmentSkinsTo (Skin combinedSkin) { void AddEquipmentSkinsTo (Skin combinedSkin) {
Skeleton skeleton = skeletonAnimation.Skeleton; Skeleton skeleton = skeletonAnimation.Skeleton;
SkeletonData skeletonData = skeleton.Data; SkeletonData skeletonData = skeleton.Data;
combinedSkin.AddSkin(skeletonData.FindSkin(clothesSkin)); combinedSkin.AddSkin(skeletonData.FindSkin(clothesSkin));
combinedSkin.AddSkin(skeletonData.FindSkin(pantsSkin)); combinedSkin.AddSkin(skeletonData.FindSkin(pantsSkin));
if (!string.IsNullOrEmpty(bagSkin)) combinedSkin.AddSkin(skeletonData.FindSkin(bagSkin)); if (!string.IsNullOrEmpty(bagSkin)) combinedSkin.AddSkin(skeletonData.FindSkin(bagSkin));
if (!string.IsNullOrEmpty(hatSkin)) combinedSkin.AddSkin(skeletonData.FindSkin(hatSkin)); if (!string.IsNullOrEmpty(hatSkin)) combinedSkin.AddSkin(skeletonData.FindSkin(hatSkin));
} }
void UpdateCombinedSkin () { void UpdateCombinedSkin () {
Skeleton skeleton = skeletonAnimation.Skeleton; Skeleton skeleton = skeletonAnimation.Skeleton;
Skin resultCombinedSkin = new Skin("character-combined"); Skin resultCombinedSkin = new Skin("character-combined");
resultCombinedSkin.AddSkin(characterSkin); resultCombinedSkin.AddSkin(characterSkin);
AddEquipmentSkinsTo(resultCombinedSkin); AddEquipmentSkinsTo(resultCombinedSkin);
skeleton.SetSkin(resultCombinedSkin); skeleton.SetSkin(resultCombinedSkin);
skeleton.SetSlotsToSetupPose(); skeleton.SetSlotsToSetupPose();
} }
} }
} }

View File

@ -1,151 +1,151 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This is an example script that shows you how to change images on your skeleton using UnityEngine.Sprites. // This is an example script that shows you how to change images on your skeleton using UnityEngine.Sprites.
public class MixAndMatch : MonoBehaviour { public class MixAndMatch : MonoBehaviour {
#region Inspector #region Inspector
[SpineSkin] [SpineSkin]
public string templateAttachmentsSkin = "base"; public string templateAttachmentsSkin = "base";
public Material sourceMaterial; // This will be used as the basis for shader and material property settings. public Material sourceMaterial; // This will be used as the basis for shader and material property settings.
[Header("Visor")] [Header("Visor")]
public Sprite visorSprite; public Sprite visorSprite;
[SpineSlot] public string visorSlot; [SpineSlot] public string visorSlot;
[SpineAttachment(slotField: "visorSlot", skinField: "baseSkinName")] public string visorKey = "goggles"; [SpineAttachment(slotField: "visorSlot", skinField: "baseSkinName")] public string visorKey = "goggles";
[Header("Gun")] [Header("Gun")]
public Sprite gunSprite; public Sprite gunSprite;
[SpineSlot] public string gunSlot; [SpineSlot] public string gunSlot;
[SpineAttachment(slotField: "gunSlot", skinField: "baseSkinName")] public string gunKey = "gun"; [SpineAttachment(slotField: "gunSlot", skinField: "baseSkinName")] public string gunKey = "gun";
[Header("Runtime Repack")] [Header("Runtime Repack")]
public bool repack = true; public bool repack = true;
public BoundingBoxFollower bbFollower; public BoundingBoxFollower bbFollower;
[Header("Do not assign")] [Header("Do not assign")]
public Texture2D runtimeAtlas; public Texture2D runtimeAtlas;
public Material runtimeMaterial; public Material runtimeMaterial;
#endregion #endregion
Skin customSkin; Skin customSkin;
void OnValidate () { void OnValidate () {
if (sourceMaterial == null) { if (sourceMaterial == null) {
SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>(); SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>();
if (skeletonAnimation != null) if (skeletonAnimation != null)
sourceMaterial = skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial; sourceMaterial = skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial;
} }
} }
IEnumerator Start () { IEnumerator Start () {
yield return new WaitForSeconds(1f); // Delay for one second before applying. For testing. yield return new WaitForSeconds(1f); // Delay for one second before applying. For testing.
Apply(); Apply();
} }
void Apply () { void Apply () {
SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>(); SkeletonAnimation skeletonAnimation = GetComponent<SkeletonAnimation>();
Skeleton skeleton = skeletonAnimation.Skeleton; Skeleton skeleton = skeletonAnimation.Skeleton;
// STEP 0: PREPARE SKINS // STEP 0: PREPARE SKINS
// Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected. // Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected.
customSkin = customSkin ?? new Skin("custom skin"); // This requires that all customizations are done with skin placeholders defined in Spine. customSkin = customSkin ?? new Skin("custom skin"); // This requires that all customizations are done with skin placeholders defined in Spine.
Skin templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin); Skin templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin);
// STEP 1: "EQUIP" ITEMS USING SPRITES // STEP 1: "EQUIP" ITEMS USING SPRITES
// STEP 1.1 Find the original/template attachment. // STEP 1.1 Find the original/template attachment.
// Step 1.2 Get a clone of the original/template attachment. // Step 1.2 Get a clone of the original/template attachment.
// Step 1.3 Apply the Sprite image to the clone. // Step 1.3 Apply the Sprite image to the clone.
// Step 1.4 Add the remapped clone to the new custom skin. // Step 1.4 Add the remapped clone to the new custom skin.
// Let's do this for the visor. // Let's do this for the visor.
int visorSlotIndex = skeleton.Data.FindSlot(visorSlot).Index; // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster. int visorSlotIndex = skeleton.Data.FindSlot(visorSlot).Index; // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1 Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1
// Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
// a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done in the method below. // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done in the method below.
Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3 Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3
customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4 customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
// And now for the gun. // And now for the gun.
int gunSlotIndex = skeleton.Data.FindSlot(gunSlot).Index; int gunSlotIndex = skeleton.Data.FindSlot(gunSlot).Index;
Attachment templateGun = templateSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1 Attachment templateGun = templateSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1
Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3 Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3
if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4 if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4
// customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item. // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
// customSkin.Clear() // customSkin.Clear()
// Use skin.Clear() To remove all customizations. // Use skin.Clear() To remove all customizations.
// Customizations will fall back to the value in the default skin if it was defined there. // Customizations will fall back to the value in the default skin if it was defined there.
// To prevent fallback from happening, make sure the key is not defined in the default skin. // To prevent fallback from happening, make sure the key is not defined in the default skin.
// STEP 3: APPLY AND CLEAN UP. // STEP 3: APPLY AND CLEAN UP.
// Recommended, preferably at level-load-time: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS // Recommended, preferably at level-load-time: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS
// IMPORTANT NOTE: the GetRepackedSkin() operation is expensive - if multiple characters // IMPORTANT NOTE: the GetRepackedSkin() operation is expensive - if multiple characters
// need to call it every few seconds the overhead will outweigh the draw call benefits. // need to call it every few seconds the overhead will outweigh the draw call benefits.
// //
// Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector. // Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector.
// Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin. // Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin.
// call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture. // call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
if (repack) { if (repack) {
Skin repackedSkin = new Skin("repacked skin"); Skin repackedSkin = new Skin("repacked skin");
repackedSkin.AddSkin(skeleton.Data.DefaultSkin); // Include the "default" skin. (everything outside of skin placeholders) repackedSkin.AddSkin(skeleton.Data.DefaultSkin); // Include the "default" skin. (everything outside of skin placeholders)
repackedSkin.AddSkin(customSkin); // Include your new custom skin. repackedSkin.AddSkin(customSkin); // Include your new custom skin.
// Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed
if (runtimeMaterial) if (runtimeMaterial)
Destroy(runtimeMaterial); Destroy(runtimeMaterial);
if (runtimeAtlas) if (runtimeAtlas)
Destroy(runtimeAtlas); Destroy(runtimeAtlas);
repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin. repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
skeleton.SetSkin(repackedSkin); // Assign the repacked skin to your Skeleton. skeleton.SetSkin(repackedSkin); // Assign the repacked skin to your Skeleton.
if (bbFollower != null) bbFollower.Initialize(true); if (bbFollower != null) bbFollower.Initialize(true);
} else { } else {
skeleton.SetSkin(customSkin); // Just use the custom skin directly. skeleton.SetSkin(customSkin); // Just use the custom skin directly.
} }
skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose. skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
skeletonAnimation.Update(0); // Use the pose in the currently active animation. skeletonAnimation.Update(0); // Use the pose in the currently active animation.
// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
// cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
// You can optionally clear the textures cache after multiple repack operations. // You can optionally clear the textures cache after multiple repack operations.
// Just be aware that while this cleanup frees up memory, it is also a costly operation // Just be aware that while this cleanup frees up memory, it is also a costly operation
// and will likely cause a spike in the framerate. // and will likely cause a spike in the framerate.
AtlasUtilities.ClearCache(); AtlasUtilities.ClearCache();
Resources.UnloadUnusedAssets(); Resources.UnloadUnusedAssets();
} }
} }
} }

View File

@ -1,150 +1,150 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This is an example script that shows you how to change images on your skeleton using UnityEngine.Sprites. // This is an example script that shows you how to change images on your skeleton using UnityEngine.Sprites.
public class MixAndMatchGraphic : MonoBehaviour { public class MixAndMatchGraphic : MonoBehaviour {
#region Inspector #region Inspector
[SpineSkin] [SpineSkin]
public string baseSkinName = "base"; public string baseSkinName = "base";
public Material sourceMaterial; // This will be used as the basis for shader and material property settings. public Material sourceMaterial; // This will be used as the basis for shader and material property settings.
[Header("Visor")] [Header("Visor")]
public Sprite visorSprite; public Sprite visorSprite;
[SpineSlot] public string visorSlot; [SpineSlot] public string visorSlot;
[SpineAttachment(slotField: "visorSlot", skinField: "baseSkinName")] public string visorKey = "goggles"; [SpineAttachment(slotField: "visorSlot", skinField: "baseSkinName")] public string visorKey = "goggles";
[Header("Gun")] [Header("Gun")]
public Sprite gunSprite; public Sprite gunSprite;
[SpineSlot] public string gunSlot; [SpineSlot] public string gunSlot;
[SpineAttachment(slotField: "gunSlot", skinField: "baseSkinName")] public string gunKey = "gun"; [SpineAttachment(slotField: "gunSlot", skinField: "baseSkinName")] public string gunKey = "gun";
[Header("Runtime Repack Required!!")] [Header("Runtime Repack Required!!")]
public bool repack = true; public bool repack = true;
[Header("Do not assign")] [Header("Do not assign")]
public Texture2D runtimeAtlas; public Texture2D runtimeAtlas;
public Material runtimeMaterial; public Material runtimeMaterial;
#endregion #endregion
Skin customSkin; Skin customSkin;
void OnValidate () { void OnValidate () {
if (sourceMaterial == null) { if (sourceMaterial == null) {
SkeletonGraphic skeletonGraphic = GetComponent<SkeletonGraphic>(); SkeletonGraphic skeletonGraphic = GetComponent<SkeletonGraphic>();
if (skeletonGraphic != null) if (skeletonGraphic != null)
sourceMaterial = skeletonGraphic.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial; sourceMaterial = skeletonGraphic.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial;
} }
} }
IEnumerator Start () { IEnumerator Start () {
yield return new WaitForSeconds(1f); // Delay for 1 second. For testing. yield return new WaitForSeconds(1f); // Delay for 1 second. For testing.
Apply(); Apply();
} }
[ContextMenu("Apply")] [ContextMenu("Apply")]
void Apply () { void Apply () {
SkeletonGraphic skeletonGraphic = GetComponent<SkeletonGraphic>(); SkeletonGraphic skeletonGraphic = GetComponent<SkeletonGraphic>();
Skeleton skeleton = skeletonGraphic.Skeleton; Skeleton skeleton = skeletonGraphic.Skeleton;
// STEP 0: PREPARE SKINS // STEP 0: PREPARE SKINS
// Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected. // Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected.
customSkin = customSkin ?? new Skin("custom skin"); // This requires that all customizations are done with skin placeholders defined in Spine. customSkin = customSkin ?? new Skin("custom skin"); // This requires that all customizations are done with skin placeholders defined in Spine.
// Next let's get the skin that contains our source attachments. These are the attachments that // Next let's get the skin that contains our source attachments. These are the attachments that
Skin baseSkin = skeleton.Data.FindSkin(baseSkinName); Skin baseSkin = skeleton.Data.FindSkin(baseSkinName);
// STEP 1: "EQUIP" ITEMS USING SPRITES // STEP 1: "EQUIP" ITEMS USING SPRITES
// STEP 1.1 Find the original attachment. // STEP 1.1 Find the original attachment.
// Step 1.2 Get a clone of the original attachment. // Step 1.2 Get a clone of the original attachment.
// Step 1.3 Apply the Sprite image to it. // Step 1.3 Apply the Sprite image to it.
// Step 1.4 Add the remapped clone to the new custom skin. // Step 1.4 Add the remapped clone to the new custom skin.
// Let's do this for the visor. // Let's do this for the visor.
int visorSlotIndex = skeleton.Data.FindSlot(visorSlot).Index; // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster. int visorSlotIndex = skeleton.Data.FindSlot(visorSlot).Index; // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
Attachment baseAttachment = baseSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1 Attachment baseAttachment = baseSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1
// Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
// a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done below. // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done below.
Attachment newAttachment = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3 Attachment newAttachment = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3
customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4 customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
// And now for the gun. // And now for the gun.
int gunSlotIndex = skeleton.Data.FindSlot(gunSlot).Index; int gunSlotIndex = skeleton.Data.FindSlot(gunSlot).Index;
Attachment baseGun = baseSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1 Attachment baseGun = baseSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1
Attachment newGun = baseGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3 Attachment newGun = baseGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3
if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4 if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4
// customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item. // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
// customSkin.Clear() // customSkin.Clear()
// Use skin.Clear() To remove all customizations. // Use skin.Clear() To remove all customizations.
// Customizations will fall back to the value in the default skin if it was defined there. // Customizations will fall back to the value in the default skin if it was defined there.
// To prevent fallback from happening, make sure the key is not defined in the default skin. // To prevent fallback from happening, make sure the key is not defined in the default skin.
// STEP 3: APPLY AND CLEAN UP. // STEP 3: APPLY AND CLEAN UP.
// Recommended: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS // Recommended: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS
// Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector. // Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector.
// Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin. // Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin.
// call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture. // call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
if (repack) { if (repack) {
Skin repackedSkin = new Skin("repacked skin"); Skin repackedSkin = new Skin("repacked skin");
repackedSkin.AddSkin(skeleton.Data.DefaultSkin); repackedSkin.AddSkin(skeleton.Data.DefaultSkin);
repackedSkin.AddSkin(customSkin); repackedSkin.AddSkin(customSkin);
// Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed
if (runtimeMaterial) if (runtimeMaterial)
Destroy(runtimeMaterial); Destroy(runtimeMaterial);
if (runtimeAtlas) if (runtimeAtlas)
Destroy(runtimeAtlas); Destroy(runtimeAtlas);
repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas);
skeleton.SetSkin(repackedSkin); skeleton.SetSkin(repackedSkin);
} else { } else {
skeleton.SetSkin(customSkin); skeleton.SetSkin(customSkin);
} }
//skeleton.SetSlotsToSetupPose(); //skeleton.SetSlotsToSetupPose();
skeleton.SetToSetupPose(); skeleton.SetToSetupPose();
skeletonGraphic.Update(0); skeletonGraphic.Update(0);
skeletonGraphic.OverrideTexture = runtimeAtlas; skeletonGraphic.OverrideTexture = runtimeAtlas;
// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
// cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache(). // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
// You can optionally clear the textures cache after multiple repack operations. // You can optionally clear the textures cache after multiple repack operations.
// Just be aware that while this cleanup frees up memory, it is also a costly operation // Just be aware that while this cleanup frees up memory, it is also a costly operation
// and will likely cause a spike in the framerate. // and will likely cause a spike in the framerate.
AtlasUtilities.ClearCache(); AtlasUtilities.ClearCache();
Resources.UnloadUnusedAssets(); Resources.UnloadUnusedAssets();
} }
} }
} }

View File

@ -1,102 +1,102 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class RaggedySpineboy : MonoBehaviour { public class RaggedySpineboy : MonoBehaviour {
public LayerMask groundMask; public LayerMask groundMask;
public float restoreDuration = 0.5f; public float restoreDuration = 0.5f;
public Vector2 launchVelocity = new Vector2(50, 100); public Vector2 launchVelocity = new Vector2(50, 100);
Spine.Unity.Examples.SkeletonRagdoll2D ragdoll; Spine.Unity.Examples.SkeletonRagdoll2D ragdoll;
Collider2D naturalCollider; Collider2D naturalCollider;
void Start () { void Start () {
ragdoll = GetComponent<Spine.Unity.Examples.SkeletonRagdoll2D>(); ragdoll = GetComponent<Spine.Unity.Examples.SkeletonRagdoll2D>();
naturalCollider = GetComponent<Collider2D>(); naturalCollider = GetComponent<Collider2D>();
} }
void AddRigidbody () { void AddRigidbody () {
Rigidbody2D rb = gameObject.AddComponent<Rigidbody2D>(); Rigidbody2D rb = gameObject.AddComponent<Rigidbody2D>();
rb.freezeRotation = true; rb.freezeRotation = true;
naturalCollider.enabled = true; naturalCollider.enabled = true;
} }
void RemoveRigidbody () { void RemoveRigidbody () {
Destroy(GetComponent<Rigidbody2D>()); Destroy(GetComponent<Rigidbody2D>());
naturalCollider.enabled = false; naturalCollider.enabled = false;
} }
void OnMouseUp () { void OnMouseUp () {
if (naturalCollider.enabled) if (naturalCollider.enabled)
Launch(); Launch();
} }
void Launch () { void Launch () {
RemoveRigidbody(); RemoveRigidbody();
ragdoll.Apply(); ragdoll.Apply();
ragdoll.RootRigidbody.velocity = new Vector2(Random.Range(-launchVelocity.x, launchVelocity.x), launchVelocity.y); ragdoll.RootRigidbody.velocity = new Vector2(Random.Range(-launchVelocity.x, launchVelocity.x), launchVelocity.y);
StartCoroutine(WaitUntilStopped()); StartCoroutine(WaitUntilStopped());
} }
IEnumerator Restore () { IEnumerator Restore () {
Vector3 estimatedPos = ragdoll.EstimatedSkeletonPosition; Vector3 estimatedPos = ragdoll.EstimatedSkeletonPosition;
Vector3 rbPosition = ragdoll.RootRigidbody.position; Vector3 rbPosition = ragdoll.RootRigidbody.position;
Vector3 skeletonPoint = estimatedPos; Vector3 skeletonPoint = estimatedPos;
RaycastHit2D hit = Physics2D.Raycast((Vector2)rbPosition, (Vector2)(estimatedPos - rbPosition), Vector3.Distance(estimatedPos, rbPosition), groundMask); RaycastHit2D hit = Physics2D.Raycast((Vector2)rbPosition, (Vector2)(estimatedPos - rbPosition), Vector3.Distance(estimatedPos, rbPosition), groundMask);
if (hit.collider != null) if (hit.collider != null)
skeletonPoint = hit.point; skeletonPoint = hit.point;
ragdoll.RootRigidbody.isKinematic = true; ragdoll.RootRigidbody.isKinematic = true;
ragdoll.SetSkeletonPosition(skeletonPoint); ragdoll.SetSkeletonPosition(skeletonPoint);
yield return ragdoll.SmoothMix(0, restoreDuration); yield return ragdoll.SmoothMix(0, restoreDuration);
ragdoll.Remove(); ragdoll.Remove();
AddRigidbody(); AddRigidbody();
} }
IEnumerator WaitUntilStopped () { IEnumerator WaitUntilStopped () {
yield return new WaitForSeconds(0.5f); yield return new WaitForSeconds(0.5f);
float t = 0; float t = 0;
while (t < 0.5f) { while (t < 0.5f) {
t = (ragdoll.RootRigidbody.velocity.magnitude > 0.09f) ? 0 : t + Time.deltaTime; t = (ragdoll.RootRigidbody.velocity.magnitude > 0.09f) ? 0 : t + Time.deltaTime;
yield return null; yield return null;
} }
StartCoroutine(Restore()); StartCoroutine(Restore());
} }
} }
} }

View File

@ -1,44 +1,44 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
public class ReloadSceneOnKeyDown : MonoBehaviour { public class ReloadSceneOnKeyDown : MonoBehaviour {
public KeyCode reloadKey = KeyCode.R; public KeyCode reloadKey = KeyCode.R;
void Update () { void Update () {
if (Input.GetKeyDown(reloadKey)) if (Input.GetKeyDown(reloadKey))
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single); SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
} }
} }

View File

@ -1,92 +1,92 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2022, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2017_2_OR_NEWER #if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR_INT #define HAS_VECTOR_INT
#endif #endif
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class RenderTextureFadeoutExample : MonoBehaviour { public class RenderTextureFadeoutExample : MonoBehaviour {
public SkeletonRenderTextureFadeout renderTextureFadeout; public SkeletonRenderTextureFadeout renderTextureFadeout;
public SkeletonRenderTextureFadeout renderTextureFadeoutCanvas; public SkeletonRenderTextureFadeout renderTextureFadeoutCanvas;
public SkeletonRenderer normalSkeletonRenderer; public SkeletonRenderer normalSkeletonRenderer;
float fadeoutSeconds = 2.0f; float fadeoutSeconds = 2.0f;
float fadeoutSecondsRemaining; float fadeoutSecondsRemaining;
IEnumerator Start () { IEnumerator Start () {
while (true) { while (true) {
StartFadeoutBad(); StartFadeoutBad();
StartFadeoutGood(renderTextureFadeout); StartFadeoutGood(renderTextureFadeout);
StartFadeoutGood(renderTextureFadeoutCanvas); StartFadeoutGood(renderTextureFadeoutCanvas);
yield return new WaitForSeconds(fadeoutSeconds + 1.0f); yield return new WaitForSeconds(fadeoutSeconds + 1.0f);
} }
} }
void Update () { void Update () {
UpdateBadFadeOutAlpha(); UpdateBadFadeOutAlpha();
} }
void UpdateBadFadeOutAlpha () { void UpdateBadFadeOutAlpha () {
if (fadeoutSecondsRemaining == 0) if (fadeoutSecondsRemaining == 0)
return; return;
fadeoutSecondsRemaining -= Time.deltaTime; fadeoutSecondsRemaining -= Time.deltaTime;
if (fadeoutSecondsRemaining <= 0) { if (fadeoutSecondsRemaining <= 0) {
fadeoutSecondsRemaining = 0; fadeoutSecondsRemaining = 0;
return; return;
} }
float fadeoutAlpha = fadeoutSecondsRemaining / fadeoutSeconds; float fadeoutAlpha = fadeoutSecondsRemaining / fadeoutSeconds;
// changing transparency at a MeshRenderer does not yield the desired effect // changing transparency at a MeshRenderer does not yield the desired effect
// due to overlapping attachment meshes. // due to overlapping attachment meshes.
normalSkeletonRenderer.Skeleton.SetColor(new Color(1, 1, 1, fadeoutAlpha)); normalSkeletonRenderer.Skeleton.SetColor(new Color(1, 1, 1, fadeoutAlpha));
} }
void StartFadeoutBad () { void StartFadeoutBad () {
fadeoutSecondsRemaining = fadeoutSeconds; fadeoutSecondsRemaining = fadeoutSeconds;
} }
void StartFadeoutGood (SkeletonRenderTextureFadeout fadeoutComponent) { void StartFadeoutGood (SkeletonRenderTextureFadeout fadeoutComponent) {
fadeoutComponent.gameObject.SetActive(true); fadeoutComponent.gameObject.SetActive(true);
// enabling the SkeletonRenderTextureFadeout component starts the fadeout. // enabling the SkeletonRenderTextureFadeout component starts the fadeout.
fadeoutComponent.enabled = true; fadeoutComponent.enabled = true;
fadeoutComponent.OnFadeoutComplete -= DisableGameObject; fadeoutComponent.OnFadeoutComplete -= DisableGameObject;
fadeoutComponent.OnFadeoutComplete += DisableGameObject; fadeoutComponent.OnFadeoutComplete += DisableGameObject;
} }
void DisableGameObject (SkeletonRenderTextureFadeout target) { void DisableGameObject (SkeletonRenderTextureFadeout target) {
target.gameObject.SetActive(false); target.gameObject.SetActive(false);
} }
} }
} }

View File

@ -1,41 +1,41 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class Rotator : MonoBehaviour { public class Rotator : MonoBehaviour {
public Vector3 direction = new Vector3(0, 0, 1f); public Vector3 direction = new Vector3(0, 0, 1f);
public float speed = 1f; public float speed = 1f;
void Update () { void Update () {
transform.Rotate(direction * (speed * Time.deltaTime * 100f)); transform.Rotate(direction * (speed * Time.deltaTime * 100f));
} }
} }
} }

View File

@ -1,77 +1,120 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class RuntimeLoadFromExportsExample : MonoBehaviour { public class RuntimeLoadFromExportsExample : MonoBehaviour {
public TextAsset skeletonJson; public TextAsset skeletonJson;
public TextAsset atlasText; public TextAsset atlasText;
public Texture2D[] textures; public Texture2D[] textures;
public Material materialPropertySource; public Material materialPropertySource;
public float delay = 0; public float delay = 0;
public string skinName; public string skinName;
public string animationName; public string animationName;
SpineAtlasAsset runtimeAtlasAsset; SpineAtlasAsset runtimeAtlasAsset;
SkeletonDataAsset runtimeSkeletonDataAsset; SkeletonDataAsset runtimeSkeletonDataAsset;
SkeletonAnimation runtimeSkeletonAnimation; SkeletonAnimation runtimeSkeletonAnimation;
SkeletonGraphic runtimeSkeletonGraphic;
void CreateRuntimeAssetsAndGameObject () {
// 1. Create the AtlasAsset (needs atlas text asset and textures, and materials/shader); public bool blendModeMaterials = false;
// 2. Create SkeletonDataAsset (needs json or binary asset file, and an AtlasAsset) public bool applyAdditiveMaterial = false;
// 3. Create SkeletonAnimation (needs a valid SkeletonDataAsset) public BlendModeMaterials.TemplateMaterials blendModeTemplateMaterials;
public BlendModeMaterials.TemplateMaterials graphicBlendModeMaterials;
runtimeAtlasAsset = SpineAtlasAsset.CreateRuntimeInstance(atlasText, textures, materialPropertySource, true); public Material skeletonGraphicMaterial;
runtimeSkeletonDataAsset = SkeletonDataAsset.CreateRuntimeInstance(skeletonJson, runtimeAtlasAsset, true);
} void CreateRuntimeAssetsAndGameObject () {
// 1. Create the AtlasAsset (needs atlas text asset and textures, and materials/shader);
IEnumerator Start () { // 2. Create SkeletonDataAsset (needs json or binary asset file, and an AtlasAsset)
CreateRuntimeAssetsAndGameObject(); // 2.1 Optional: Setup blend mode materials at SkeletonDataAsset. Only required if the skeleton
if (delay > 0) { // uses blend modes which require blend mode materials.
runtimeSkeletonDataAsset.GetSkeletonData(false); // preload // 3.a Create SkeletonAnimation (needs a valid SkeletonDataAsset)
yield return new WaitForSeconds(delay); // 3.b Create SkeletonGraphic (needs a valid SkeletonDataAsset)
}
runtimeSkeletonAnimation = SkeletonAnimation.NewSkeletonAnimationGameObject(runtimeSkeletonDataAsset); runtimeAtlasAsset = SpineAtlasAsset.CreateRuntimeInstance(atlasText, textures, materialPropertySource, true, null, true);
runtimeSkeletonDataAsset = SkeletonDataAsset.CreateRuntimeInstance(skeletonJson, runtimeAtlasAsset, true);
// additional initialization if (blendModeMaterials)
runtimeSkeletonAnimation.Initialize(false); runtimeSkeletonDataAsset.SetupRuntimeBlendModeMaterials(
if (skinName != "") applyAdditiveMaterial, blendModeTemplateMaterials);
runtimeSkeletonAnimation.Skeleton.SetSkin(skinName); }
runtimeSkeletonAnimation.Skeleton.SetSlotsToSetupPose();
if (animationName != "") IEnumerator Start () {
runtimeSkeletonAnimation.AnimationState.SetAnimation(0, animationName, true); CreateRuntimeAssetsAndGameObject();
} if (delay > 0) {
} runtimeSkeletonDataAsset.GetSkeletonData(false); // preload
yield return new WaitForSeconds(delay);
} }
InstantiateSkeletonAnimation();
InstantiateSkeletonGraphic();
}
void InstantiateSkeletonAnimation () {
runtimeSkeletonAnimation = SkeletonAnimation.NewSkeletonAnimationGameObject(runtimeSkeletonDataAsset);
runtimeSkeletonAnimation.transform.parent = transform;
runtimeSkeletonAnimation.name = "SkeletonAnimation Instance";
// additional initialization
runtimeSkeletonAnimation.Initialize(false);
if (skinName != "")
runtimeSkeletonAnimation.Skeleton.SetSkin(skinName);
runtimeSkeletonAnimation.Skeleton.SetSlotsToSetupPose();
if (animationName != "")
runtimeSkeletonAnimation.AnimationState.SetAnimation(0, animationName, true);
}
void InstantiateSkeletonGraphic () {
Canvas canvas = this.GetComponentInChildren<Canvas>();
Transform parent = canvas.transform;
runtimeSkeletonGraphic = SkeletonGraphic.NewSkeletonGraphicGameObject(runtimeSkeletonDataAsset, parent, skeletonGraphicMaterial);
runtimeSkeletonGraphic.name = "SkeletonGraphic Instance";
if (blendModeMaterials) {
runtimeSkeletonGraphic.allowMultipleCanvasRenderers = true;
runtimeSkeletonGraphic.additiveMaterial = graphicBlendModeMaterials.additiveTemplate;
runtimeSkeletonGraphic.multiplyMaterial = graphicBlendModeMaterials.multiplyTemplate;
runtimeSkeletonGraphic.screenMaterial = graphicBlendModeMaterials.screenTemplate;
}
// additional initialization
runtimeSkeletonGraphic.Initialize(false);
if (skinName != "")
runtimeSkeletonGraphic.Skeleton.SetSkin(skinName);
runtimeSkeletonGraphic.Skeleton.SetSlotsToSetupPose();
if (animationName != "")
runtimeSkeletonGraphic.AnimationState.SetAnimation(0, animationName, true);
}
}
}

View File

@ -1,91 +1,91 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class BoneLocalOverride : MonoBehaviour { public class BoneLocalOverride : MonoBehaviour {
[SpineBone] [SpineBone]
public string boneName; public string boneName;
[Space] [Space]
[Range(0, 1)] public float alpha = 1; [Range(0, 1)] public float alpha = 1;
[Space] [Space]
public bool overridePosition = true; public bool overridePosition = true;
public Vector2 localPosition; public Vector2 localPosition;
[Space] [Space]
public bool overrideRotation = true; public bool overrideRotation = true;
[Range(0, 360)] public float rotation = 0; [Range(0, 360)] public float rotation = 0;
ISkeletonAnimation spineComponent; ISkeletonAnimation spineComponent;
Bone bone; Bone bone;
#if UNITY_EDITOR #if UNITY_EDITOR
void OnValidate () { void OnValidate () {
if (Application.isPlaying) return; if (Application.isPlaying) return;
if (spineComponent == null) spineComponent = GetComponent<ISkeletonAnimation>(); if (spineComponent == null) spineComponent = GetComponent<ISkeletonAnimation>();
if (spineComponent.IsNullOrDestroyed()) return; if (spineComponent.IsNullOrDestroyed()) return;
if (bone != null) bone.SetToSetupPose(); if (bone != null) bone.SetToSetupPose();
OverrideLocal(spineComponent); OverrideLocal(spineComponent);
} }
#endif #endif
void Awake () { void Awake () {
spineComponent = GetComponent<ISkeletonAnimation>(); spineComponent = GetComponent<ISkeletonAnimation>();
if (spineComponent == null) { this.enabled = false; return; } if (spineComponent == null) { this.enabled = false; return; }
spineComponent.UpdateLocal += OverrideLocal; spineComponent.UpdateLocal += OverrideLocal;
if (bone == null) { this.enabled = false; return; } if (bone == null) { this.enabled = false; return; }
} }
void OverrideLocal (ISkeletonAnimation animated) { void OverrideLocal (ISkeletonAnimation animated) {
if (bone == null || bone.Data.Name != boneName) { if (bone == null || bone.Data.Name != boneName) {
if (string.IsNullOrEmpty(boneName)) return; if (string.IsNullOrEmpty(boneName)) return;
bone = spineComponent.Skeleton.FindBone(boneName); bone = spineComponent.Skeleton.FindBone(boneName);
if (bone == null) { if (bone == null) {
Debug.LogFormat("Cannot find bone: '{0}'", boneName); Debug.LogFormat("Cannot find bone: '{0}'", boneName);
return; return;
} }
} }
if (overridePosition) { if (overridePosition) {
bone.X = Mathf.Lerp(bone.X, localPosition.x, alpha); bone.X = Mathf.Lerp(bone.X, localPosition.x, alpha);
bone.Y = Mathf.Lerp(bone.Y, localPosition.y, alpha); bone.Y = Mathf.Lerp(bone.Y, localPosition.y, alpha);
} }
if (overrideRotation) if (overrideRotation)
bone.Rotation = Mathf.Lerp(bone.Rotation, rotation, alpha); bone.Rotation = Mathf.Lerp(bone.Rotation, rotation, alpha);
} }
} }
} }

View File

@ -1,62 +1,62 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class CombinedSkin : MonoBehaviour { public class CombinedSkin : MonoBehaviour {
[SpineSkin] [SpineSkin]
public List<string> skinsToCombine; public List<string> skinsToCombine;
Skin combinedSkin; Skin combinedSkin;
void Start () { void Start () {
ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>(); ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>();
if (skeletonComponent == null) return; if (skeletonComponent == null) return;
Skeleton skeleton = skeletonComponent.Skeleton; Skeleton skeleton = skeletonComponent.Skeleton;
if (skeleton == null) return; if (skeleton == null) return;
combinedSkin = combinedSkin ?? new Skin("combined"); combinedSkin = combinedSkin ?? new Skin("combined");
combinedSkin.Clear(); combinedSkin.Clear();
foreach (string skinName in skinsToCombine) { foreach (string skinName in skinsToCombine) {
Skin skin = skeleton.Data.FindSkin(skinName); Skin skin = skeleton.Data.FindSkin(skinName);
if (skin != null) combinedSkin.AddSkin(skin); if (skin != null) combinedSkin.AddSkin(skin);
} }
skeleton.SetSkin(combinedSkin); skeleton.SetSkin(combinedSkin);
skeleton.SetToSetupPose(); skeleton.SetToSetupPose();
IAnimationStateComponent animationStateComponent = skeletonComponent as IAnimationStateComponent; IAnimationStateComponent animationStateComponent = skeletonComponent as IAnimationStateComponent;
if (animationStateComponent != null) animationStateComponent.AnimationState.Apply(skeleton); if (animationStateComponent != null) animationStateComponent.AnimationState.Apply(skeleton);
} }
} }
} }

View File

@ -1,201 +1,201 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
[RequireComponent(typeof(SkeletonRenderer))] [RequireComponent(typeof(SkeletonRenderer))]
public class SkeletonGhost : MonoBehaviour { public class SkeletonGhost : MonoBehaviour {
// Internal Settings // Internal Settings
const HideFlags GhostHideFlags = HideFlags.HideInHierarchy; const HideFlags GhostHideFlags = HideFlags.HideInHierarchy;
const string GhostingShaderName = "Spine/Special/SkeletonGhost"; const string GhostingShaderName = "Spine/Special/SkeletonGhost";
[Header("Animation")] [Header("Animation")]
public bool ghostingEnabled = true; public bool ghostingEnabled = true;
[Tooltip("The time between invididual ghost pieces being spawned.")] [Tooltip("The time between invididual ghost pieces being spawned.")]
[UnityEngine.Serialization.FormerlySerializedAs("spawnRate")] [UnityEngine.Serialization.FormerlySerializedAs("spawnRate")]
public float spawnInterval = 1f / 30f; public float spawnInterval = 1f / 30f;
[Tooltip("Maximum number of ghosts that can exist at a time. If the fade speed is not fast enough, the oldest ghost will immediately disappear to enforce the maximum number.")] [Tooltip("Maximum number of ghosts that can exist at a time. If the fade speed is not fast enough, the oldest ghost will immediately disappear to enforce the maximum number.")]
public int maximumGhosts = 10; public int maximumGhosts = 10;
public float fadeSpeed = 10; public float fadeSpeed = 10;
[Header("Rendering")] [Header("Rendering")]
public Shader ghostShader; public Shader ghostShader;
public Color32 color = new Color32(0xFF, 0xFF, 0xFF, 0x00); // default for additive. public Color32 color = new Color32(0xFF, 0xFF, 0xFF, 0x00); // default for additive.
[Tooltip("Remember to set color alpha to 0 if Additive is true")] [Tooltip("Remember to set color alpha to 0 if Additive is true")]
public bool additive = true; public bool additive = true;
[Tooltip("0 is Color and Alpha, 1 is Alpha only.")] [Tooltip("0 is Color and Alpha, 1 is Alpha only.")]
[Range(0, 1)] [Range(0, 1)]
public float textureFade = 1; public float textureFade = 1;
[Header("Sorting")] [Header("Sorting")]
public bool sortWithDistanceOnly; public bool sortWithDistanceOnly;
public float zOffset = 0f; public float zOffset = 0f;
float nextSpawnTime; float nextSpawnTime;
SkeletonGhostRenderer[] pool; SkeletonGhostRenderer[] pool;
int poolIndex = 0; int poolIndex = 0;
SkeletonRenderer skeletonRenderer; SkeletonRenderer skeletonRenderer;
MeshRenderer meshRenderer; MeshRenderer meshRenderer;
MeshFilter meshFilter; MeshFilter meshFilter;
readonly Dictionary<Material, Material> materialTable = new Dictionary<Material, Material>(); readonly Dictionary<Material, Material> materialTable = new Dictionary<Material, Material>();
void Start () { void Start () {
Initialize(false); Initialize(false);
} }
public void Initialize (bool overwrite) { public void Initialize (bool overwrite) {
if (pool == null || overwrite) { if (pool == null || overwrite) {
if (ghostShader == null) if (ghostShader == null)
ghostShader = Shader.Find(GhostingShaderName); ghostShader = Shader.Find(GhostingShaderName);
skeletonRenderer = GetComponent<SkeletonRenderer>(); skeletonRenderer = GetComponent<SkeletonRenderer>();
meshFilter = GetComponent<MeshFilter>(); meshFilter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>(); meshRenderer = GetComponent<MeshRenderer>();
nextSpawnTime = Time.time + spawnInterval; nextSpawnTime = Time.time + spawnInterval;
pool = new SkeletonGhostRenderer[maximumGhosts]; pool = new SkeletonGhostRenderer[maximumGhosts];
for (int i = 0; i < maximumGhosts; i++) { for (int i = 0; i < maximumGhosts; i++) {
GameObject go = new GameObject(gameObject.name + " Ghost", typeof(SkeletonGhostRenderer)); GameObject go = new GameObject(gameObject.name + " Ghost", typeof(SkeletonGhostRenderer));
pool[i] = go.GetComponent<SkeletonGhostRenderer>(); pool[i] = go.GetComponent<SkeletonGhostRenderer>();
go.SetActive(false); go.SetActive(false);
go.hideFlags = GhostHideFlags; go.hideFlags = GhostHideFlags;
} }
IAnimationStateComponent skeletonAnimation = skeletonRenderer as Spine.Unity.IAnimationStateComponent; IAnimationStateComponent skeletonAnimation = skeletonRenderer as Spine.Unity.IAnimationStateComponent;
if (skeletonAnimation != null) if (skeletonAnimation != null)
skeletonAnimation.AnimationState.Event += OnEvent; skeletonAnimation.AnimationState.Event += OnEvent;
} }
} }
//SkeletonAnimation //SkeletonAnimation
/* /*
* Int Value: 0 sets ghostingEnabled to false, 1 sets ghostingEnabled to true * Int Value: 0 sets ghostingEnabled to false, 1 sets ghostingEnabled to true
* Float Value: Values greater than 0 set the spawnRate equal the float value * Float Value: Values greater than 0 set the spawnRate equal the float value
* String Value: Pass RGBA hex color values in to set the color property. IE: "A0FF8BFF" * String Value: Pass RGBA hex color values in to set the color property. IE: "A0FF8BFF"
*/ */
void OnEvent (Spine.TrackEntry trackEntry, Spine.Event e) { void OnEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
if (e.Data.Name.Equals("Ghosting", System.StringComparison.Ordinal)) { if (e.Data.Name.Equals("Ghosting", System.StringComparison.Ordinal)) {
ghostingEnabled = e.Int > 0; ghostingEnabled = e.Int > 0;
if (e.Float > 0) if (e.Float > 0)
spawnInterval = e.Float; spawnInterval = e.Float;
if (!string.IsNullOrEmpty(e.String)) if (!string.IsNullOrEmpty(e.String))
this.color = HexToColor(e.String); this.color = HexToColor(e.String);
} }
} }
//SkeletonAnimator //SkeletonAnimator
//SkeletonAnimator or Mecanim based animations only support toggling ghostingEnabled. Be sure not to set anything other than the Int param in Spine or String will take priority. //SkeletonAnimator or Mecanim based animations only support toggling ghostingEnabled. Be sure not to set anything other than the Int param in Spine or String will take priority.
void Ghosting (float val) { void Ghosting (float val) {
ghostingEnabled = val > 0; ghostingEnabled = val > 0;
} }
void Update () { void Update () {
if (!ghostingEnabled || poolIndex >= pool.Length) if (!ghostingEnabled || poolIndex >= pool.Length)
return; return;
if (Time.time >= nextSpawnTime) { if (Time.time >= nextSpawnTime) {
GameObject go = pool[poolIndex].gameObject; GameObject go = pool[poolIndex].gameObject;
Material[] materials = meshRenderer.sharedMaterials; Material[] materials = meshRenderer.sharedMaterials;
for (int i = 0; i < materials.Length; i++) { for (int i = 0; i < materials.Length; i++) {
Material originalMat = materials[i]; Material originalMat = materials[i];
Material ghostMat; Material ghostMat;
if (!materialTable.ContainsKey(originalMat)) { if (!materialTable.ContainsKey(originalMat)) {
ghostMat = new Material(originalMat) { ghostMat = new Material(originalMat) {
shader = ghostShader, shader = ghostShader,
color = Color.white color = Color.white
}; };
if (ghostMat.HasProperty("_TextureFade")) if (ghostMat.HasProperty("_TextureFade"))
ghostMat.SetFloat("_TextureFade", textureFade); ghostMat.SetFloat("_TextureFade", textureFade);
materialTable.Add(originalMat, ghostMat); materialTable.Add(originalMat, ghostMat);
} else { } else {
ghostMat = materialTable[originalMat]; ghostMat = materialTable[originalMat];
} }
materials[i] = ghostMat; materials[i] = ghostMat;
} }
Transform goTransform = go.transform; Transform goTransform = go.transform;
goTransform.parent = transform; goTransform.parent = transform;
pool[poolIndex].Initialize(meshFilter.sharedMesh, materials, color, additive, fadeSpeed, meshRenderer.sortingLayerID, (sortWithDistanceOnly) ? meshRenderer.sortingOrder : meshRenderer.sortingOrder - 1); pool[poolIndex].Initialize(meshFilter.sharedMesh, materials, color, additive, fadeSpeed, meshRenderer.sortingLayerID, (sortWithDistanceOnly) ? meshRenderer.sortingOrder : meshRenderer.sortingOrder - 1);
goTransform.localPosition = new Vector3(0f, 0f, zOffset); goTransform.localPosition = new Vector3(0f, 0f, zOffset);
goTransform.localRotation = Quaternion.identity; goTransform.localRotation = Quaternion.identity;
goTransform.localScale = Vector3.one; goTransform.localScale = Vector3.one;
goTransform.parent = null; goTransform.parent = null;
poolIndex++; poolIndex++;
if (poolIndex == pool.Length) if (poolIndex == pool.Length)
poolIndex = 0; poolIndex = 0;
nextSpawnTime = Time.time + spawnInterval; nextSpawnTime = Time.time + spawnInterval;
} }
} }
void OnDestroy () { void OnDestroy () {
if (pool != null) { if (pool != null) {
for (int i = 0; i < maximumGhosts; i++) for (int i = 0; i < maximumGhosts; i++)
if (pool[i] != null) pool[i].Cleanup(); if (pool[i] != null) pool[i].Cleanup();
} }
foreach (Material mat in materialTable.Values) foreach (Material mat in materialTable.Values)
Destroy(mat); Destroy(mat);
} }
// based on UnifyWiki http://wiki.unity3d.com/index.php?title=HexConverter // based on UnifyWiki http://wiki.unity3d.com/index.php?title=HexConverter
static Color32 HexToColor (string hex) { static Color32 HexToColor (string hex) {
const System.Globalization.NumberStyles HexNumber = System.Globalization.NumberStyles.HexNumber; const System.Globalization.NumberStyles HexNumber = System.Globalization.NumberStyles.HexNumber;
if (hex.Length < 6) if (hex.Length < 6)
return Color.magenta; return Color.magenta;
hex = hex.Replace("#", ""); hex = hex.Replace("#", "");
byte r = byte.Parse(hex.Substring(0, 2), HexNumber); byte r = byte.Parse(hex.Substring(0, 2), HexNumber);
byte g = byte.Parse(hex.Substring(2, 2), HexNumber); byte g = byte.Parse(hex.Substring(2, 2), HexNumber);
byte b = byte.Parse(hex.Substring(4, 2), HexNumber); byte b = byte.Parse(hex.Substring(4, 2), HexNumber);
byte a = 0xFF; byte a = 0xFF;
if (hex.Length == 8) if (hex.Length == 8)
a = byte.Parse(hex.Substring(6, 2), HexNumber); a = byte.Parse(hex.Substring(6, 2), HexNumber);
return new Color32(r, g, b, a); return new Color32(r, g, b, a);
} }
} }
} }

View File

@ -1,128 +1,128 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SkeletonGhostRenderer : MonoBehaviour { public class SkeletonGhostRenderer : MonoBehaviour {
static readonly Color32 TransparentBlack = new Color32(0, 0, 0, 0); static readonly Color32 TransparentBlack = new Color32(0, 0, 0, 0);
const string colorPropertyName = "_Color"; const string colorPropertyName = "_Color";
float fadeSpeed = 10; float fadeSpeed = 10;
Color32 startColor; Color32 startColor;
MeshFilter meshFilter; MeshFilter meshFilter;
MeshRenderer meshRenderer; MeshRenderer meshRenderer;
MaterialPropertyBlock mpb; MaterialPropertyBlock mpb;
int colorId; int colorId;
void Awake () { void Awake () {
meshRenderer = gameObject.AddComponent<MeshRenderer>(); meshRenderer = gameObject.AddComponent<MeshRenderer>();
meshFilter = gameObject.AddComponent<MeshFilter>(); meshFilter = gameObject.AddComponent<MeshFilter>();
colorId = Shader.PropertyToID(colorPropertyName); colorId = Shader.PropertyToID(colorPropertyName);
mpb = new MaterialPropertyBlock(); mpb = new MaterialPropertyBlock();
} }
public void Initialize (Mesh mesh, Material[] materials, Color32 color, bool additive, float speed, int sortingLayerID, int sortingOrder) { public void Initialize (Mesh mesh, Material[] materials, Color32 color, bool additive, float speed, int sortingLayerID, int sortingOrder) {
StopAllCoroutines(); StopAllCoroutines();
gameObject.SetActive(true); gameObject.SetActive(true);
meshRenderer.sharedMaterials = materials; meshRenderer.sharedMaterials = materials;
meshRenderer.sortingLayerID = sortingLayerID; meshRenderer.sortingLayerID = sortingLayerID;
meshRenderer.sortingOrder = sortingOrder; meshRenderer.sortingOrder = sortingOrder;
meshFilter.sharedMesh = Instantiate(mesh); meshFilter.sharedMesh = Instantiate(mesh);
startColor = color; startColor = color;
mpb.SetColor(colorId, color); mpb.SetColor(colorId, color);
meshRenderer.SetPropertyBlock(mpb); meshRenderer.SetPropertyBlock(mpb);
fadeSpeed = speed; fadeSpeed = speed;
if (additive) if (additive)
StartCoroutine(FadeAdditive()); StartCoroutine(FadeAdditive());
else else
StartCoroutine(Fade()); StartCoroutine(Fade());
} }
IEnumerator Fade () { IEnumerator Fade () {
Color32 c = startColor; Color32 c = startColor;
Color32 black = SkeletonGhostRenderer.TransparentBlack; Color32 black = SkeletonGhostRenderer.TransparentBlack;
float t = 1f; float t = 1f;
for (float hardTimeLimit = 5f; hardTimeLimit > 0; hardTimeLimit -= Time.deltaTime) { for (float hardTimeLimit = 5f; hardTimeLimit > 0; hardTimeLimit -= Time.deltaTime) {
c = Color32.Lerp(black, startColor, t); c = Color32.Lerp(black, startColor, t);
mpb.SetColor(colorId, c); mpb.SetColor(colorId, c);
meshRenderer.SetPropertyBlock(mpb); meshRenderer.SetPropertyBlock(mpb);
t = Mathf.Lerp(t, 0, Time.deltaTime * fadeSpeed); t = Mathf.Lerp(t, 0, Time.deltaTime * fadeSpeed);
if (t <= 0) if (t <= 0)
break; break;
yield return null; yield return null;
} }
Destroy(meshFilter.sharedMesh); Destroy(meshFilter.sharedMesh);
gameObject.SetActive(false); gameObject.SetActive(false);
} }
IEnumerator FadeAdditive () { IEnumerator FadeAdditive () {
Color32 c = startColor; Color32 c = startColor;
Color32 black = SkeletonGhostRenderer.TransparentBlack; Color32 black = SkeletonGhostRenderer.TransparentBlack;
float t = 1f; float t = 1f;
for (float hardTimeLimit = 5f; hardTimeLimit > 0; hardTimeLimit -= Time.deltaTime) { for (float hardTimeLimit = 5f; hardTimeLimit > 0; hardTimeLimit -= Time.deltaTime) {
c = Color32.Lerp(black, startColor, t); c = Color32.Lerp(black, startColor, t);
mpb.SetColor(colorId, c); mpb.SetColor(colorId, c);
meshRenderer.SetPropertyBlock(mpb); meshRenderer.SetPropertyBlock(mpb);
t = Mathf.Lerp(t, 0, Time.deltaTime * fadeSpeed); t = Mathf.Lerp(t, 0, Time.deltaTime * fadeSpeed);
if (t <= 0) if (t <= 0)
break; break;
yield return null; yield return null;
} }
Destroy(meshFilter.sharedMesh); Destroy(meshFilter.sharedMesh);
gameObject.SetActive(false); gameObject.SetActive(false);
} }
public void Cleanup () { public void Cleanup () {
if (meshFilter != null && meshFilter.sharedMesh != null) if (meshFilter != null && meshFilter.sharedMesh != null)
Destroy(meshFilter.sharedMesh); Destroy(meshFilter.sharedMesh);
Destroy(gameObject); Destroy(gameObject);
} }
} }
} }

View File

@ -1,81 +1,81 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
/// <summary> /// <summary>
/// Example code for a component that replaces the default attachment of a slot with an image from a Spine atlas.</summary> /// Example code for a component that replaces the default attachment of a slot with an image from a Spine atlas.</summary>
public class AtlasRegionAttacher : MonoBehaviour { public class AtlasRegionAttacher : MonoBehaviour {
[System.Serializable] [System.Serializable]
public class SlotRegionPair { public class SlotRegionPair {
[SpineSlot] public string slot; [SpineSlot] public string slot;
[SpineAtlasRegion] public string region; [SpineAtlasRegion] public string region;
} }
[SerializeField] protected SpineAtlasAsset atlasAsset; [SerializeField] protected SpineAtlasAsset atlasAsset;
[SerializeField] protected bool inheritProperties = true; [SerializeField] protected bool inheritProperties = true;
[SerializeField] protected List<SlotRegionPair> attachments = new List<SlotRegionPair>(); [SerializeField] protected List<SlotRegionPair> attachments = new List<SlotRegionPair>();
Atlas atlas; Atlas atlas;
void Awake () { void Awake () {
SkeletonRenderer skeletonRenderer = GetComponent<SkeletonRenderer>(); SkeletonRenderer skeletonRenderer = GetComponent<SkeletonRenderer>();
skeletonRenderer.OnRebuild += Apply; skeletonRenderer.OnRebuild += Apply;
if (skeletonRenderer.valid) Apply(skeletonRenderer); if (skeletonRenderer.valid) Apply(skeletonRenderer);
} }
void Apply (SkeletonRenderer skeletonRenderer) { void Apply (SkeletonRenderer skeletonRenderer) {
if (!this.enabled) return; if (!this.enabled) return;
atlas = atlasAsset.GetAtlas(); atlas = atlasAsset.GetAtlas();
if (atlas == null) return; if (atlas == null) return;
float scale = skeletonRenderer.skeletonDataAsset.scale; float scale = skeletonRenderer.skeletonDataAsset.scale;
foreach (SlotRegionPair entry in attachments) { foreach (SlotRegionPair entry in attachments) {
Slot slot = skeletonRenderer.Skeleton.FindSlot(entry.slot); Slot slot = skeletonRenderer.Skeleton.FindSlot(entry.slot);
Attachment originalAttachment = slot.Attachment; Attachment originalAttachment = slot.Attachment;
AtlasRegion region = atlas.FindRegion(entry.region); AtlasRegion region = atlas.FindRegion(entry.region);
if (region == null) { if (region == null) {
slot.Attachment = null; slot.Attachment = null;
} else if (inheritProperties && originalAttachment != null) { } else if (inheritProperties && originalAttachment != null) {
slot.Attachment = originalAttachment.GetRemappedClone(region, true, true, scale); slot.Attachment = originalAttachment.GetRemappedClone(region, true, true, scale);
} else { } else {
RegionAttachment newRegionAttachment = region.ToRegionAttachment(region.name, scale); RegionAttachment newRegionAttachment = region.ToRegionAttachment(region.name, scale);
slot.Attachment = newRegionAttachment; slot.Attachment = newRegionAttachment;
} }
} }
} }
} }
} }

View File

@ -1,184 +1,184 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Original Contribution by: Mitch Thompson // Original Contribution by: Mitch Thompson
using Spine.Unity.AttachmentTools; using Spine.Unity.AttachmentTools;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SpriteAttacher : MonoBehaviour { public class SpriteAttacher : MonoBehaviour {
public const string DefaultPMAShader = "Spine/Skeleton"; public const string DefaultPMAShader = "Spine/Skeleton";
public const string DefaultStraightAlphaShader = "Sprites/Default"; public const string DefaultStraightAlphaShader = "Sprites/Default";
#region Inspector #region Inspector
public bool attachOnStart = true; public bool attachOnStart = true;
public bool overrideAnimation = true; public bool overrideAnimation = true;
public Sprite sprite; public Sprite sprite;
[SpineSlot] public string slot; [SpineSlot] public string slot;
#endregion #endregion
#if UNITY_EDITOR #if UNITY_EDITOR
void OnValidate () { void OnValidate () {
ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>(); ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>();
SkeletonRenderer skeletonRenderer = skeletonComponent as SkeletonRenderer; SkeletonRenderer skeletonRenderer = skeletonComponent as SkeletonRenderer;
bool applyPMA; bool applyPMA;
if (skeletonRenderer != null) { if (skeletonRenderer != null) {
applyPMA = skeletonRenderer.pmaVertexColors; applyPMA = skeletonRenderer.pmaVertexColors;
} else { } else {
SkeletonGraphic skeletonGraphic = skeletonComponent as SkeletonGraphic; SkeletonGraphic skeletonGraphic = skeletonComponent as SkeletonGraphic;
applyPMA = skeletonGraphic != null && skeletonGraphic.MeshGenerator.settings.pmaVertexColors; applyPMA = skeletonGraphic != null && skeletonGraphic.MeshGenerator.settings.pmaVertexColors;
} }
if (applyPMA) { if (applyPMA) {
try { try {
if (sprite == null) if (sprite == null)
return; return;
sprite.texture.GetPixel(0, 0); sprite.texture.GetPixel(0, 0);
} catch (UnityException e) { } catch (UnityException e) {
Debug.LogFormat("Texture of {0} ({1}) is not read/write enabled. SpriteAttacher requires this in order to work with a SkeletonRenderer that renders premultiplied alpha. Please check the texture settings.", sprite.name, sprite.texture.name); Debug.LogFormat("Texture of {0} ({1}) is not read/write enabled. SpriteAttacher requires this in order to work with a SkeletonRenderer that renders premultiplied alpha. Please check the texture settings.", sprite.name, sprite.texture.name);
UnityEditor.EditorGUIUtility.PingObject(sprite.texture); UnityEditor.EditorGUIUtility.PingObject(sprite.texture);
throw e; throw e;
} }
} }
} }
#endif #endif
RegionAttachment attachment; RegionAttachment attachment;
Slot spineSlot; Slot spineSlot;
bool applyPMA; bool applyPMA;
static Dictionary<Texture, AtlasPage> atlasPageCache; static Dictionary<Texture, AtlasPage> atlasPageCache;
static AtlasPage GetPageFor (Texture texture, Shader shader) { static AtlasPage GetPageFor (Texture texture, Shader shader) {
if (atlasPageCache == null) atlasPageCache = new Dictionary<Texture, AtlasPage>(); if (atlasPageCache == null) atlasPageCache = new Dictionary<Texture, AtlasPage>();
AtlasPage atlasPage; AtlasPage atlasPage;
atlasPageCache.TryGetValue(texture, out atlasPage); atlasPageCache.TryGetValue(texture, out atlasPage);
if (atlasPage == null) { if (atlasPage == null) {
Material newMaterial = new Material(shader); Material newMaterial = new Material(shader);
atlasPage = newMaterial.ToSpineAtlasPage(); atlasPage = newMaterial.ToSpineAtlasPage();
atlasPageCache[texture] = atlasPage; atlasPageCache[texture] = atlasPage;
} }
return atlasPage; return atlasPage;
} }
void Start () { void Start () {
// Initialize slot and attachment references. // Initialize slot and attachment references.
Initialize(false); Initialize(false);
if (attachOnStart) if (attachOnStart)
Attach(); Attach();
} }
void AnimationOverrideSpriteAttach (ISkeletonAnimation animated) { void AnimationOverrideSpriteAttach (ISkeletonAnimation animated) {
if (overrideAnimation && isActiveAndEnabled) if (overrideAnimation && isActiveAndEnabled)
Attach(); Attach();
} }
public void Initialize (bool overwrite = true) { public void Initialize (bool overwrite = true) {
if (overwrite || attachment == null) { if (overwrite || attachment == null) {
// Get the applyPMA value. // Get the applyPMA value.
ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>(); ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>();
SkeletonRenderer skeletonRenderer = skeletonComponent as SkeletonRenderer; SkeletonRenderer skeletonRenderer = skeletonComponent as SkeletonRenderer;
if (skeletonRenderer != null) if (skeletonRenderer != null)
this.applyPMA = skeletonRenderer.pmaVertexColors; this.applyPMA = skeletonRenderer.pmaVertexColors;
else { else {
SkeletonGraphic skeletonGraphic = skeletonComponent as SkeletonGraphic; SkeletonGraphic skeletonGraphic = skeletonComponent as SkeletonGraphic;
if (skeletonGraphic != null) if (skeletonGraphic != null)
this.applyPMA = skeletonGraphic.MeshGenerator.settings.pmaVertexColors; this.applyPMA = skeletonGraphic.MeshGenerator.settings.pmaVertexColors;
} }
// Subscribe to UpdateComplete to override animation keys. // Subscribe to UpdateComplete to override animation keys.
if (overrideAnimation) { if (overrideAnimation) {
ISkeletonAnimation animatedSkeleton = skeletonComponent as ISkeletonAnimation; ISkeletonAnimation animatedSkeleton = skeletonComponent as ISkeletonAnimation;
if (animatedSkeleton != null) { if (animatedSkeleton != null) {
animatedSkeleton.UpdateComplete -= AnimationOverrideSpriteAttach; animatedSkeleton.UpdateComplete -= AnimationOverrideSpriteAttach;
animatedSkeleton.UpdateComplete += AnimationOverrideSpriteAttach; animatedSkeleton.UpdateComplete += AnimationOverrideSpriteAttach;
} }
} }
spineSlot = spineSlot ?? skeletonComponent.Skeleton.FindSlot(slot); spineSlot = spineSlot ?? skeletonComponent.Skeleton.FindSlot(slot);
Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader); Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader);
if (sprite == null) if (sprite == null)
attachment = null; attachment = null;
else else
attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(SpriteAttacher.GetPageFor(sprite.texture, attachmentShader)); attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(SpriteAttacher.GetPageFor(sprite.texture, attachmentShader));
} }
} }
void OnDestroy () { void OnDestroy () {
ISkeletonAnimation animatedSkeleton = GetComponent<ISkeletonAnimation>(); ISkeletonAnimation animatedSkeleton = GetComponent<ISkeletonAnimation>();
if (animatedSkeleton != null) if (animatedSkeleton != null)
animatedSkeleton.UpdateComplete -= AnimationOverrideSpriteAttach; animatedSkeleton.UpdateComplete -= AnimationOverrideSpriteAttach;
} }
/// <summary>Update the slot's attachment to the Attachment generated from the sprite.</summary> /// <summary>Update the slot's attachment to the Attachment generated from the sprite.</summary>
public void Attach () { public void Attach () {
if (spineSlot != null) if (spineSlot != null)
spineSlot.Attachment = attachment; spineSlot.Attachment = attachment;
} }
} }
public static class SpriteAttachmentExtensions { public static class SpriteAttachmentExtensions {
[System.Obsolete] [System.Obsolete]
public static RegionAttachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = SpriteAttacher.DefaultPMAShader, bool applyPMA = true, float rotation = 0f) { public static RegionAttachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = SpriteAttacher.DefaultPMAShader, bool applyPMA = true, float rotation = 0f) {
return skeleton.AttachUnitySprite(slotName, sprite, Shader.Find(shaderName), applyPMA, rotation: rotation); return skeleton.AttachUnitySprite(slotName, sprite, Shader.Find(shaderName), applyPMA, rotation: rotation);
} }
[System.Obsolete] [System.Obsolete]
public static RegionAttachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = SpriteAttacher.DefaultPMAShader, bool applyPMA = true, float rotation = 0f) { public static RegionAttachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = SpriteAttacher.DefaultPMAShader, bool applyPMA = true, float rotation = 0f) {
return skeletonData.AddUnitySprite(slotName, sprite, skinName, Shader.Find(shaderName), applyPMA, rotation: rotation); return skeletonData.AddUnitySprite(slotName, sprite, skinName, Shader.Find(shaderName), applyPMA, rotation: rotation);
} }
[System.Obsolete] [System.Obsolete]
public static RegionAttachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, Shader shader, bool applyPMA, float rotation = 0f) { public static RegionAttachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, Shader shader, bool applyPMA, float rotation = 0f) {
RegionAttachment att = applyPMA ? sprite.ToRegionAttachmentPMAClone(shader, rotation: rotation) : sprite.ToRegionAttachment(new Material(shader), rotation: rotation); RegionAttachment att = applyPMA ? sprite.ToRegionAttachmentPMAClone(shader, rotation: rotation) : sprite.ToRegionAttachment(new Material(shader), rotation: rotation);
skeleton.FindSlot(slotName).Attachment = att; skeleton.FindSlot(slotName).Attachment = att;
return att; return att;
} }
[System.Obsolete] [System.Obsolete]
public static RegionAttachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName, Shader shader, bool applyPMA, float rotation = 0f) { public static RegionAttachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName, Shader shader, bool applyPMA, float rotation = 0f) {
RegionAttachment att = applyPMA ? sprite.ToRegionAttachmentPMAClone(shader, rotation: rotation) : sprite.ToRegionAttachment(new Material(shader), rotation); RegionAttachment att = applyPMA ? sprite.ToRegionAttachmentPMAClone(shader, rotation: rotation) : sprite.ToRegionAttachment(new Material(shader), rotation);
int slotIndex = skeletonData.FindSlot(slotName).Index; int slotIndex = skeletonData.FindSlot(slotName).Index;
Skin skin = skeletonData.DefaultSkin; Skin skin = skeletonData.DefaultSkin;
if (skinName != "") if (skinName != "")
skin = skeletonData.FindSkin(skinName); skin = skeletonData.FindSkin(skinName);
if (skin != null) if (skin != null)
skin.SetAttachment(slotIndex, att.Name, att); skin.SetAttachment(slotIndex, att.Name, att);
return att; return att;
} }
} }
} }

View File

@ -1,69 +1,69 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class OutlineSkeletonGraphic : MonoBehaviour { public class OutlineSkeletonGraphic : MonoBehaviour {
public SkeletonGraphic skeletonGraphic; public SkeletonGraphic skeletonGraphic;
public Material materialWithoutOutline; public Material materialWithoutOutline;
public Material materialWithOutline; public Material materialWithOutline;
#if UNITY_EDITOR #if UNITY_EDITOR
void Reset () { void Reset () {
skeletonGraphic = GetComponent<SkeletonGraphic>(); skeletonGraphic = GetComponent<SkeletonGraphic>();
// Add normal material as default // Add normal material as default
if (skeletonGraphic != null && skeletonGraphic.skeletonDataAsset != null) { if (skeletonGraphic != null && skeletonGraphic.skeletonDataAsset != null) {
AtlasAssetBase[] atlasAssets = skeletonGraphic.skeletonDataAsset.atlasAssets; AtlasAssetBase[] atlasAssets = skeletonGraphic.skeletonDataAsset.atlasAssets;
if (atlasAssets.Length > 0 && atlasAssets[0].PrimaryMaterial) { if (atlasAssets.Length > 0 && atlasAssets[0].PrimaryMaterial) {
materialWithoutOutline = atlasAssets[0].PrimaryMaterial; materialWithoutOutline = atlasAssets[0].PrimaryMaterial;
} }
} }
} }
#endif #endif
void OnEnable () { void OnEnable () {
if (skeletonGraphic == null) if (skeletonGraphic == null)
skeletonGraphic = GetComponent<SkeletonGraphic>(); skeletonGraphic = GetComponent<SkeletonGraphic>();
} }
public void EnableOutlineRendering () { public void EnableOutlineRendering () {
skeletonGraphic.material = materialWithOutline; skeletonGraphic.material = materialWithOutline;
} }
public void DisableOutlineRendering () { public void DisableOutlineRendering () {
skeletonGraphic.material = materialWithoutOutline; skeletonGraphic.material = materialWithoutOutline;
} }
} }
} }

View File

@ -0,0 +1,268 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
* otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
#if UNITY_2019_3_OR_NEWER
#define SET_VERTICES_HAS_LENGTH_PARAMETER
#endif
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Spine.Unity.Examples {
#if NEW_PREFAB_SYSTEM
[ExecuteAlways]
#else
[ExecuteInEditMode]
#endif
public class RenderCombinedMesh : MonoBehaviour {
public SkeletonRenderer skeletonRenderer;
public SkeletonRenderSeparator renderSeparator;
public MeshRenderer[] referenceRenderers;
bool updateViaSkeletonCallback = false;
MeshFilter[] referenceMeshFilters;
MeshRenderer ownRenderer;
MeshFilter ownMeshFilter;
protected DoubleBuffered<Mesh> doubleBufferedMesh;
protected ExposedList<Vector3> positionBuffer;
protected ExposedList<Color32> colorBuffer;
protected ExposedList<Vector2> uvBuffer;
protected ExposedList<int> indexBuffer;
#if UNITY_EDITOR
private void Reset () {
if (skeletonRenderer == null)
skeletonRenderer = this.GetComponentInParent<SkeletonRenderer>();
GatherRenderers();
Awake();
if (referenceRenderers.Length > 0)
ownRenderer.sharedMaterial = referenceRenderers[0].sharedMaterial;
LateUpdate();
}
#endif
protected void GatherRenderers () {
referenceRenderers = this.GetComponentsInChildren<MeshRenderer>();
if (referenceRenderers.Length == 0 ||
(referenceRenderers.Length == 1 && referenceRenderers[0].gameObject == this.gameObject)) {
Transform parent = this.transform.parent;
if (parent)
referenceRenderers = parent.GetComponentsInChildren<MeshRenderer>();
}
referenceRenderers = referenceRenderers.Where(
(val, idx) => val.gameObject != this.gameObject && val.enabled).ToArray();
}
void Awake () {
if (skeletonRenderer == null)
skeletonRenderer = this.GetComponentInParent<SkeletonRenderer>();
if (referenceRenderers == null || referenceRenderers.Length == 0) {
GatherRenderers();
}
if (renderSeparator == null) {
if (skeletonRenderer)
renderSeparator = skeletonRenderer.GetComponent<SkeletonRenderSeparator>();
else
renderSeparator = this.GetComponentInParent<SkeletonRenderSeparator>();
}
int count = referenceRenderers.Length;
referenceMeshFilters = new MeshFilter[count];
for (int i = 0; i < count; ++i) {
referenceMeshFilters[i] = referenceRenderers[i].GetComponent<MeshFilter>();
}
ownRenderer = this.GetComponent<MeshRenderer>();
if (ownRenderer == null)
ownRenderer = this.gameObject.AddComponent<MeshRenderer>();
ownMeshFilter = this.GetComponent<MeshFilter>();
if (ownMeshFilter == null)
ownMeshFilter = this.gameObject.AddComponent<MeshFilter>();
}
void OnEnable () {
#if UNITY_EDITOR
if (Application.isPlaying)
Awake();
#endif
if (skeletonRenderer) {
skeletonRenderer.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
skeletonRenderer.OnMeshAndMaterialsUpdated += UpdateOnCallback;
updateViaSkeletonCallback = true;
}
if (renderSeparator) {
renderSeparator.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
renderSeparator.OnMeshAndMaterialsUpdated += UpdateOnCallback;
updateViaSkeletonCallback = true;
}
}
void OnDisable () {
if (skeletonRenderer)
skeletonRenderer.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
if (renderSeparator)
renderSeparator.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
}
void OnDestroy () {
for (int i = 0; i < 2; ++i) {
Mesh mesh = doubleBufferedMesh.GetNext();
#if UNITY_EDITOR
if (Application.isEditor && !Application.isPlaying)
UnityEngine.Object.DestroyImmediate(mesh);
else
UnityEngine.Object.Destroy(mesh);
#else
UnityEngine.Object.Destroy(mesh);
#endif
}
}
void LateUpdate () {
#if UNITY_EDITOR
if (!Application.isPlaying) {
UpdateMesh();
return;
}
#endif
if (updateViaSkeletonCallback)
return;
UpdateMesh();
}
void UpdateOnCallback (SkeletonRenderer r) {
UpdateMesh();
}
protected void EnsureBufferSizes (int combinedVertexCount, int combinedIndexCount) {
if (positionBuffer == null) {
positionBuffer = new ExposedList<Vector3>(combinedVertexCount);
uvBuffer = new ExposedList<Vector2>(combinedVertexCount);
colorBuffer = new ExposedList<Color32>(combinedVertexCount);
indexBuffer = new ExposedList<int>(combinedIndexCount);
}
if (positionBuffer.Count != combinedVertexCount) {
positionBuffer.Resize(combinedVertexCount);
uvBuffer.Resize(combinedVertexCount);
colorBuffer.Resize(combinedVertexCount);
}
if (indexBuffer.Count != combinedIndexCount) {
indexBuffer.Resize(combinedIndexCount);
}
}
void InitMesh () {
if (doubleBufferedMesh == null) {
doubleBufferedMesh = new DoubleBuffered<Mesh>();
for (int i = 0; i < 2; ++i) {
Mesh combinedMesh = doubleBufferedMesh.GetNext();
combinedMesh.MarkDynamic();
combinedMesh.name = "RenderCombinedMesh" + i;
combinedMesh.subMeshCount = 1;
}
}
}
void UpdateMesh () {
InitMesh();
int combinedVertexCount = 0;
int combinedIndexCount = 0;
GetCombinedMeshInfo(ref combinedVertexCount, ref combinedIndexCount);
EnsureBufferSizes(combinedVertexCount, combinedIndexCount);
int combinedV = 0;
int combinedI = 0;
for (int r = 0, rendererCount = referenceMeshFilters.Length; r < rendererCount; ++r) {
MeshFilter meshFilter = referenceMeshFilters[r];
Mesh mesh = meshFilter.sharedMesh;
if (mesh == null) continue;
int vertexCount = mesh.vertexCount;
Vector3[] positions = mesh.vertices;
Vector2[] uvs = mesh.uv;
Color32[] colors = mesh.colors32;
System.Array.Copy(positions, 0, this.positionBuffer.Items, combinedV, vertexCount);
System.Array.Copy(uvs, 0, this.uvBuffer.Items, combinedV, vertexCount);
System.Array.Copy(colors, 0, this.colorBuffer.Items, combinedV, vertexCount);
for (int s = 0, submeshCount = mesh.subMeshCount; s < submeshCount; ++s) {
int submeshIndexCount = (int)mesh.GetIndexCount(s);
int[] submeshIndices = mesh.GetIndices(s);
int[] dstIndices = this.indexBuffer.Items;
for (int i = 0; i < submeshIndexCount; ++i)
dstIndices[i + combinedI] = submeshIndices[i] + combinedV;
combinedI += submeshIndexCount;
}
combinedV += vertexCount;
}
Mesh combinedMesh = doubleBufferedMesh.GetNext();
combinedMesh.Clear();
#if SET_VERTICES_HAS_LENGTH_PARAMETER
combinedMesh.SetVertices(this.positionBuffer.Items, 0, this.positionBuffer.Count);
combinedMesh.SetUVs(0, this.uvBuffer.Items, 0, this.uvBuffer.Count);
combinedMesh.SetColors(this.colorBuffer.Items, 0, this.colorBuffer.Count);
combinedMesh.SetTriangles(this.indexBuffer.Items, 0, this.indexBuffer.Count, 0);
#else
// Note: excess already contains zero positions and indices after ExposedList.Resize().
combinedMesh.vertices = this.positionBuffer.Items;
combinedMesh.uv = this.uvBuffer.Items;
combinedMesh.colors32 = this.colorBuffer.Items;
combinedMesh.triangles = this.indexBuffer.Items;
#endif
ownMeshFilter.sharedMesh = combinedMesh;
}
void GetCombinedMeshInfo (ref int vertexCount, ref int indexCount) {
for (int r = 0, rendererCount = referenceMeshFilters.Length; r < rendererCount; ++r) {
MeshFilter meshFilter = referenceMeshFilters[r];
Mesh mesh = meshFilter.sharedMesh;
if (mesh == null) continue;
vertexCount += mesh.vertexCount;
for (int s = 0, submeshCount = mesh.subMeshCount; s < submeshCount; ++s) {
indexCount += (int)mesh.GetIndexCount(s);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05709c69e8e14304b9781652ad05daef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,151 +1,182 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER #if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM #define NEW_PREFAB_SYSTEM
#endif #endif
using System.Collections.Generic; #if UNITY_2018_2_OR_NEWER
using UnityEngine; #define HAS_GET_SHARED_MATERIALS
#endif
namespace Spine.Unity.Examples {
using System.Collections.Generic;
#if NEW_PREFAB_SYSTEM using UnityEngine;
[ExecuteAlways]
#else namespace Spine.Unity.Examples {
[ExecuteInEditMode]
#endif #if NEW_PREFAB_SYSTEM
[RequireComponent(typeof(MeshRenderer)), RequireComponent(typeof(MeshFilter))] [ExecuteAlways]
public class RenderExistingMesh : MonoBehaviour { #else
public MeshRenderer referenceRenderer; [ExecuteInEditMode]
#endif
bool updateViaSkeletonCallback = false; [RequireComponent(typeof(MeshRenderer)), RequireComponent(typeof(MeshFilter))]
MeshFilter referenceMeshFilter; public class RenderExistingMesh : MonoBehaviour {
MeshRenderer ownRenderer; public MeshRenderer referenceRenderer;
MeshFilter ownMeshFilter;
bool updateViaSkeletonCallback = false;
[System.Serializable] MeshFilter referenceMeshFilter;
public struct MaterialReplacement { MeshRenderer ownRenderer;
public Material originalMaterial; MeshFilter ownMeshFilter;
public Material replacementMaterial;
} [System.Serializable]
public MaterialReplacement[] replacementMaterials = new MaterialReplacement[0]; public struct MaterialReplacement {
public Material originalMaterial;
private Dictionary<Material, Material> replacementMaterialDict = new Dictionary<Material, Material>(); public Material replacementMaterial;
private Material[] sharedMaterials = new Material[0]; }
public MaterialReplacement[] replacementMaterials = new MaterialReplacement[0];
#if UNITY_EDITOR
private void Reset () { private Dictionary<Material, Material> replacementMaterialDict = new Dictionary<Material, Material>();
if (referenceRenderer == null) { private Material[] sharedMaterials = new Material[0];
referenceRenderer = this.transform.parent.GetComponentInParent<MeshRenderer>(); #if HAS_GET_SHARED_MATERIALS
if (!referenceRenderer) private List<Material> parentMaterials = new List<Material>();
return; #endif
}
#if UNITY_EDITOR
Material[] parentMaterials = referenceRenderer.sharedMaterials; private void Reset () {
if (replacementMaterials.Length != parentMaterials.Length) { if (referenceRenderer == null) {
replacementMaterials = new MaterialReplacement[parentMaterials.Length]; if (this.transform.parent)
} referenceRenderer = this.transform.parent.GetComponentInParent<MeshRenderer>();
for (int i = 0; i < parentMaterials.Length; ++i) { if (referenceRenderer == null) return;
replacementMaterials[i].originalMaterial = parentMaterials[i]; }
replacementMaterials[i].replacementMaterial = parentMaterials[i]; #if HAS_GET_SHARED_MATERIALS
} referenceRenderer.GetSharedMaterials(parentMaterials);
Awake(); int parentMaterialsCount = parentMaterials.Count;
LateUpdate(); #else
} Material[] parentMaterials = referenceRenderer.sharedMaterials;
#endif int parentMaterialsCount = parentMaterials.Length;
#endif
void Awake () { if (replacementMaterials.Length != parentMaterialsCount) {
if (referenceRenderer == null) { replacementMaterials = new MaterialReplacement[parentMaterialsCount];
referenceRenderer = this.transform.parent.GetComponentInParent<MeshRenderer>(); }
} for (int i = 0; i < parentMaterialsCount; ++i) {
replacementMaterials[i].originalMaterial = parentMaterials[i];
// subscribe to OnMeshAndMaterialsUpdated replacementMaterials[i].replacementMaterial = parentMaterials[i];
SkeletonAnimation skeletonRenderer = referenceRenderer.GetComponent<SkeletonAnimation>(); }
if (skeletonRenderer) { Awake();
skeletonRenderer.OnMeshAndMaterialsUpdated -= UpdateOnCallback; LateUpdate();
skeletonRenderer.OnMeshAndMaterialsUpdated += UpdateOnCallback; }
updateViaSkeletonCallback = true; #endif
}
referenceMeshFilter = referenceRenderer.GetComponent<MeshFilter>(); void Awake () {
ownRenderer = this.GetComponent<MeshRenderer>(); ownRenderer = this.GetComponent<MeshRenderer>();
ownMeshFilter = this.GetComponent<MeshFilter>(); ownMeshFilter = this.GetComponent<MeshFilter>();
InitializeDict(); if (referenceRenderer == null) {
} if (this.transform.parent != null)
referenceRenderer = this.transform.parent.GetComponentInParent<MeshRenderer>();
#if UNITY_EDITOR if (referenceRenderer == null) return;
private void Update () { }
if (!Application.isPlaying) { referenceMeshFilter = referenceRenderer.GetComponent<MeshFilter>();
InitializeDict();
} // subscribe to OnMeshAndMaterialsUpdated
} SkeletonAnimation skeletonRenderer = referenceRenderer.GetComponent<SkeletonAnimation>();
#endif if (skeletonRenderer) {
skeletonRenderer.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
void LateUpdate () { skeletonRenderer.OnMeshAndMaterialsUpdated += UpdateOnCallback;
#if UNITY_EDITOR updateViaSkeletonCallback = true;
if (!Application.isPlaying) { }
UpdateMaterials();
return; InitializeDict();
} }
#endif
#if UNITY_EDITOR
if (updateViaSkeletonCallback) // handle disabled scene reload
return; private void OnEnable () {
UpdateMaterials(); if (Application.isPlaying)
} Awake();
}
void UpdateOnCallback (SkeletonRenderer r) {
UpdateMaterials(); private void Update () {
} if (!Application.isPlaying)
InitializeDict();
void UpdateMaterials () { }
ownMeshFilter.sharedMesh = referenceMeshFilter.sharedMesh; #endif
Material[] parentMaterials = referenceRenderer.sharedMaterials; void LateUpdate () {
if (sharedMaterials.Length != parentMaterials.Length) { #if UNITY_EDITOR
sharedMaterials = new Material[parentMaterials.Length]; if (!Application.isPlaying) {
} UpdateMaterials();
for (int i = 0; i < parentMaterials.Length; ++i) { return;
Material parentMaterial = parentMaterials[i]; }
if (replacementMaterialDict.ContainsKey(parentMaterial)) { #endif
sharedMaterials[i] = replacementMaterialDict[parentMaterial];
} if (updateViaSkeletonCallback)
} return;
ownRenderer.sharedMaterials = sharedMaterials; UpdateMaterials();
} }
void InitializeDict () { void UpdateOnCallback (SkeletonRenderer r) {
for (int i = 0; i < replacementMaterials.Length; ++i) { UpdateMaterials();
MaterialReplacement entry = replacementMaterials[i]; }
replacementMaterialDict[entry.originalMaterial] = entry.replacementMaterial;
} void UpdateMaterials () {
} #if UNITY_EDITOR
} if (!referenceRenderer) return;
} if (!referenceMeshFilter) Reset();
#endif
ownMeshFilter.sharedMesh = referenceMeshFilter.sharedMesh;
#if HAS_GET_SHARED_MATERIALS
referenceRenderer.GetSharedMaterials(parentMaterials);
int parentMaterialsCount = parentMaterials.Count;
#else
Material[] parentMaterials = referenceRenderer.sharedMaterials;
int parentMaterialsCount = parentMaterials.Length;
#endif
if (sharedMaterials.Length != parentMaterialsCount) {
sharedMaterials = new Material[parentMaterialsCount];
}
for (int i = 0; i < parentMaterialsCount; ++i) {
Material parentMaterial = parentMaterials[i];
if (replacementMaterialDict.ContainsKey(parentMaterial)) {
sharedMaterials[i] = replacementMaterialDict[parentMaterial];
}
}
ownRenderer.sharedMaterials = sharedMaterials;
}
void InitializeDict () {
replacementMaterialDict.Clear();
for (int i = 0; i < replacementMaterials.Length; ++i) {
MaterialReplacement entry = replacementMaterials[i];
replacementMaterialDict[entry.originalMaterial] = entry.replacementMaterial;
}
}
}
}

View File

@ -0,0 +1,224 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2025, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
* otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
#if UNITY_2018_2_OR_NEWER
#define HAS_CULL_TRANSPARENT_MESH
#endif
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Spine.Unity.Examples {
using MaterialReplacement = RenderExistingMesh.MaterialReplacement;
#if NEW_PREFAB_SYSTEM
[ExecuteAlways]
#else
[ExecuteInEditMode]
#endif
public class RenderExistingMeshGraphic : MonoBehaviour {
public SkeletonGraphic referenceSkeletonGraphic;
public Material replacementMaterial;
public MaterialReplacement[] replacementMaterials = new MaterialReplacement[0];
SkeletonSubmeshGraphic ownGraphic;
public List<SkeletonSubmeshGraphic> ownSubmeshGraphics;
#if UNITY_EDITOR
private void Reset () {
Awake();
LateUpdate();
}
#endif
void Awake () {
// subscribe to OnMeshAndMaterialsUpdated
if (referenceSkeletonGraphic) {
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated += UpdateOnCallback;
}
ownGraphic = this.GetComponent<SkeletonSubmeshGraphic>();
if (referenceSkeletonGraphic) {
if (referenceSkeletonGraphic.allowMultipleCanvasRenderers)
EnsureCanvasRendererCount(referenceSkeletonGraphic.canvasRenderers.Count);
else
SetupSubmeshGraphic();
}
}
protected void OnDisable () {
if (referenceSkeletonGraphic) {
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
}
}
protected void OnEnable () {
#if UNITY_EDITOR
// handle disabled scene reload
if (Application.isPlaying) {
Awake();
return;
}
#endif
if (referenceSkeletonGraphic) {
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
referenceSkeletonGraphic.OnMeshAndMaterialsUpdated += UpdateOnCallback;
}
}
void SetupSubmeshGraphic () {
if (ownGraphic == null)
ownGraphic = this.gameObject.AddComponent<SkeletonSubmeshGraphic>();
ownGraphic.maskable = referenceSkeletonGraphic.maskable;
#if HAS_CULL_TRANSPARENT_MESH
ownGraphic.canvasRenderer.cullTransparentMesh = referenceSkeletonGraphic.canvasRenderer.cullTransparentMesh;
#endif
ownGraphic.canvasRenderer.SetMaterial(replacementMaterial, referenceSkeletonGraphic.mainTexture);
}
protected void EnsureCanvasRendererCount (int targetCount) {
if (ownSubmeshGraphics == null)
ownSubmeshGraphics = new List<SkeletonSubmeshGraphic>();
#if HAS_CULL_TRANSPARENT_MESH
bool cullTransparentMesh = referenceSkeletonGraphic.canvasRenderer.cullTransparentMesh;
#endif
Vector2 pivot = referenceSkeletonGraphic.rectTransform.pivot;
int currentCount = ownSubmeshGraphics.Count;
for (int i = currentCount; i < targetCount; ++i) {
GameObject go = new GameObject(string.Format("Renderer{0}", i), typeof(RectTransform));
go.transform.SetParent(this.transform, false);
go.transform.localPosition = Vector3.zero;
CanvasRenderer canvasRenderer = go.AddComponent<CanvasRenderer>();
#if HAS_CULL_TRANSPARENT_MESH
canvasRenderer.cullTransparentMesh = cullTransparentMesh;
#endif
SkeletonSubmeshGraphic submeshGraphic = go.AddComponent<SkeletonSubmeshGraphic>();
ownSubmeshGraphics.Add(submeshGraphic);
submeshGraphic.maskable = referenceSkeletonGraphic.maskable;
submeshGraphic.raycastTarget = false;
submeshGraphic.rectTransform.pivot = pivot;
submeshGraphic.rectTransform.anchorMin = Vector2.zero;
submeshGraphic.rectTransform.anchorMax = Vector2.one;
submeshGraphic.rectTransform.sizeDelta = Vector2.zero;
}
}
protected void UpdateCanvasRenderers () {
Mesh[] referenceMeshes = referenceSkeletonGraphic.MeshesMultipleCanvasRenderers.Items;
Material[] referenceMaterials = referenceSkeletonGraphic.MaterialsMultipleCanvasRenderers.Items;
Texture[] referenceTextures = referenceSkeletonGraphic.TexturesMultipleCanvasRenderers.Items;
int end = Math.Min(ownSubmeshGraphics.Count, referenceSkeletonGraphic.TexturesMultipleCanvasRenderers.Count);
for (int i = 0; i < end; i++) {
SkeletonSubmeshGraphic submeshGraphic = ownSubmeshGraphics[i];
CanvasRenderer reference = referenceSkeletonGraphic.canvasRenderers[i];
if (reference.gameObject.activeInHierarchy) {
Material usedMaterial = replacementMaterial != null ?
replacementMaterial : GetReplacementMaterialFor(referenceMaterials[i]);
if (usedMaterial == null)
usedMaterial = referenceMaterials[i];
usedMaterial = referenceSkeletonGraphic.GetModifiedMaterial(usedMaterial);
submeshGraphic.canvasRenderer.SetMaterial(usedMaterial, referenceTextures[i]);
submeshGraphic.canvasRenderer.SetMesh(referenceMeshes[i]);
submeshGraphic.gameObject.SetActive(true);
} else {
submeshGraphic.canvasRenderer.Clear();
submeshGraphic.gameObject.SetActive(false);
}
}
}
protected void DisableCanvasRenderers () {
for (int i = 0; i < ownSubmeshGraphics.Count; i++) {
SkeletonSubmeshGraphic submeshGraphic = ownSubmeshGraphics[i];
submeshGraphic.canvasRenderer.Clear();
submeshGraphic.gameObject.SetActive(false);
}
}
protected Material GetReplacementMaterialFor (Material originalMaterial) {
for (int i = 0; i < replacementMaterials.Length; ++i) {
MaterialReplacement entry = replacementMaterials[i];
if (entry.originalMaterial != null && entry.originalMaterial.shader == originalMaterial.shader)
return entry.replacementMaterial;
}
return null;
}
#if UNITY_EDITOR
void LateUpdate () {
if (!Application.isPlaying) {
UpdateMesh();
}
}
#endif
void UpdateOnCallback (SkeletonGraphic g) {
UpdateMesh();
}
void UpdateMesh () {
if (!referenceSkeletonGraphic) return;
if (referenceSkeletonGraphic.allowMultipleCanvasRenderers) {
EnsureCanvasRendererCount(referenceSkeletonGraphic.canvasRenderers.Count);
UpdateCanvasRenderers();
if (ownGraphic)
ownGraphic.canvasRenderer.Clear();
} else {
if (ownGraphic == null)
ownGraphic = this.gameObject.AddComponent<SkeletonSubmeshGraphic>();
DisableCanvasRenderers();
Material referenceMaterial = referenceSkeletonGraphic.materialForRendering;
Material usedMaterial = replacementMaterial != null ? replacementMaterial : GetReplacementMaterialFor(referenceMaterial);
if (usedMaterial == null)
usedMaterial = referenceMaterial;
usedMaterial = referenceSkeletonGraphic.GetModifiedMaterial(usedMaterial);
ownGraphic.canvasRenderer.SetMaterial(usedMaterial, referenceSkeletonGraphic.mainTexture);
Mesh mesh = referenceSkeletonGraphic.GetLastMesh();
ownGraphic.canvasRenderer.SetMesh(mesh);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff6ce4ce6b9336a479c6bf5af81fa80a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,77 +1,77 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class RootMotionDeltaCompensation : MonoBehaviour { public class RootMotionDeltaCompensation : MonoBehaviour {
[SerializeField] protected SkeletonRootMotionBase rootMotion; [SerializeField] protected SkeletonRootMotionBase rootMotion;
public Transform targetPosition; public Transform targetPosition;
public int trackIndex = 0; public int trackIndex = 0;
public bool adjustX = true; public bool adjustX = true;
public bool adjustY = true; public bool adjustY = true;
public float minScaleX = -999; public float minScaleX = -999;
public float minScaleY = -999; public float minScaleY = -999;
public float maxScaleX = 999; public float maxScaleX = 999;
public float maxScaleY = 999; public float maxScaleY = 999;
public bool allowXTranslation = false; public bool allowXTranslation = false;
public bool allowYTranslation = true; public bool allowYTranslation = true;
void Start () { void Start () {
if (rootMotion == null) if (rootMotion == null)
rootMotion = this.GetComponent<SkeletonRootMotionBase>(); rootMotion = this.GetComponent<SkeletonRootMotionBase>();
} }
void Update () { void Update () {
AdjustDelta(); AdjustDelta();
} }
void OnDisable () { void OnDisable () {
if (adjustX) if (adjustX)
rootMotion.rootMotionScaleX = 1; rootMotion.rootMotionScaleX = 1;
if (adjustY) if (adjustY)
rootMotion.rootMotionScaleY = 1; rootMotion.rootMotionScaleY = 1;
if (allowXTranslation) if (allowXTranslation)
rootMotion.rootMotionTranslateXPerY = 0; rootMotion.rootMotionTranslateXPerY = 0;
if (allowYTranslation) if (allowYTranslation)
rootMotion.rootMotionTranslateYPerX = 0; rootMotion.rootMotionTranslateYPerX = 0;
} }
void AdjustDelta () { void AdjustDelta () {
Vector3 toTarget = targetPosition.position - this.transform.position; Vector3 toTarget = targetPosition.position - this.transform.position;
rootMotion.AdjustRootMotionToDistance(toTarget, trackIndex, adjustX, adjustY, rootMotion.AdjustRootMotionToDistance(toTarget, trackIndex, adjustX, adjustY,
minScaleX, maxScaleX, minScaleY, maxScaleY, minScaleX, maxScaleX, minScaleY, maxScaleY,
allowXTranslation, allowYTranslation); allowXTranslation, allowYTranslation);
} }
} }
} }

View File

@ -1,84 +1,84 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This is a sample component for C# vertex effects for Spine rendering components. // This is a sample component for C# vertex effects for Spine rendering components.
// Using shaders and materials to control vertex properties is still more performant // Using shaders and materials to control vertex properties is still more performant
// than using this API, but in cases where your vertex effect logic cannot be // than using this API, but in cases where your vertex effect logic cannot be
// expressed as shader code, these vertex effects can be useful. // expressed as shader code, these vertex effects can be useful.
public class JitterEffectExample : MonoBehaviour { public class JitterEffectExample : MonoBehaviour {
[Range(0f, 0.8f)] [Range(0f, 0.8f)]
public float jitterMagnitude = 0.2f; public float jitterMagnitude = 0.2f;
SkeletonRenderer skeletonRenderer; SkeletonRenderer skeletonRenderer;
void OnEnable () { void OnEnable () {
skeletonRenderer = GetComponent<SkeletonRenderer>(); skeletonRenderer = GetComponent<SkeletonRenderer>();
if (skeletonRenderer == null) return; if (skeletonRenderer == null) return;
// Use the OnPostProcessVertices callback to modify the vertices at the correct time. // Use the OnPostProcessVertices callback to modify the vertices at the correct time.
skeletonRenderer.OnPostProcessVertices -= ProcessVertices; skeletonRenderer.OnPostProcessVertices -= ProcessVertices;
skeletonRenderer.OnPostProcessVertices += ProcessVertices; skeletonRenderer.OnPostProcessVertices += ProcessVertices;
Debug.Log("Jitter Effect Enabled."); Debug.Log("Jitter Effect Enabled.");
} }
void ProcessVertices (MeshGeneratorBuffers buffers) { void ProcessVertices (MeshGeneratorBuffers buffers) {
if (!this.enabled) return; if (!this.enabled) return;
// For efficiency, limit your effect to the actual mesh vertex count using vertexCount // For efficiency, limit your effect to the actual mesh vertex count using vertexCount
int vertexCount = buffers.vertexCount; int vertexCount = buffers.vertexCount;
// Modify vertex positions by accessing Vector3[] vertexBuffer // Modify vertex positions by accessing Vector3[] vertexBuffer
Vector3[] vertices = buffers.vertexBuffer; Vector3[] vertices = buffers.vertexBuffer;
for (int i = 0; i < vertexCount; i++) for (int i = 0; i < vertexCount; i++)
vertices[i] += (Vector3)(Random.insideUnitCircle * jitterMagnitude); vertices[i] += (Vector3)(Random.insideUnitCircle * jitterMagnitude);
// You can also modify uvs and colors. // You can also modify uvs and colors.
//Vector2[] uvs = buffers.uvBuffer; //Vector2[] uvs = buffers.uvBuffer;
//Color32[] colors = buffers.colorBuffer; //Color32[] colors = buffers.colorBuffer;
// //
} }
void OnDisable () { void OnDisable () {
if (skeletonRenderer == null) return; if (skeletonRenderer == null) return;
skeletonRenderer.OnPostProcessVertices -= ProcessVertices; skeletonRenderer.OnPostProcessVertices -= ProcessVertices;
Debug.Log("Jitter Effect Disabled."); Debug.Log("Jitter Effect Disabled.");
} }
} }
} }

View File

@ -1,105 +1,109 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
// This is a sample component for C# vertex effects for Spine rendering components. // This is a sample component for C# vertex effects for Spine rendering components.
// Using shaders and materials to control vertex properties is still more performant // Using shaders and materials to control vertex properties is still more performant
// than using this API, but in cases where your vertex effect logic cannot be // than using this API, but in cases where your vertex effect logic cannot be
// expressed as shader code, these vertex effects can be useful. // expressed as shader code, these vertex effects can be useful.
public class TwoByTwoTransformEffectExample : MonoBehaviour { public class TwoByTwoTransformEffectExample : MonoBehaviour {
public Vector2 xAxis = new Vector2(1, 0); public Vector2 xAxis = new Vector2(1, 0);
public Vector2 yAxis = new Vector2(0, 1); public Vector2 yAxis = new Vector2(0, 1);
SkeletonRenderer skeletonRenderer; SkeletonRenderer skeletonRenderer;
void OnEnable () { void OnEnable () {
skeletonRenderer = GetComponent<SkeletonRenderer>(); skeletonRenderer = GetComponent<SkeletonRenderer>();
if (skeletonRenderer == null) return; if (skeletonRenderer == null) return;
// Use the OnPostProcessVertices callback to modify the vertices at the correct time. // Use the OnPostProcessVertices callback to modify the vertices at the correct time.
skeletonRenderer.OnPostProcessVertices -= ProcessVertices; skeletonRenderer.OnPostProcessVertices -= ProcessVertices;
skeletonRenderer.OnPostProcessVertices += ProcessVertices; skeletonRenderer.OnPostProcessVertices += ProcessVertices;
Debug.Log("2x2 Transform Effect Enabled."); Debug.Log("2x2 Transform Effect Enabled.");
} }
void ProcessVertices (MeshGeneratorBuffers buffers) { void ProcessVertices (MeshGeneratorBuffers buffers) {
if (!this.enabled) if (!this.enabled)
return; return;
int vertexCount = buffers.vertexCount; // For efficiency, limit your effect to the actual mesh vertex count using vertexCount int vertexCount = buffers.vertexCount; // For efficiency, limit your effect to the actual mesh vertex count using vertexCount
// Modify vertex positions by accessing Vector3[] vertexBuffer // Modify vertex positions by accessing Vector3[] vertexBuffer
Vector3[] vertices = buffers.vertexBuffer; Vector3[] vertices = buffers.vertexBuffer;
Vector3 transformedPos = default(Vector3); Vector3 transformedPos = default(Vector3);
for (int i = 0; i < vertexCount; i++) { for (int i = 0; i < vertexCount; i++) {
Vector3 originalPos = vertices[i]; Vector3 originalPos = vertices[i];
transformedPos.x = (xAxis.x * originalPos.x) + (yAxis.x * originalPos.y); transformedPos.x = (xAxis.x * originalPos.x) + (yAxis.x * originalPos.y);
transformedPos.y = (xAxis.y * originalPos.x) + (yAxis.y * originalPos.y); transformedPos.y = (xAxis.y * originalPos.x) + (yAxis.y * originalPos.y);
vertices[i] = transformedPos; vertices[i] = transformedPos;
} }
} }
void OnDisable () { void OnDisable () {
if (skeletonRenderer == null) return; if (skeletonRenderer == null) return;
skeletonRenderer.OnPostProcessVertices -= ProcessVertices; skeletonRenderer.OnPostProcessVertices -= ProcessVertices;
Debug.Log("2x2 Transform Effect Disabled."); Debug.Log("2x2 Transform Effect Disabled.");
} }
} }
} }
#if UNITY_EDITOR #if UNITY_EDITOR
[UnityEditor.CustomEditor(typeof(Spine.Unity.Examples.TwoByTwoTransformEffectExample))] [UnityEditor.CustomEditor(typeof(Spine.Unity.Examples.TwoByTwoTransformEffectExample))]
public class TwoByTwoTransformEffectExampleEditor : UnityEditor.Editor { public class TwoByTwoTransformEffectExampleEditor : UnityEditor.Editor {
Spine.Unity.Examples.TwoByTwoTransformEffectExample Target { get { return target as Spine.Unity.Examples.TwoByTwoTransformEffectExample; } } Spine.Unity.Examples.TwoByTwoTransformEffectExample Target { get { return target as Spine.Unity.Examples.TwoByTwoTransformEffectExample; } }
void OnSceneGUI () { void OnSceneGUI () {
Transform transform = Target.transform; Transform transform = Target.transform;
LocalVectorHandle(ref Target.xAxis, transform, Color.red); LocalVectorHandle(ref Target.xAxis, transform, Color.red);
LocalVectorHandle(ref Target.yAxis, transform, Color.green); LocalVectorHandle(ref Target.yAxis, transform, Color.green);
} }
static void LocalVectorHandle (ref Vector2 v, Transform transform, Color color) { static void LocalVectorHandle (ref Vector2 v, Transform transform, Color color) {
Color originalColor = UnityEditor.Handles.color; Color originalColor = UnityEditor.Handles.color;
UnityEditor.Handles.color = color; UnityEditor.Handles.color = color;
UnityEditor.Handles.DrawLine(transform.position, transform.TransformPoint(v)); UnityEditor.Handles.DrawLine(transform.position, transform.TransformPoint(v));
v = transform.InverseTransformPoint(UnityEditor.Handles.FreeMoveHandle(transform.TransformPoint(v), Quaternion.identity, 0.3f, Vector3.zero, UnityEditor.Handles.CubeHandleCap)); #if UNITY_2022_1_OR_NEWER
UnityEditor.Handles.color = originalColor; v = transform.InverseTransformPoint(UnityEditor.Handles.FreeMoveHandle(transform.TransformPoint(v), 0.3f, Vector3.zero, UnityEditor.Handles.CubeHandleCap));
} #else
} v = transform.InverseTransformPoint(UnityEditor.Handles.FreeMoveHandle(transform.TransformPoint(v), Quaternion.identity, 0.3f, Vector3.zero, UnityEditor.Handles.CubeHandleCap));
#endif #endif
UnityEditor.Handles.color = originalColor;
}
}
#endif

View File

@ -1,53 +1,53 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
/// <summary> /// <summary>
/// This component is intended to increase the physics solver iteration count /// This component is intended to increase the physics solver iteration count
/// for Rigidbody Joint setups which would otherwise be too unstable. /// for Rigidbody Joint setups which would otherwise be too unstable.
/// ///
/// To use this example component, add it to a GameObject which is parent of /// To use this example component, add it to a GameObject which is parent of
/// one or more Rigidbody instances. The physics setting "solver iteration count" /// one or more Rigidbody instances. The physics setting "solver iteration count"
/// will be overwritten by the provided value. /// will be overwritten by the provided value.
/// </summary> /// </summary>
[DisallowMultipleComponent] [DisallowMultipleComponent]
public class SetRigidbodySolverIterations : MonoBehaviour { public class SetRigidbodySolverIterations : MonoBehaviour {
public int solverIterations = 30; public int solverIterations = 30;
void Awake () { void Awake () {
Rigidbody[] rigidbodies = this.GetComponentsInChildren<Rigidbody>(); Rigidbody[] rigidbodies = this.GetComponentsInChildren<Rigidbody>();
foreach (Rigidbody rigidbody in rigidbodies) { foreach (Rigidbody rigidbody in rigidbodies) {
rigidbody.solverIterations = solverIterations; rigidbody.solverIterations = solverIterations;
} }
} }
} }
} }

View File

@ -1,96 +1,96 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using UnityEngine; using UnityEngine;
namespace Spine.Unity { namespace Spine.Unity {
// To use this example component, add it to your SkeletonAnimation Spine GameObject. // To use this example component, add it to your SkeletonAnimation Spine GameObject.
// This component will disable that SkeletonAnimation component to prevent it from calling its own Update and LateUpdate methods. // This component will disable that SkeletonAnimation component to prevent it from calling its own Update and LateUpdate methods.
[DisallowMultipleComponent] [DisallowMultipleComponent]
public sealed class SkeletonAnimationFixedTimestep : MonoBehaviour { public sealed class SkeletonAnimationFixedTimestep : MonoBehaviour {
#region Inspector #region Inspector
public SkeletonAnimation skeletonAnimation; public SkeletonAnimation skeletonAnimation;
[Tooltip("The duration of each frame in seconds. For 12 fps: enter '1/12' in the Unity inspector.")] [Tooltip("The duration of each frame in seconds. For 12 fps: enter '1/12' in the Unity inspector.")]
public float frameDeltaTime = 1 / 15f; public float frameDeltaTime = 1 / 15f;
[Header("Advanced")] [Header("Advanced")]
[Tooltip("The maximum number of fixed timesteps. If the game framerate drops below the If the framerate is consistently faster than the limited frames, this does nothing.")] [Tooltip("The maximum number of fixed timesteps. If the game framerate drops below the If the framerate is consistently faster than the limited frames, this does nothing.")]
public int maxFrameSkip = 4; public int maxFrameSkip = 4;
[Tooltip("If enabled, the Skeleton mesh will be updated only on the same frame when the animation and skeleton are updated. Disable this or call SkeletonAnimation.LateUpdate yourself if you are modifying the Skeleton using other components that don't run in the same fixed timestep.")] [Tooltip("If enabled, the Skeleton mesh will be updated only on the same frame when the animation and skeleton are updated. Disable this or call SkeletonAnimation.LateUpdate yourself if you are modifying the Skeleton using other components that don't run in the same fixed timestep.")]
public bool frameskipMeshUpdate = true; public bool frameskipMeshUpdate = true;
[Tooltip("This is the amount the internal accumulator starts with. Set it to some fraction of your frame delta time if you want to stagger updates between multiple skeletons.")] [Tooltip("This is the amount the internal accumulator starts with. Set it to some fraction of your frame delta time if you want to stagger updates between multiple skeletons.")]
public float timeOffset; public float timeOffset;
#endregion #endregion
float accumulatedTime = 0; float accumulatedTime = 0;
bool requiresNewMesh; bool requiresNewMesh;
void OnValidate () { void OnValidate () {
skeletonAnimation = GetComponent<SkeletonAnimation>(); skeletonAnimation = GetComponent<SkeletonAnimation>();
if (frameDeltaTime <= 0) frameDeltaTime = 1 / 60f; if (frameDeltaTime <= 0) frameDeltaTime = 1 / 60f;
if (maxFrameSkip < 1) maxFrameSkip = 1; if (maxFrameSkip < 1) maxFrameSkip = 1;
} }
void Awake () { void Awake () {
requiresNewMesh = true; requiresNewMesh = true;
accumulatedTime = timeOffset; accumulatedTime = timeOffset;
} }
void Update () { void Update () {
if (skeletonAnimation.enabled) if (skeletonAnimation.enabled)
skeletonAnimation.enabled = false; skeletonAnimation.enabled = false;
accumulatedTime += Time.deltaTime; accumulatedTime += Time.deltaTime;
float frames = 0; float frames = 0;
while (accumulatedTime >= frameDeltaTime) { while (accumulatedTime >= frameDeltaTime) {
frames++; frames++;
if (frames > maxFrameSkip) break; if (frames > maxFrameSkip) break;
accumulatedTime -= frameDeltaTime; accumulatedTime -= frameDeltaTime;
} }
if (frames > 0) { if (frames > 0) {
skeletonAnimation.Update(frames * frameDeltaTime); skeletonAnimation.Update(frames * frameDeltaTime);
requiresNewMesh = true; requiresNewMesh = true;
} }
} }
void LateUpdate () { void LateUpdate () {
if (frameskipMeshUpdate && !requiresNewMesh) return; if (frameskipMeshUpdate && !requiresNewMesh) return;
skeletonAnimation.LateUpdate(); skeletonAnimation.LateUpdate();
requiresNewMesh = false; requiresNewMesh = false;
} }
} }
} }

View File

@ -1,168 +1,168 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity; using Spine.Unity;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity { namespace Spine.Unity {
using Animation = Spine.Animation; using Animation = Spine.Animation;
using AnimationState = Spine.AnimationState; using AnimationState = Spine.AnimationState;
public class SkeletonAnimationMulti : MonoBehaviour { public class SkeletonAnimationMulti : MonoBehaviour {
const int MainTrackIndex = 0; const int MainTrackIndex = 0;
public bool initialFlipX, initialFlipY; public bool initialFlipX, initialFlipY;
public string initialAnimation; public string initialAnimation;
public bool initialLoop; public bool initialLoop;
[Space] [Space]
public List<SkeletonDataAsset> skeletonDataAssets = new List<SkeletonDataAsset>(); public List<SkeletonDataAsset> skeletonDataAssets = new List<SkeletonDataAsset>();
[Header("Settings")] [Header("Settings")]
public MeshGenerator.Settings meshGeneratorSettings = MeshGenerator.Settings.Default; public MeshGenerator.Settings meshGeneratorSettings = MeshGenerator.Settings.Default;
readonly List<SkeletonAnimation> skeletonAnimations = new List<SkeletonAnimation>(); readonly List<SkeletonAnimation> skeletonAnimations = new List<SkeletonAnimation>();
readonly Dictionary<string, Animation> animationNameTable = new Dictionary<string, Animation>(); readonly Dictionary<string, Animation> animationNameTable = new Dictionary<string, Animation>();
readonly Dictionary<Animation, SkeletonAnimation> animationSkeletonTable = new Dictionary<Animation, SkeletonAnimation>(); readonly Dictionary<Animation, SkeletonAnimation> animationSkeletonTable = new Dictionary<Animation, SkeletonAnimation>();
//Stateful //Stateful
SkeletonAnimation currentSkeletonAnimation; SkeletonAnimation currentSkeletonAnimation;
void Clear () { void Clear () {
foreach (SkeletonAnimation skeletonAnimation in skeletonAnimations) foreach (SkeletonAnimation skeletonAnimation in skeletonAnimations)
Destroy(skeletonAnimation.gameObject); Destroy(skeletonAnimation.gameObject);
skeletonAnimations.Clear(); skeletonAnimations.Clear();
animationNameTable.Clear(); animationNameTable.Clear();
animationSkeletonTable.Clear(); animationSkeletonTable.Clear();
} }
void SetActiveSkeleton (int index) { void SetActiveSkeleton (int index) {
if (index < 0 || index >= skeletonAnimations.Count) if (index < 0 || index >= skeletonAnimations.Count)
SetActiveSkeleton(null); SetActiveSkeleton(null);
else else
SetActiveSkeleton(skeletonAnimations[index]); SetActiveSkeleton(skeletonAnimations[index]);
} }
void SetActiveSkeleton (SkeletonAnimation skeletonAnimation) { void SetActiveSkeleton (SkeletonAnimation skeletonAnimation) {
foreach (SkeletonAnimation iter in skeletonAnimations) foreach (SkeletonAnimation iter in skeletonAnimations)
iter.gameObject.SetActive(iter == skeletonAnimation); iter.gameObject.SetActive(iter == skeletonAnimation);
currentSkeletonAnimation = skeletonAnimation; currentSkeletonAnimation = skeletonAnimation;
} }
#region Lifecycle #region Lifecycle
void Awake () { void Awake () {
Initialize(false); Initialize(false);
} }
#endregion #endregion
#region API #region API
public Dictionary<Animation, SkeletonAnimation> AnimationSkeletonTable { get { return this.animationSkeletonTable; } } public Dictionary<Animation, SkeletonAnimation> AnimationSkeletonTable { get { return this.animationSkeletonTable; } }
public Dictionary<string, Animation> AnimationNameTable { get { return this.animationNameTable; } } public Dictionary<string, Animation> AnimationNameTable { get { return this.animationNameTable; } }
public SkeletonAnimation CurrentSkeletonAnimation { get { return this.currentSkeletonAnimation; } } public SkeletonAnimation CurrentSkeletonAnimation { get { return this.currentSkeletonAnimation; } }
public List<SkeletonAnimation> SkeletonAnimations { get { return skeletonAnimations; } } public List<SkeletonAnimation> SkeletonAnimations { get { return skeletonAnimations; } }
public void Initialize (bool overwrite) { public void Initialize (bool overwrite) {
if (skeletonAnimations.Count != 0 && !overwrite) return; if (skeletonAnimations.Count != 0 && !overwrite) return;
Clear(); Clear();
MeshGenerator.Settings settings = this.meshGeneratorSettings; MeshGenerator.Settings settings = this.meshGeneratorSettings;
Transform thisTransform = this.transform; Transform thisTransform = this.transform;
foreach (SkeletonDataAsset dataAsset in skeletonDataAssets) { foreach (SkeletonDataAsset dataAsset in skeletonDataAssets) {
SkeletonAnimation newSkeletonAnimation = SkeletonAnimation.NewSkeletonAnimationGameObject(dataAsset); SkeletonAnimation newSkeletonAnimation = SkeletonAnimation.NewSkeletonAnimationGameObject(dataAsset);
newSkeletonAnimation.transform.SetParent(thisTransform, false); newSkeletonAnimation.transform.SetParent(thisTransform, false);
newSkeletonAnimation.SetMeshSettings(settings); newSkeletonAnimation.SetMeshSettings(settings);
newSkeletonAnimation.initialFlipX = this.initialFlipX; newSkeletonAnimation.initialFlipX = this.initialFlipX;
newSkeletonAnimation.initialFlipY = this.initialFlipY; newSkeletonAnimation.initialFlipY = this.initialFlipY;
Skeleton skeleton = newSkeletonAnimation.skeleton; Skeleton skeleton = newSkeletonAnimation.skeleton;
skeleton.ScaleX = this.initialFlipX ? -1 : 1; skeleton.ScaleX = this.initialFlipX ? -1 : 1;
skeleton.ScaleY = this.initialFlipY ? -1 : 1; skeleton.ScaleY = this.initialFlipY ? -1 : 1;
newSkeletonAnimation.Initialize(false); newSkeletonAnimation.Initialize(false);
skeletonAnimations.Add(newSkeletonAnimation); skeletonAnimations.Add(newSkeletonAnimation);
} }
// Build cache // Build cache
Dictionary<string, Animation> animationNameTable = this.animationNameTable; Dictionary<string, Animation> animationNameTable = this.animationNameTable;
Dictionary<Animation, SkeletonAnimation> animationSkeletonTable = this.animationSkeletonTable; Dictionary<Animation, SkeletonAnimation> animationSkeletonTable = this.animationSkeletonTable;
foreach (SkeletonAnimation skeletonAnimation in skeletonAnimations) { foreach (SkeletonAnimation skeletonAnimation in skeletonAnimations) {
foreach (Animation animationObject in skeletonAnimation.Skeleton.Data.Animations) { foreach (Animation animationObject in skeletonAnimation.Skeleton.Data.Animations) {
animationNameTable[animationObject.Name] = animationObject; animationNameTable[animationObject.Name] = animationObject;
animationSkeletonTable[animationObject] = skeletonAnimation; animationSkeletonTable[animationObject] = skeletonAnimation;
} }
} }
SetActiveSkeleton(skeletonAnimations[0]); SetActiveSkeleton(skeletonAnimations[0]);
SetAnimation(initialAnimation, initialLoop); SetAnimation(initialAnimation, initialLoop);
} }
public Animation FindAnimation (string animationName) { public Animation FindAnimation (string animationName) {
Animation animation; Animation animation;
animationNameTable.TryGetValue(animationName, out animation); animationNameTable.TryGetValue(animationName, out animation);
return animation; return animation;
} }
public TrackEntry SetAnimation (string animationName, bool loop) { public TrackEntry SetAnimation (string animationName, bool loop) {
return SetAnimation(FindAnimation(animationName), loop); return SetAnimation(FindAnimation(animationName), loop);
} }
public TrackEntry SetAnimation (Animation animation, bool loop) { public TrackEntry SetAnimation (Animation animation, bool loop) {
if (animation == null) return null; if (animation == null) return null;
SkeletonAnimation skeletonAnimation; SkeletonAnimation skeletonAnimation;
animationSkeletonTable.TryGetValue(animation, out skeletonAnimation); animationSkeletonTable.TryGetValue(animation, out skeletonAnimation);
if (skeletonAnimation != null) { if (skeletonAnimation != null) {
SetActiveSkeleton(skeletonAnimation); SetActiveSkeleton(skeletonAnimation);
skeletonAnimation.skeleton.SetToSetupPose(); skeletonAnimation.skeleton.SetToSetupPose();
TrackEntry trackEntry = skeletonAnimation.state.SetAnimation(MainTrackIndex, animation, loop); TrackEntry trackEntry = skeletonAnimation.state.SetAnimation(MainTrackIndex, animation, loop);
skeletonAnimation.Update(0); skeletonAnimation.Update(0);
return trackEntry; return trackEntry;
} }
return null; return null;
} }
public void SetEmptyAnimation (float mixDuration) { public void SetEmptyAnimation (float mixDuration) {
currentSkeletonAnimation.state.SetEmptyAnimation(MainTrackIndex, mixDuration); currentSkeletonAnimation.state.SetEmptyAnimation(MainTrackIndex, mixDuration);
} }
public void ClearAnimation () { public void ClearAnimation () {
currentSkeletonAnimation.state.ClearTrack(MainTrackIndex); currentSkeletonAnimation.state.ClearTrack(MainTrackIndex);
} }
public TrackEntry GetCurrent () { public TrackEntry GetCurrent () {
return currentSkeletonAnimation.state.GetCurrent(MainTrackIndex); return currentSkeletonAnimation.state.GetCurrent(MainTrackIndex);
} }
#endregion #endregion
} }
} }

View File

@ -1,83 +1,83 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine; using Spine;
using Spine.Unity; using Spine.Unity;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Prototyping { namespace Spine.Unity.Prototyping {
/// <summary> /// <summary>
/// Stores and serializes initial settings for a Spine Skeleton component. The settings only get applied on Start at runtime.</summary> /// Stores and serializes initial settings for a Spine Skeleton component. The settings only get applied on Start at runtime.</summary>
public class SkeletonColorInitialize : MonoBehaviour { public class SkeletonColorInitialize : MonoBehaviour {
public Color skeletonColor = Color.white; public Color skeletonColor = Color.white;
public List<SlotSettings> slotSettings = new List<SlotSettings>(); public List<SlotSettings> slotSettings = new List<SlotSettings>();
[System.Serializable] [System.Serializable]
public class SlotSettings { public class SlotSettings {
[SpineSlot] [SpineSlot]
public string slot = string.Empty; public string slot = string.Empty;
public Color color = Color.white; public Color color = Color.white;
} }
#if UNITY_EDITOR #if UNITY_EDITOR
void OnValidate () { void OnValidate () {
ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>(); ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>();
if (skeletonComponent != null) { if (skeletonComponent != null) {
skeletonComponent.Skeleton.SetSlotsToSetupPose(); skeletonComponent.Skeleton.SetSlotsToSetupPose();
IAnimationStateComponent animationStateComponent = GetComponent<IAnimationStateComponent>(); IAnimationStateComponent animationStateComponent = GetComponent<IAnimationStateComponent>();
if (animationStateComponent != null && animationStateComponent.AnimationState != null) { if (animationStateComponent != null && animationStateComponent.AnimationState != null) {
animationStateComponent.AnimationState.Apply(skeletonComponent.Skeleton); animationStateComponent.AnimationState.Apply(skeletonComponent.Skeleton);
} }
} }
ApplySettings(); ApplySettings();
} }
#endif #endif
void Start () { void Start () {
ApplySettings(); ApplySettings();
} }
void ApplySettings () { void ApplySettings () {
ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>(); ISkeletonComponent skeletonComponent = GetComponent<ISkeletonComponent>();
if (skeletonComponent != null) { if (skeletonComponent != null) {
Skeleton skeleton = skeletonComponent.Skeleton; Skeleton skeleton = skeletonComponent.Skeleton;
skeleton.SetColor(skeletonColor); skeleton.SetColor(skeletonColor);
foreach (SlotSettings s in slotSettings) { foreach (SlotSettings s in slotSettings) {
Slot slot = skeleton.FindSlot(s.slot); Slot slot = skeleton.FindSlot(s.slot);
if (slot != null) slot.SetColor(s.color); if (slot != null) slot.SetColor(s.color);
} }
} }
} }
} }
} }

View File

@ -1,104 +1,104 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SkeletonGraphicMirror : MonoBehaviour { public class SkeletonGraphicMirror : MonoBehaviour {
public SkeletonRenderer source; public SkeletonRenderer source;
public bool mirrorOnStart = true; public bool mirrorOnStart = true;
public bool restoreOnDisable = true; public bool restoreOnDisable = true;
SkeletonGraphic skeletonGraphic; SkeletonGraphic skeletonGraphic;
Skeleton originalSkeleton; Skeleton originalSkeleton;
bool originalFreeze; bool originalFreeze;
Texture2D overrideTexture; Texture2D overrideTexture;
private void Awake () { private void Awake () {
skeletonGraphic = GetComponent<SkeletonGraphic>(); skeletonGraphic = GetComponent<SkeletonGraphic>();
} }
void Start () { void Start () {
if (mirrorOnStart) if (mirrorOnStart)
StartMirroring(); StartMirroring();
} }
void LateUpdate () { void LateUpdate () {
skeletonGraphic.UpdateMesh(); skeletonGraphic.UpdateMesh();
} }
void OnDisable () { void OnDisable () {
if (restoreOnDisable) if (restoreOnDisable)
RestoreIndependentSkeleton(); RestoreIndependentSkeleton();
} }
/// <summary>Freeze the SkeletonGraphic on this GameObject, and use the source as the Skeleton to be rendered by the SkeletonGraphic.</summary> /// <summary>Freeze the SkeletonGraphic on this GameObject, and use the source as the Skeleton to be rendered by the SkeletonGraphic.</summary>
public void StartMirroring () { public void StartMirroring () {
if (source == null) if (source == null)
return; return;
if (skeletonGraphic == null) if (skeletonGraphic == null)
return; return;
skeletonGraphic.startingAnimation = string.Empty; skeletonGraphic.startingAnimation = string.Empty;
if (originalSkeleton == null) { if (originalSkeleton == null) {
originalSkeleton = skeletonGraphic.Skeleton; originalSkeleton = skeletonGraphic.Skeleton;
originalFreeze = skeletonGraphic.freeze; originalFreeze = skeletonGraphic.freeze;
} }
skeletonGraphic.Skeleton = source.skeleton; skeletonGraphic.Skeleton = source.skeleton;
skeletonGraphic.freeze = true; skeletonGraphic.freeze = true;
if (overrideTexture != null) if (overrideTexture != null)
skeletonGraphic.OverrideTexture = overrideTexture; skeletonGraphic.OverrideTexture = overrideTexture;
} }
/// <summary>Use a new texture for the SkeletonGraphic. Use this if your source skeleton uses a repacked atlas. </summary> /// <summary>Use a new texture for the SkeletonGraphic. Use this if your source skeleton uses a repacked atlas. </summary>
public void UpdateTexture (Texture2D newOverrideTexture) { public void UpdateTexture (Texture2D newOverrideTexture) {
overrideTexture = newOverrideTexture; overrideTexture = newOverrideTexture;
if (newOverrideTexture != null) if (newOverrideTexture != null)
skeletonGraphic.OverrideTexture = overrideTexture; skeletonGraphic.OverrideTexture = overrideTexture;
} }
/// <summary>Stops mirroring the source SkeletonRenderer and allows the SkeletonGraphic to become an independent Skeleton component again.</summary> /// <summary>Stops mirroring the source SkeletonRenderer and allows the SkeletonGraphic to become an independent Skeleton component again.</summary>
public void RestoreIndependentSkeleton () { public void RestoreIndependentSkeleton () {
if (originalSkeleton == null) if (originalSkeleton == null)
return; return;
skeletonGraphic.Skeleton = originalSkeleton; skeletonGraphic.Skeleton = originalSkeleton;
skeletonGraphic.freeze = originalFreeze; skeletonGraphic.freeze = originalFreeze;
skeletonGraphic.OverrideTexture = null; skeletonGraphic.OverrideTexture = null;
originalSkeleton = null; originalSkeleton = null;
} }
} }
} }

View File

@ -1,52 +1,52 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using Spine.Unity; using Spine.Unity;
using UnityEngine; using UnityEngine;
public class SkeletonGraphicPlayAnimationAtEvent : MonoBehaviour { public class SkeletonGraphicPlayAnimationAtEvent : MonoBehaviour {
public SkeletonGraphic skeletonGraphic; public SkeletonGraphic skeletonGraphic;
public int trackIndex = 0; public int trackIndex = 0;
public float playbackSpeed = 1.0f; public float playbackSpeed = 1.0f;
public void PlayAnimationLooping (string animation) { public void PlayAnimationLooping (string animation) {
Spine.TrackEntry entry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animation, true); Spine.TrackEntry entry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animation, true);
entry.TimeScale = playbackSpeed; entry.TimeScale = playbackSpeed;
} }
public void PlayAnimationOnce (string animation) { public void PlayAnimationOnce (string animation) {
Spine.TrackEntry entry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animation, false); Spine.TrackEntry entry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animation, false);
entry.TimeScale = playbackSpeed; entry.TimeScale = playbackSpeed;
} }
public void ClearTrack () { public void ClearTrack () {
skeletonGraphic.AnimationState.ClearTrack(trackIndex); skeletonGraphic.AnimationState.ClearTrack(trackIndex);
} }
} }

View File

@ -0,0 +1,106 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: RenderQuadGraphicMaterial
m_Shader: {fileID: 4800000, guid: fa95b0fb6983c0f40a152e6f9aa82bfb, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords:
- _CANVAS_GROUP_COMPATIBLE
m_InvalidKeywords:
- _ALPHAPREMULTIPLY_ON
- _USE8NEIGHBOURHOOD_ON
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _CanvasGroupCompatible: 1
- _ColorMask: 15
- _Cutoff: 0.5
- _DarkColorAlphaAdditive: 0
- _DetailNormalMapScale: 1
- _DstBlend: 10
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 3
- _OcclusionStrength: 1
- _OutlineMipLevel: 0
- _OutlineOpaqueAlpha: 1
- _OutlineReferenceTexWidth: 1024
- _OutlineSmoothness: 1
- _OutlineWidth: 3
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Stencil: 0
- _StencilComp: 8
- _StencilOp: 0
- _StencilReadMask: 255
- _StencilRef: 1
- _StencilWriteMask: 255
- _StraightAlphaInput: 0
- _ThresholdEnd: 0.25
- _UVSec: 0
- _Use8Neighbourhood: 1
- _UseUIAlphaClip: 0
- _ZWrite: 0
m_Colors:
- _Black: {r: 0, g: 0, b: 0, a: 0}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _OutlineColor: {r: 1, g: 1, b: 0, a: 1}
m_BuildTextureStacks: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: afeb0ae2ea2cda94796515bf8d1b3cb1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,260 +1,295 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2022, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2017_2_OR_NEWER #if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR2INT #define HAS_VECTOR2INT
#endif #endif
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
using UnityEngine.UI; using UnityEngine.UI;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
/// <summary> /// <summary>
/// When enabled, this component renders a skeleton to a RenderTexture and /// When enabled, this component renders a skeleton to a RenderTexture and
/// then draws this RenderTexture at a UI RawImage quad of the same size. /// then draws this RenderTexture at a UI SkeletonSubmeshGraphic quad of the same size.
/// This allows changing transparency at a single quad, which produces a more /// This allows changing transparency at a single quad, which produces a more
/// natural fadeout effect. /// natural fadeout effect.
/// Note: It is recommended to keep this component disabled as much as possible /// Note: It is recommended to keep this component disabled as much as possible
/// because of the additional rendering overhead. Only enable it when alpha blending is required. /// because of the additional rendering overhead. Only enable it when alpha blending is required.
/// </summary> /// </summary>
[RequireComponent(typeof(SkeletonGraphic))] [RequireComponent(typeof(SkeletonGraphic))]
public class SkeletonGraphicRenderTexture : SkeletonRenderTextureBase { public class SkeletonGraphicRenderTexture : SkeletonRenderTextureBase {
#if HAS_VECTOR2INT #if HAS_VECTOR2INT
[System.Serializable] [System.Serializable]
public struct TextureMaterialPair { public struct TextureMaterialPair {
public Texture texture; public Texture texture;
public Material material; public Material material;
public TextureMaterialPair (Texture texture, Material material) { public TextureMaterialPair (Texture texture, Material material) {
this.texture = texture; this.texture = texture;
this.material = material; this.material = material;
} }
} }
public RectTransform customRenderRect; public RectTransform customRenderRect;
protected SkeletonGraphic skeletonGraphic; protected SkeletonGraphic skeletonGraphic;
public List<TextureMaterialPair> meshRendererMaterialForTexture = new List<TextureMaterialPair>(); public List<TextureMaterialPair> meshRendererMaterialForTexture = new List<TextureMaterialPair>();
protected CanvasRenderer quadCanvasRenderer; protected CanvasRenderer quadCanvasRenderer;
protected RawImage quadRawImage; protected SkeletonSubmeshGraphic quadMaskableGraphic;
protected readonly Vector3[] worldCorners = new Vector3[4]; protected readonly Vector3[] worldCorners = new Vector3[4];
protected override void Awake () { public void ResetMeshRendererMaterials () {
base.Awake(); meshRendererMaterialForTexture.Clear();
skeletonGraphic = this.GetComponent<SkeletonGraphic>(); AtlasAssetBase[] atlasAssets = skeletonGraphic.SkeletonDataAsset.atlasAssets;
if (targetCamera == null) { for (int i = 0; i < atlasAssets.Length; ++i) {
targetCamera = skeletonGraphic.canvas.worldCamera; foreach (Material material in atlasAssets[i].Materials) {
if (targetCamera == null) if (material.mainTexture != null) {
targetCamera = Camera.main; meshRendererMaterialForTexture.Add(
} new TextureMaterialPair(material.mainTexture, material));
CreateQuadChild(); }
} }
}
void CreateQuadChild () { }
quad = new GameObject(this.name + " RenderTexture", typeof(CanvasRenderer), typeof(RawImage));
quad.transform.SetParent(this.transform.parent, false); protected override void Awake () {
quadCanvasRenderer = quad.GetComponent<CanvasRenderer>(); base.Awake();
quadRawImage = quad.GetComponent<RawImage>(); skeletonGraphic = this.GetComponent<SkeletonGraphic>();
if (targetCamera == null) {
quadMesh = new Mesh(); targetCamera = skeletonGraphic.canvas.worldCamera;
quadMesh.MarkDynamic(); if (targetCamera == null)
quadMesh.name = "RenderTexture Quad"; targetCamera = Camera.main;
quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; }
} CreateQuadChild();
}
void Reset () {
skeletonGraphic = this.GetComponent<SkeletonGraphic>(); void CreateQuadChild () {
AtlasAssetBase[] atlasAssets = skeletonGraphic.SkeletonDataAsset.atlasAssets; quad = new GameObject(this.name + " RenderTexture", typeof(CanvasRenderer), typeof(SkeletonSubmeshGraphic));
for (int i = 0; i < atlasAssets.Length; ++i) { quad.transform.SetParent(this.transform.parent, false);
foreach (Material material in atlasAssets[i].Materials) { quadCanvasRenderer = quad.GetComponent<CanvasRenderer>();
if (material.mainTexture != null) { quadMaskableGraphic = quad.GetComponent<SkeletonSubmeshGraphic>();
meshRendererMaterialForTexture.Add(
new TextureMaterialPair(material.mainTexture, material)); quadMesh = new Mesh();
} quadMesh.MarkDynamic();
} quadMesh.name = "RenderTexture Quad";
} quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor;
}
if (quadMaterial == null) {
void OnEnable () { quadMaterial = new Material(Shader.Find("Spine/SkeletonGraphic"));
skeletonGraphic.OnInstructionsPrepared += PrepareQuad; quadMaterial.EnableKeyword("_CANVAS_GROUP_COMPATIBLE");
skeletonGraphic.AssignMeshOverrideSingleRenderer += RenderSingleMeshToRenderTexture; }
skeletonGraphic.AssignMeshOverrideMultipleRenderers += RenderMultipleMeshesToRenderTexture; }
skeletonGraphic.disableMeshAssignmentOnOverride = true;
skeletonGraphic.OnMeshAndMaterialsUpdated += RenderOntoQuad; void Reset () {
List<CanvasRenderer> canvasRenderers = skeletonGraphic.canvasRenderers; skeletonGraphic = this.GetComponent<SkeletonGraphic>();
for (int i = 0; i < canvasRenderers.Count; ++i) ResetMeshRendererMaterials();
canvasRenderers[i].cull = true; #if UNITY_EDITOR
string[] assets = UnityEditor.AssetDatabase.FindAssets("t:material RenderQuadGraphicMaterial");
if (quadCanvasRenderer) if (assets.Length > 0) {
quadCanvasRenderer.gameObject.SetActive(true); string materialPath = UnityEditor.AssetDatabase.GUIDToAssetPath(assets[0]);
} quadMaterial = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(materialPath);
}
void OnDisable () { #endif
skeletonGraphic.OnInstructionsPrepared -= PrepareQuad; }
skeletonGraphic.AssignMeshOverrideSingleRenderer -= RenderSingleMeshToRenderTexture;
skeletonGraphic.AssignMeshOverrideMultipleRenderers -= RenderMultipleMeshesToRenderTexture; void OnEnable () {
skeletonGraphic.disableMeshAssignmentOnOverride = false; skeletonGraphic.OnInstructionsPrepared += PrepareQuad;
skeletonGraphic.OnMeshAndMaterialsUpdated -= RenderOntoQuad; skeletonGraphic.AssignMeshOverrideSingleRenderer += RenderSingleMeshToRenderTexture;
List<CanvasRenderer> canvasRenderers = skeletonGraphic.canvasRenderers; skeletonGraphic.AssignMeshOverrideMultipleRenderers += RenderMultipleMeshesToRenderTexture;
for (int i = 0; i < canvasRenderers.Count; ++i) skeletonGraphic.disableMeshAssignmentOnOverride = true;
canvasRenderers[i].cull = false; skeletonGraphic.OnMeshAndMaterialsUpdated += RenderOntoQuad;
skeletonGraphic.OnAnimationRebuild += OnRebuild;
if (quadCanvasRenderer) List<CanvasRenderer> canvasRenderers = skeletonGraphic.canvasRenderers;
quadCanvasRenderer.gameObject.SetActive(false); for (int i = 0; i < canvasRenderers.Count; ++i)
if (renderTexture) canvasRenderers[i].cull = true;
RenderTexture.ReleaseTemporary(renderTexture);
allocatedRenderTextureSize = Vector2Int.zero; if (quadCanvasRenderer)
} quadCanvasRenderer.gameObject.SetActive(true);
}
void PrepareQuad (SkeletonRendererInstruction instruction) {
PrepareForMesh(); void OnDisable () {
SetupQuad(); skeletonGraphic.OnInstructionsPrepared -= PrepareQuad;
} skeletonGraphic.AssignMeshOverrideSingleRenderer -= RenderSingleMeshToRenderTexture;
skeletonGraphic.AssignMeshOverrideMultipleRenderers -= RenderMultipleMeshesToRenderTexture;
void RenderOntoQuad (SkeletonGraphic skeletonRenderer) { skeletonGraphic.disableMeshAssignmentOnOverride = false;
AssignAtQuad(); skeletonGraphic.OnMeshAndMaterialsUpdated -= RenderOntoQuad;
} skeletonGraphic.OnAnimationRebuild -= OnRebuild;
List<CanvasRenderer> canvasRenderers = skeletonGraphic.canvasRenderers;
protected void PrepareForMesh () { for (int i = 0; i < canvasRenderers.Count; ++i)
// We need to get the min/max of all four corners, rotation of the skeleton canvasRenderers[i].cull = false;
// in combination with perspective projection otherwise might lead to incorrect
// screen space min/max. if (quadCanvasRenderer)
RectTransform rectTransform = customRenderRect ? customRenderRect : skeletonGraphic.rectTransform; quadCanvasRenderer.gameObject.SetActive(false);
rectTransform.GetWorldCorners(worldCorners); if (renderTexture)
RenderTexture.ReleaseTemporary(renderTexture);
RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode; allocatedRenderTextureSize = Vector2Int.zero;
Vector3 screenCorner0, screenCorner1, screenCorner2, screenCorner3; }
// note: world corners are ordered bottom left, top left, top right, bottom right.
// This corresponds to 0, 3, 1, 2 in our desired order. void PrepareQuad (SkeletonRendererInstruction instruction) {
if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) { PrepareForMesh();
screenCorner0 = worldCorners[0]; SetupQuad();
screenCorner1 = worldCorners[3]; }
screenCorner2 = worldCorners[1];
screenCorner3 = worldCorners[2]; void RenderOntoQuad (SkeletonGraphic skeletonRenderer) {
} else { AssignAtQuad();
screenCorner0 = targetCamera.WorldToScreenPoint(worldCorners[0]); }
screenCorner1 = targetCamera.WorldToScreenPoint(worldCorners[3]);
screenCorner2 = targetCamera.WorldToScreenPoint(worldCorners[1]); void OnRebuild (ISkeletonAnimation skeletonGraphic) {
screenCorner3 = targetCamera.WorldToScreenPoint(worldCorners[2]); ResetMeshRendererMaterials();
} }
// To avoid perspective distortion when rotated, we project all vertices protected void PrepareForMesh () {
// onto a plane parallel to the view frustum near plane. // We need to get the min/max of all four corners, rotation of the skeleton
// Avoids the requirement of 'noperspective' vertex attribute interpolation modifier in shaders. // in combination with perspective projection otherwise might lead to incorrect
float averageScreenDepth = (screenCorner0.z + screenCorner1.z + screenCorner2.z + screenCorner3.z) / 4.0f; // screen space min/max.
screenCorner0.z = screenCorner1.z = screenCorner2.z = screenCorner3.z = averageScreenDepth; RectTransform rectTransform = customRenderRect ? customRenderRect : skeletonGraphic.rectTransform;
rectTransform.GetWorldCorners(worldCorners);
if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
worldCornerNoDistortion0 = screenCorner0; RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode;
worldCornerNoDistortion1 = screenCorner1; Vector3 screenCorner0, screenCorner1, screenCorner2, screenCorner3;
worldCornerNoDistortion2 = screenCorner2; // note: world corners are ordered bottom left, top left, top right, bottom right.
worldCornerNoDistortion3 = screenCorner3; // This corresponds to 0, 3, 1, 2 in our desired order.
} else { if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
worldCornerNoDistortion0 = targetCamera.ScreenToWorldPoint(screenCorner0); screenCorner0 = worldCorners[0];
worldCornerNoDistortion1 = targetCamera.ScreenToWorldPoint(screenCorner1); screenCorner1 = worldCorners[3];
worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2); screenCorner2 = worldCorners[1];
worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3); screenCorner3 = worldCorners[2];
} } else {
Vector3 screenSpaceMin, screenSpaceMax; screenCorner0 = targetCamera.WorldToScreenPoint(worldCorners[0]);
PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax, screenCorner1 = targetCamera.WorldToScreenPoint(worldCorners[3]);
screenCorner0, screenCorner1, screenCorner2, screenCorner3); screenCorner2 = targetCamera.WorldToScreenPoint(worldCorners[1]);
PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax); screenCorner3 = targetCamera.WorldToScreenPoint(worldCorners[2]);
} }
protected Material MeshRendererMaterialForTexture (Texture texture) { // To avoid perspective distortion when rotated, we project all vertices
return meshRendererMaterialForTexture.Find(x => x.texture == texture).material; // onto a plane parallel to the view frustum near plane.
} // Avoids the requirement of 'noperspective' vertex attribute interpolation modifier in shaders.
float averageScreenDepth = (screenCorner0.z + screenCorner1.z + screenCorner2.z + screenCorner3.z) / 4.0f;
protected void RenderSingleMeshToRenderTexture (Mesh mesh, Material graphicMaterial, Texture texture) { screenCorner0.z = screenCorner1.z = screenCorner2.z = screenCorner3.z = averageScreenDepth;
Material meshRendererMaterial = MeshRendererMaterialForTexture(texture);
commandBuffer.DrawMesh(mesh, transform.localToWorldMatrix, meshRendererMaterial, 0, -1); if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
Graphics.ExecuteCommandBuffer(commandBuffer); worldCornerNoDistortion0 = screenCorner0;
} worldCornerNoDistortion1 = screenCorner1;
worldCornerNoDistortion2 = screenCorner2;
protected void RenderMultipleMeshesToRenderTexture (int meshCount, worldCornerNoDistortion3 = screenCorner3;
Mesh[] meshes, Material[] graphicMaterials, Texture[] textures) { } else {
worldCornerNoDistortion0 = targetCamera.ScreenToWorldPoint(screenCorner0);
for (int i = 0; i < meshCount; ++i) { worldCornerNoDistortion1 = targetCamera.ScreenToWorldPoint(screenCorner1);
Material meshRendererMaterial = MeshRendererMaterialForTexture(textures[i]); worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2);
commandBuffer.DrawMesh(meshes[i], transform.localToWorldMatrix, meshRendererMaterial, 0, -1); worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3);
} }
Graphics.ExecuteCommandBuffer(commandBuffer); Vector3 screenSpaceMin, screenSpaceMax;
} PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax,
screenCorner0, screenCorner1, screenCorner2, screenCorner3);
protected void SetupQuad () { PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax);
quadRawImage.texture = this.renderTexture; }
quadRawImage.color = color;
quadCanvasRenderer.SetColor(color); protected Material MeshRendererMaterialForTexture (Texture texture) {
return meshRendererMaterialForTexture.Find(x => x.texture == texture).material;
RectTransform srcRectTransform = skeletonGraphic.rectTransform; }
RectTransform dstRectTransform = quadRawImage.rectTransform;
protected void RenderSingleMeshToRenderTexture (Mesh mesh, Material graphicMaterial, Texture texture) {
dstRectTransform.anchorMin = srcRectTransform.anchorMin; if (mesh.subMeshCount == 0) return;
dstRectTransform.anchorMax = srcRectTransform.anchorMax; Material meshRendererMaterial = MeshRendererMaterialForTexture(texture);
dstRectTransform.anchoredPosition = srcRectTransform.anchoredPosition; foreach (int shaderPass in shaderPasses)
dstRectTransform.pivot = srcRectTransform.pivot; commandBuffer.DrawMesh(mesh, transform.localToWorldMatrix, meshRendererMaterial, 0, shaderPass);
dstRectTransform.localScale = srcRectTransform.localScale; Graphics.ExecuteCommandBuffer(commandBuffer);
dstRectTransform.sizeDelta = srcRectTransform.sizeDelta; }
dstRectTransform.rotation = srcRectTransform.rotation;
} protected void RenderMultipleMeshesToRenderTexture (int meshCount,
Mesh[] meshes, Material[] graphicMaterials, Texture[] textures) {
protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) {
commandBuffer.Clear(); for (int i = 0; i < meshCount; ++i) {
commandBuffer.SetRenderTarget(renderTexture); Mesh mesh = meshes[i];
commandBuffer.ClearRenderTarget(true, true, Color.clear); if (mesh.subMeshCount == 0) continue;
Rect canvasRect = skeletonGraphic.canvas.pixelRect; Material meshRendererMaterial = MeshRendererMaterialForTexture(textures[i]);
foreach (int shaderPass in shaderPasses)
Matrix4x4 projectionMatrix = Matrix4x4.Ortho( commandBuffer.DrawMesh(mesh, transform.localToWorldMatrix, meshRendererMaterial, 0, shaderPass);
canvasRect.x, canvasRect.x + canvasRect.width, }
canvasRect.y, canvasRect.y + canvasRect.height, Graphics.ExecuteCommandBuffer(commandBuffer);
float.MinValue, float.MaxValue); }
RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode; protected void SetupQuad () {
if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) { quadCanvasRenderer.SetMaterial(quadMaterial, this.renderTexture);
commandBuffer.SetViewMatrix(Matrix4x4.identity); quadMaskableGraphic.color = color;
commandBuffer.SetProjectionMatrix(projectionMatrix); quadCanvasRenderer.SetColor(color);
} else {
commandBuffer.SetViewMatrix(targetCamera.worldToCameraMatrix); RectTransform srcRectTransform = skeletonGraphic.rectTransform;
commandBuffer.SetProjectionMatrix(targetCamera.projectionMatrix); RectTransform dstRectTransform = quadMaskableGraphic.rectTransform;
}
dstRectTransform.anchorMin = srcRectTransform.anchorMin;
Vector2 targetCameraViewportSize = targetCamera.pixelRect.size; dstRectTransform.anchorMax = srcRectTransform.anchorMax;
Rect viewportRect = new Rect(-screenSpaceMin * downScaleFactor, targetCameraViewportSize * downScaleFactor); dstRectTransform.anchoredPosition = srcRectTransform.anchoredPosition;
commandBuffer.SetViewport(viewportRect); dstRectTransform.pivot = srcRectTransform.pivot;
} dstRectTransform.localScale = srcRectTransform.localScale;
dstRectTransform.sizeDelta = srcRectTransform.sizeDelta;
protected override void AssignMeshAtRenderer () { dstRectTransform.rotation = srcRectTransform.rotation;
quadCanvasRenderer.SetMesh(quadMesh); }
}
#endif // HAS_VECTOR2INT protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) {
} commandBuffer.Clear();
} commandBuffer.SetRenderTarget(renderTexture);
commandBuffer.ClearRenderTarget(true, true, Color.clear);
Vector2 targetViewportSize = new Vector2(
screenSpaceMax.x - screenSpaceMin.x,
screenSpaceMax.y - screenSpaceMin.y);
RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode;
if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
Rect canvasRect = skeletonGraphic.canvas.pixelRect;
canvasRect.x += screenSpaceMin.x;
canvasRect.y += screenSpaceMin.y;
canvasRect.width = targetViewportSize.x;
canvasRect.height = targetViewportSize.y;
Matrix4x4 projectionMatrix = Matrix4x4.Ortho(
canvasRect.x, canvasRect.x + canvasRect.width,
canvasRect.y, canvasRect.y + canvasRect.height,
float.MinValue, float.MaxValue);
commandBuffer.SetViewMatrix(Matrix4x4.identity);
commandBuffer.SetProjectionMatrix(projectionMatrix);
} else {
commandBuffer.SetViewMatrix(targetCamera.worldToCameraMatrix);
Matrix4x4 projectionMatrix = CalculateProjectionMatrix(targetCamera,
screenSpaceMin, screenSpaceMax, skeletonGraphic.canvas.pixelRect.size);
commandBuffer.SetProjectionMatrix(projectionMatrix);
}
Rect viewportRect = new Rect(Vector2.zero, targetViewportSize * downScaleFactor);
commandBuffer.SetViewport(viewportRect);
}
protected override void AssignMeshAtRenderer () {
quadCanvasRenderer.SetMesh(quadMesh);
}
#endif // HAS_VECTOR2INT
}
}

View File

@ -1,191 +1,221 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2022, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2019_3_OR_NEWER #if UNITY_2019_3_OR_NEWER
#define HAS_FORCE_RENDER_OFF #define HAS_FORCE_RENDER_OFF
#endif #endif
#if UNITY_2018_2_OR_NEWER #if UNITY_2018_2_OR_NEWER
#define HAS_GET_SHARED_MATERIALS #define HAS_GET_SHARED_MATERIALS
#endif #endif
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
/// <summary> /// <summary>
/// When enabled, this component renders a skeleton to a RenderTexture and /// When enabled, this component renders a skeleton to a RenderTexture and
/// then draws this RenderTexture at a quad of the same size. /// then draws this RenderTexture at a quad of the same size.
/// This allows changing transparency at a single quad, which produces a more /// This allows changing transparency at a single quad, which produces a more
/// natural fadeout effect. /// natural fadeout effect.
/// Note: It is recommended to keep this component disabled as much as possible /// Note: It is recommended to keep this component disabled as much as possible
/// because of the additional rendering overhead. Only enable it when alpha blending is required. /// because of the additional rendering overhead. Only enable it when alpha blending is required.
/// </summary> /// </summary>
[RequireComponent(typeof(SkeletonRenderer))] [RequireComponent(typeof(SkeletonRenderer))]
public class SkeletonRenderTexture : SkeletonRenderTextureBase { public class SkeletonRenderTexture : SkeletonRenderTextureBase {
#if HAS_GET_SHARED_MATERIALS #if HAS_GET_SHARED_MATERIALS
public Material quadMaterial; protected SkeletonRenderer skeletonRenderer;
protected SkeletonRenderer skeletonRenderer; protected MeshRenderer meshRenderer;
protected MeshRenderer meshRenderer; protected MeshFilter meshFilter;
protected MeshFilter meshFilter; protected MeshRenderer quadMeshRenderer;
protected MeshRenderer quadMeshRenderer; protected MeshFilter quadMeshFilter;
protected MeshFilter quadMeshFilter;
private MaterialPropertyBlock propertyBlock;
private MaterialPropertyBlock propertyBlock; private readonly List<Material> materials = new List<Material>();
private readonly List<Material> materials = new List<Material>(); protected override void Awake () {
protected override void Awake () { base.Awake();
base.Awake(); meshRenderer = this.GetComponent<MeshRenderer>();
meshRenderer = this.GetComponent<MeshRenderer>(); meshFilter = this.GetComponent<MeshFilter>();
meshFilter = this.GetComponent<MeshFilter>(); skeletonRenderer = this.GetComponent<SkeletonRenderer>();
skeletonRenderer = this.GetComponent<SkeletonRenderer>(); if (targetCamera == null)
if (targetCamera == null) targetCamera = Camera.main;
targetCamera = Camera.main;
propertyBlock = new MaterialPropertyBlock();
propertyBlock = new MaterialPropertyBlock(); CreateQuadChild();
CreateQuadChild(); }
}
#if UNITY_EDITOR
void CreateQuadChild () { protected void Reset () {
quad = new GameObject(this.name + " RenderTexture", typeof(MeshRenderer), typeof(MeshFilter)); string[] folders = { "Assets", "Packages" };
quad.transform.SetParent(this.transform.parent, false); string[] assets = UnityEditor.AssetDatabase.FindAssets("t:material RenderQuadMaterial", folders);
quadMeshRenderer = quad.GetComponent<MeshRenderer>(); if (assets.Length > 0) {
quadMeshFilter = quad.GetComponent<MeshFilter>(); string materialPath = UnityEditor.AssetDatabase.GUIDToAssetPath(assets[0]);
quadMaterial = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(materialPath);
quadMeshRenderer.sortingOrder = meshRenderer.sortingOrder; }
quadMeshRenderer.sortingLayerID = meshRenderer.sortingLayerID; }
#endif
quadMesh = new Mesh();
quadMesh.MarkDynamic(); void CreateQuadChild () {
quadMesh.name = "RenderTexture Quad"; quad = new GameObject(this.name + " RenderTexture", typeof(MeshRenderer), typeof(MeshFilter));
quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; quad.transform.SetParent(this.transform.parent, false);
quad.layer = meshRenderer.gameObject.layer;
if (quadMaterial != null) quadMeshRenderer = quad.GetComponent<MeshRenderer>();
quadMeshRenderer.material = new Material(quadMaterial); quadMeshFilter = quad.GetComponent<MeshFilter>();
else
quadMeshRenderer.material = new Material(Shader.Find("Spine/RenderQuad")); quadMeshRenderer.sortingOrder = meshRenderer.sortingOrder;
} quadMeshRenderer.sortingLayerID = meshRenderer.sortingLayerID;
void OnEnable () { quadMesh = new Mesh();
skeletonRenderer.OnMeshAndMaterialsUpdated += RenderOntoQuad; quadMesh.MarkDynamic();
#if HAS_FORCE_RENDER_OFF quadMesh.name = "RenderTexture Quad";
meshRenderer.forceRenderingOff = true; quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor;
#else
Debug.LogError("This component requires Unity 2019.3 or newer for meshRenderer.forceRenderingOff. " + if (quadMaterial != null)
"Otherwise you will see the mesh rendered twice."); quadMeshRenderer.material = new Material(quadMaterial);
#endif else
if (quadMeshRenderer) quadMeshRenderer.material = new Material(Shader.Find("Spine/RenderQuad"));
quadMeshRenderer.gameObject.SetActive(true); }
}
void OnEnable () {
void OnDisable () { skeletonRenderer.OnMeshAndMaterialsUpdated += RenderOntoQuad;
skeletonRenderer.OnMeshAndMaterialsUpdated -= RenderOntoQuad; #if HAS_FORCE_RENDER_OFF
#if HAS_FORCE_RENDER_OFF meshRenderer.forceRenderingOff = true;
meshRenderer.forceRenderingOff = false; #else
#endif Debug.LogError("This component requires Unity 2019.3 or newer for meshRenderer.forceRenderingOff. " +
if (quadMeshRenderer) "Otherwise you will see the mesh rendered twice.");
quadMeshRenderer.gameObject.SetActive(false); #endif
if (renderTexture) if (quadMeshRenderer)
RenderTexture.ReleaseTemporary(renderTexture); quadMeshRenderer.gameObject.SetActive(true);
allocatedRenderTextureSize = Vector2Int.zero; }
}
void OnDisable () {
void RenderOntoQuad (SkeletonRenderer skeletonRenderer) { skeletonRenderer.OnMeshAndMaterialsUpdated -= RenderOntoQuad;
PrepareForMesh(); #if HAS_FORCE_RENDER_OFF
RenderToRenderTexture(); meshRenderer.forceRenderingOff = false;
AssignAtQuad(); #endif
} if (quadMeshRenderer)
quadMeshRenderer.gameObject.SetActive(false);
protected void PrepareForMesh () { if (renderTexture)
// We need to get the min/max of all four corners, rotation of the skeleton RenderTexture.ReleaseTemporary(renderTexture);
// in combination with perspective projection otherwise might lead to incorrect allocatedRenderTextureSize = Vector2Int.zero;
// screen space min/max. }
Bounds boundsLocalSpace = meshFilter.sharedMesh.bounds;
Vector3 localCorner0 = boundsLocalSpace.min; void RenderOntoQuad (SkeletonRenderer skeletonRenderer) {
Vector3 localCorner3 = boundsLocalSpace.max; if (meshFilter == null)
Vector3 localCorner1 = new Vector3(localCorner0.x, localCorner3.y, localCorner0.z); meshFilter = this.GetComponent<MeshFilter>();
Vector3 localCorner2 = new Vector3(localCorner3.x, localCorner0.y, localCorner3.z); Vector3 size = meshFilter.sharedMesh.bounds.size;
if (size.x == 0f || size.y == 0f) {
Vector3 worldCorner0 = transform.TransformPoint(localCorner0); AssignNullMeshAtQuad();
Vector3 worldCorner1 = transform.TransformPoint(localCorner1); return;
Vector3 worldCorner2 = transform.TransformPoint(localCorner2); }
Vector3 worldCorner3 = transform.TransformPoint(localCorner3); PrepareForMesh();
RenderToRenderTexture();
Vector3 screenCorner0 = targetCamera.WorldToScreenPoint(worldCorner0); AssignAtQuad();
Vector3 screenCorner1 = targetCamera.WorldToScreenPoint(worldCorner1); }
Vector3 screenCorner2 = targetCamera.WorldToScreenPoint(worldCorner2);
Vector3 screenCorner3 = targetCamera.WorldToScreenPoint(worldCorner3); protected void PrepareForMesh () {
// We need to get the min/max of all four corners, rotation of the skeleton
// To avoid perspective distortion when rotated, we project all vertices // in combination with perspective projection otherwise might lead to incorrect
// onto a plane parallel to the view frustum near plane. // screen space min/max.
// Avoids the requirement of 'noperspective' vertex attribute interpolation modifier in shaders. Bounds boundsLocalSpace = meshFilter.sharedMesh.bounds;
float averageScreenDepth = (screenCorner0.z + screenCorner1.z + screenCorner2.z + screenCorner3.z) / 4.0f; Vector3 localCorner0 = boundsLocalSpace.min;
screenCorner0.z = screenCorner1.z = screenCorner2.z = screenCorner3.z = averageScreenDepth; Vector3 localCorner3 = boundsLocalSpace.max;
worldCornerNoDistortion0 = targetCamera.ScreenToWorldPoint(screenCorner0); Vector3 localCorner1 = new Vector3(localCorner0.x, localCorner3.y, localCorner0.z);
worldCornerNoDistortion1 = targetCamera.ScreenToWorldPoint(screenCorner1); Vector3 localCorner2 = new Vector3(localCorner3.x, localCorner0.y, localCorner3.z);
worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2);
worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3); Vector3 worldCorner0 = transform.TransformPoint(localCorner0);
Vector3 worldCorner1 = transform.TransformPoint(localCorner1);
Vector3 screenSpaceMin, screenSpaceMax; Vector3 worldCorner2 = transform.TransformPoint(localCorner2);
PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax, Vector3 worldCorner3 = transform.TransformPoint(localCorner3);
screenCorner0, screenCorner1, screenCorner2, screenCorner3);
PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax); Vector3 screenCorner0 = targetCamera.WorldToScreenPoint(worldCorner0);
} Vector3 screenCorner1 = targetCamera.WorldToScreenPoint(worldCorner1);
Vector3 screenCorner2 = targetCamera.WorldToScreenPoint(worldCorner2);
protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) { Vector3 screenCorner3 = targetCamera.WorldToScreenPoint(worldCorner3);
commandBuffer.Clear();
commandBuffer.SetRenderTarget(renderTexture); // To avoid perspective distortion when rotated, we project all vertices
commandBuffer.ClearRenderTarget(true, true, Color.clear); // onto a plane parallel to the view frustum near plane.
// Avoids the requirement of 'noperspective' vertex attribute interpolation modifier in shaders.
commandBuffer.SetProjectionMatrix(targetCamera.projectionMatrix); float averageScreenDepth = (screenCorner0.z + screenCorner1.z + screenCorner2.z + screenCorner3.z) / 4.0f;
commandBuffer.SetViewMatrix(targetCamera.worldToCameraMatrix); screenCorner0.z = screenCorner1.z = screenCorner2.z = screenCorner3.z = averageScreenDepth;
Vector2 targetCameraViewportSize = targetCamera.pixelRect.size; worldCornerNoDistortion0 = targetCamera.ScreenToWorldPoint(screenCorner0);
Rect viewportRect = new Rect(-screenSpaceMin * downScaleFactor, targetCameraViewportSize * downScaleFactor); worldCornerNoDistortion1 = targetCamera.ScreenToWorldPoint(screenCorner1);
commandBuffer.SetViewport(viewportRect); worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2);
} worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3);
protected void RenderToRenderTexture () { Vector3 screenSpaceMin, screenSpaceMax;
meshRenderer.GetPropertyBlock(propertyBlock); PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax,
meshRenderer.GetSharedMaterials(materials); screenCorner0, screenCorner1, screenCorner2, screenCorner3);
PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax);
for (int i = 0; i < materials.Count; i++) }
commandBuffer.DrawMesh(meshFilter.sharedMesh, transform.localToWorldMatrix,
materials[i], meshRenderer.subMeshStartIndex + i, -1, propertyBlock); protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) {
Graphics.ExecuteCommandBuffer(commandBuffer); commandBuffer.Clear();
} commandBuffer.SetRenderTarget(renderTexture);
commandBuffer.ClearRenderTarget(true, true, Color.clear);
protected override void AssignMeshAtRenderer () {
quadMeshFilter.mesh = quadMesh; commandBuffer.SetViewMatrix(targetCamera.worldToCameraMatrix);
quadMeshRenderer.sharedMaterial.mainTexture = this.renderTexture;
quadMeshRenderer.sharedMaterial.color = color; Matrix4x4 projectionMatrix = CalculateProjectionMatrix(targetCamera,
} screenSpaceMin, screenSpaceMax, targetCamera.pixelRect.size);
#endif commandBuffer.SetProjectionMatrix(projectionMatrix);
}
} Vector2 targetViewportSize = new Vector2(
screenSpaceMax.x - screenSpaceMin.x,
screenSpaceMax.y - screenSpaceMin.y);
Rect viewportRect = new Rect(Vector2.zero, targetViewportSize * downScaleFactor);
commandBuffer.SetViewport(viewportRect);
}
protected void RenderToRenderTexture () {
meshRenderer.GetPropertyBlock(propertyBlock);
meshRenderer.GetSharedMaterials(materials);
for (int i = 0; i < materials.Count; i++) {
foreach (int shaderPass in shaderPasses)
commandBuffer.DrawMesh(meshFilter.sharedMesh, transform.localToWorldMatrix,
materials[i], meshRenderer.subMeshStartIndex + i, shaderPass, propertyBlock);
}
Graphics.ExecuteCommandBuffer(commandBuffer);
}
protected override void AssignMeshAtRenderer () {
quadMeshFilter.mesh = quadMesh;
quadMeshRenderer.sharedMaterial.mainTexture = this.renderTexture;
quadMeshRenderer.sharedMaterial.color = color;
}
protected void AssignNullMeshAtQuad () {
quadMeshFilter.mesh = null;
}
#endif
}
}

View File

@ -1,164 +1,208 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2022, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2017_2_OR_NEWER #if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR2INT #define HAS_VECTOR2INT
#endif #endif
using System; using System;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public abstract class SkeletonRenderTextureBase : MonoBehaviour { public abstract class SkeletonRenderTextureBase : MonoBehaviour {
#if HAS_VECTOR2INT #if HAS_VECTOR2INT
public Color color = Color.white; public Color color = Color.white;
public int maxRenderTextureSize = 1024; public int maxRenderTextureSize = 1024;
public GameObject quad; public GameObject quad;
protected Mesh quadMesh; public Material quadMaterial;
public RenderTexture renderTexture; protected Mesh quadMesh;
public Camera targetCamera; public RenderTexture renderTexture;
public Camera targetCamera;
protected CommandBuffer commandBuffer; [Tooltip("Shader passes to render to the RenderTexture. E.g. set the first element " +
protected Vector2Int screenSize; "to -1 to render all shader passes, or set it to 0 to only render the first " +
protected Vector2Int usedRenderTextureSize; "shader pass, which may be required when using URP or shadow-casting shaders.")]
protected Vector2Int allocatedRenderTextureSize; public int[] shaderPasses = new int[1] { 0 };
protected Vector2 downScaleFactor = Vector2.one;
protected CommandBuffer commandBuffer;
protected Vector3 worldCornerNoDistortion0; protected Vector2Int screenSize;
protected Vector3 worldCornerNoDistortion1; protected Vector2Int usedRenderTextureSize;
protected Vector3 worldCornerNoDistortion2; protected Vector2Int allocatedRenderTextureSize;
protected Vector3 worldCornerNoDistortion3; protected Vector2 downScaleFactor = Vector2.one;
protected Vector2 uvCorner0;
protected Vector2 uvCorner1; protected Vector3 worldCornerNoDistortion0;
protected Vector2 uvCorner2; protected Vector3 worldCornerNoDistortion1;
protected Vector2 uvCorner3; protected Vector3 worldCornerNoDistortion2;
protected Vector3 worldCornerNoDistortion3;
protected virtual void Awake () { protected Vector2 uvCorner0;
commandBuffer = new CommandBuffer(); protected Vector2 uvCorner1;
} protected Vector2 uvCorner2;
protected Vector2 uvCorner3;
void OnDestroy () {
if (renderTexture) protected virtual void Awake () {
RenderTexture.ReleaseTemporary(renderTexture); commandBuffer = new CommandBuffer();
} }
protected void PrepareTextureMapping (out Vector3 screenSpaceMin, out Vector3 screenSpaceMax, void OnDestroy () {
Vector3 screenCorner0, Vector3 screenCorner1, Vector3 screenCorner2, Vector3 screenCorner3) { if (renderTexture)
RenderTexture.ReleaseTemporary(renderTexture);
screenSpaceMin = }
Vector3.Min(screenCorner0, Vector3.Min(screenCorner1,
Vector3.Min(screenCorner2, screenCorner3))); protected void PrepareTextureMapping (out Vector3 screenSpaceMin, out Vector3 screenSpaceMax,
screenSpaceMax = Vector3 screenCorner0, Vector3 screenCorner1, Vector3 screenCorner2, Vector3 screenCorner3) {
Vector3.Max(screenCorner0, Vector3.Max(screenCorner1,
Vector3.Max(screenCorner2, screenCorner3))); screenSpaceMin =
// ensure we are on whole pixel borders Vector3.Min(screenCorner0, Vector3.Min(screenCorner1,
screenSpaceMin.x = Mathf.Floor(screenSpaceMin.x); Vector3.Min(screenCorner2, screenCorner3)));
screenSpaceMin.y = Mathf.Floor(screenSpaceMin.y); screenSpaceMax =
screenSpaceMax.x = Mathf.Ceil(screenSpaceMax.x); Vector3.Max(screenCorner0, Vector3.Max(screenCorner1,
screenSpaceMax.y = Mathf.Ceil(screenSpaceMax.y); Vector3.Max(screenCorner2, screenCorner3)));
// ensure we are on whole pixel borders
// inverse-map screenCornerN to screenSpaceMin/screenSpaceMax area to get UV coordinates screenSpaceMin.x = Mathf.Floor(screenSpaceMin.x);
uvCorner0 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner0); screenSpaceMin.y = Mathf.Floor(screenSpaceMin.y);
uvCorner1 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner1); screenSpaceMax.x = Mathf.Ceil(screenSpaceMax.x);
uvCorner2 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner2); screenSpaceMax.y = Mathf.Ceil(screenSpaceMax.y);
uvCorner3 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner3);
// inverse-map screenCornerN to screenSpaceMin/screenSpaceMax area to get UV coordinates
screenSize = new Vector2Int(Math.Abs((int)screenSpaceMax.x - (int)screenSpaceMin.x), uvCorner0 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner0);
Math.Abs((int)screenSpaceMax.y - (int)screenSpaceMin.y)); uvCorner1 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner1);
usedRenderTextureSize = new Vector2Int( uvCorner2 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner2);
Math.Min(maxRenderTextureSize, screenSize.x), uvCorner3 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner3);
Math.Min(maxRenderTextureSize, screenSize.y));
downScaleFactor = new Vector2( screenSize = new Vector2Int(Math.Abs((int)screenSpaceMax.x - (int)screenSpaceMin.x),
(float)usedRenderTextureSize.x / (float)screenSize.x, Math.Abs((int)screenSpaceMax.y - (int)screenSpaceMin.y));
(float)usedRenderTextureSize.y / (float)screenSize.y); usedRenderTextureSize = new Vector2Int(
Math.Min(maxRenderTextureSize, screenSize.x),
PrepareRenderTexture(); Math.Min(maxRenderTextureSize, screenSize.y));
} downScaleFactor = new Vector2(
(float)usedRenderTextureSize.x / (float)screenSize.x,
protected void PrepareRenderTexture () { (float)usedRenderTextureSize.y / (float)screenSize.y);
Vector2Int textureSize = new Vector2Int(
Mathf.NextPowerOfTwo(usedRenderTextureSize.x), PrepareRenderTexture();
Mathf.NextPowerOfTwo(usedRenderTextureSize.y)); }
if (textureSize != allocatedRenderTextureSize) { protected void PrepareRenderTexture () {
if (renderTexture) Vector2Int textureSize = new Vector2Int(
RenderTexture.ReleaseTemporary(renderTexture); Mathf.NextPowerOfTwo(usedRenderTextureSize.x),
renderTexture = RenderTexture.GetTemporary(textureSize.x, textureSize.y); Mathf.NextPowerOfTwo(usedRenderTextureSize.y));
renderTexture.filterMode = FilterMode.Point;
allocatedRenderTextureSize = textureSize; if (textureSize != allocatedRenderTextureSize) {
} if (renderTexture)
} RenderTexture.ReleaseTemporary(renderTexture);
renderTexture = RenderTexture.GetTemporary(textureSize.x, textureSize.y);
protected void AssignAtQuad () { renderTexture.filterMode = FilterMode.Point;
Transform quadTransform = quad.transform; allocatedRenderTextureSize = textureSize;
quadTransform.position = this.transform.position; }
quadTransform.rotation = this.transform.rotation; }
quadTransform.localScale = this.transform.localScale;
protected Matrix4x4 CalculateProjectionMatrix (Camera targetCamera,
Vector3 v0 = quadTransform.InverseTransformPoint(worldCornerNoDistortion0); Vector3 screenSpaceMin, Vector3 screenSpaceMax, Vector2 fullSizePixels) {
Vector3 v1 = quadTransform.InverseTransformPoint(worldCornerNoDistortion1); if (targetCamera.orthographic)
Vector3 v2 = quadTransform.InverseTransformPoint(worldCornerNoDistortion2); return CalculateOrthoMatrix(targetCamera, screenSpaceMin, screenSpaceMax, fullSizePixels);
Vector3 v3 = quadTransform.InverseTransformPoint(worldCornerNoDistortion3); else
Vector3[] vertices = new Vector3[4] { v0, v1, v2, v3 }; return CalculatePerspectiveMatrix(targetCamera, screenSpaceMin, screenSpaceMax, fullSizePixels);
}
quadMesh.vertices = vertices;
protected Matrix4x4 CalculateOrthoMatrix (Camera targetCamera,
int[] indices = new int[6] { 0, 1, 2, 2, 1, 3 }; Vector3 screenSpaceMin, Vector3 screenSpaceMax, Vector2 fullSizePixels) {
quadMesh.triangles = indices;
Vector2 cameraSize = new Vector2(
Vector3[] normals = new Vector3[4] { targetCamera.orthographicSize * 2.0f * targetCamera.aspect,
-Vector3.forward, targetCamera.orthographicSize * 2.0f);
-Vector3.forward, Vector2 min = new Vector2(screenSpaceMin.x, screenSpaceMin.y) / fullSizePixels;
-Vector3.forward, Vector2 max = new Vector2(screenSpaceMax.x, screenSpaceMax.y) / fullSizePixels;
-Vector3.forward Vector2 centerOffset = new Vector2(-0.5f, -0.5f);
}; min = (min + centerOffset) * cameraSize;
quadMesh.normals = normals; max = (max + centerOffset) * cameraSize;
float maxU = (float)usedRenderTextureSize.x / (float)allocatedRenderTextureSize.x; return Matrix4x4.Ortho(min.x, max.x, min.y, max.y, float.MinValue, float.MaxValue);
float maxV = (float)usedRenderTextureSize.y / (float)allocatedRenderTextureSize.y; }
if (downScaleFactor.x < 1 || downScaleFactor.y < 1) {
maxU = downScaleFactor.x * (float)screenSize.x / (float)allocatedRenderTextureSize.x; protected Matrix4x4 CalculatePerspectiveMatrix (Camera targetCamera,
maxV = downScaleFactor.y * (float)screenSize.y / (float)allocatedRenderTextureSize.y; Vector3 screenSpaceMin, Vector3 screenSpaceMax, Vector2 fullSizePixels) {
}
Vector2[] uv = new Vector2[4] { FrustumPlanes frustumPlanes = targetCamera.projectionMatrix.decomposeProjection;
new Vector2(uvCorner0.x * maxU, uvCorner0.y * maxV), Vector2 planesSize = new Vector2(
new Vector2(uvCorner1.x * maxU, uvCorner1.y * maxV), frustumPlanes.right - frustumPlanes.left,
new Vector2(uvCorner2.x * maxU, uvCorner2.y * maxV), frustumPlanes.top - frustumPlanes.bottom);
new Vector2(uvCorner3.x * maxU, uvCorner3.y * maxV), Vector2 min = new Vector2(screenSpaceMin.x, screenSpaceMin.y) / fullSizePixels * planesSize;
}; Vector2 max = new Vector2(screenSpaceMax.x, screenSpaceMax.y) / fullSizePixels * planesSize;
quadMesh.uv = uv; frustumPlanes.right = frustumPlanes.left + max.x;
AssignMeshAtRenderer(); frustumPlanes.top = frustumPlanes.bottom + max.y;
} frustumPlanes.left += min.x;
frustumPlanes.bottom += min.y;
protected abstract void AssignMeshAtRenderer (); return Matrix4x4.Frustum(frustumPlanes);
#endif // HAS_VECTOR2INT }
}
} protected void AssignAtQuad () {
Transform quadTransform = quad.transform;
quadTransform.position = this.transform.position;
quadTransform.rotation = this.transform.rotation;
quadTransform.localScale = this.transform.localScale;
Vector3 v0 = quadTransform.InverseTransformPoint(worldCornerNoDistortion0);
Vector3 v1 = quadTransform.InverseTransformPoint(worldCornerNoDistortion1);
Vector3 v2 = quadTransform.InverseTransformPoint(worldCornerNoDistortion2);
Vector3 v3 = quadTransform.InverseTransformPoint(worldCornerNoDistortion3);
Vector3[] vertices = new Vector3[4] { v0, v1, v2, v3 };
quadMesh.vertices = vertices;
int[] indices = new int[6] { 0, 1, 2, 2, 1, 3 };
quadMesh.triangles = indices;
Vector3[] normals = new Vector3[4] {
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
quadMesh.normals = normals;
float maxU = (float)usedRenderTextureSize.x / (float)allocatedRenderTextureSize.x;
float maxV = (float)usedRenderTextureSize.y / (float)allocatedRenderTextureSize.y;
if (downScaleFactor.x < 1 || downScaleFactor.y < 1) {
maxU = downScaleFactor.x * (float)screenSize.x / (float)allocatedRenderTextureSize.x;
maxV = downScaleFactor.y * (float)screenSize.y / (float)allocatedRenderTextureSize.y;
}
Vector2[] uv = new Vector2[4] {
new Vector2(uvCorner0.x * maxU, uvCorner0.y * maxV),
new Vector2(uvCorner1.x * maxU, uvCorner1.y * maxV),
new Vector2(uvCorner2.x * maxU, uvCorner2.y * maxV),
new Vector2(uvCorner3.x * maxU, uvCorner3.y * maxV),
};
quadMesh.uv = uv;
AssignMeshAtRenderer();
}
protected abstract void AssignMeshAtRenderer ();
#endif // HAS_VECTOR2INT
}
}

View File

@ -1,88 +1,88 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2022, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2019_3_OR_NEWER #if UNITY_2019_3_OR_NEWER
#define HAS_FORCE_RENDER_OFF #define HAS_FORCE_RENDER_OFF
#endif #endif
#if UNITY_2017_2_OR_NEWER #if UNITY_2017_2_OR_NEWER
#define HAS_VECTOR_INT #define HAS_VECTOR_INT
#endif #endif
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
/// <summary> /// <summary>
/// A simple fadeout component that uses a <see cref="SkeletonRenderTexture"/> for transparency fadeout. /// A simple fadeout component that uses a <see cref="SkeletonRenderTexture"/> for transparency fadeout.
/// Attach a <see cref="SkeletonRenderTexture"/> and this component to a skeleton GameObject and disable both /// Attach a <see cref="SkeletonRenderTexture"/> and this component to a skeleton GameObject and disable both
/// components initially and keep them disabled during normal gameplay. When you need to start fadeout, /// components initially and keep them disabled during normal gameplay. When you need to start fadeout,
/// enable this component. /// enable this component.
/// At the end of the fadeout, the event delegate <c>OnFadeoutComplete</c> is called, to which you can bind e.g. /// At the end of the fadeout, the event delegate <c>OnFadeoutComplete</c> is called, to which you can bind e.g.
/// a method that disables or destroys the entire GameObject. /// a method that disables or destroys the entire GameObject.
/// </summary> /// </summary>
[RequireComponent(typeof(SkeletonRenderTextureBase))] [RequireComponent(typeof(SkeletonRenderTextureBase))]
public class SkeletonRenderTextureFadeout : MonoBehaviour { public class SkeletonRenderTextureFadeout : MonoBehaviour {
SkeletonRenderTextureBase skeletonRenderTexture; SkeletonRenderTextureBase skeletonRenderTexture;
public float fadeoutSeconds = 2.0f; public float fadeoutSeconds = 2.0f;
protected float fadeoutSecondsRemaining; protected float fadeoutSecondsRemaining;
public delegate void FadeoutCallback (SkeletonRenderTextureFadeout skeleton); public delegate void FadeoutCallback (SkeletonRenderTextureFadeout skeleton);
public event FadeoutCallback OnFadeoutComplete; public event FadeoutCallback OnFadeoutComplete;
protected void Awake () { protected void Awake () {
skeletonRenderTexture = this.GetComponent<SkeletonRenderTextureBase>(); skeletonRenderTexture = this.GetComponent<SkeletonRenderTextureBase>();
} }
protected void OnEnable () { protected void OnEnable () {
fadeoutSecondsRemaining = fadeoutSeconds; fadeoutSecondsRemaining = fadeoutSeconds;
skeletonRenderTexture.enabled = true; skeletonRenderTexture.enabled = true;
} }
protected void Update () { protected void Update () {
if (fadeoutSecondsRemaining == 0) if (fadeoutSecondsRemaining == 0)
return; return;
fadeoutSecondsRemaining -= Time.deltaTime; fadeoutSecondsRemaining -= Time.deltaTime;
if (fadeoutSecondsRemaining <= 0) { if (fadeoutSecondsRemaining <= 0) {
fadeoutSecondsRemaining = 0; fadeoutSecondsRemaining = 0;
if (OnFadeoutComplete != null) if (OnFadeoutComplete != null)
OnFadeoutComplete(this); OnFadeoutComplete(this);
return; return;
} }
float fadeoutAlpha = fadeoutSecondsRemaining / fadeoutSeconds; float fadeoutAlpha = fadeoutSecondsRemaining / fadeoutSeconds;
#if HAS_VECTOR_INT #if HAS_VECTOR_INT
skeletonRenderTexture.color.a = fadeoutAlpha; skeletonRenderTexture.color.a = fadeoutAlpha;
#else #else
Debug.LogError("The SkeletonRenderTexture component requires Unity 2017.2 or newer."); Debug.LogError("The SkeletonRenderTexture component requires Unity 2017.2 or newer.");
#endif #endif
} }
} }
} }

View File

@ -1,37 +1,37 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SkeletonRagdoll2DInspector { } public class SkeletonRagdoll2DInspector { }
} }

View File

@ -1,46 +1,46 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SkeletonRagdollInspector : UnityEditor.Editor { public class SkeletonRagdollInspector : UnityEditor.Editor {
[CustomPropertyDrawer(typeof(SkeletonRagdoll.LayerFieldAttribute))] [CustomPropertyDrawer(typeof(SkeletonRagdoll.LayerFieldAttribute))]
public class LayerFieldPropertyDrawer : PropertyDrawer { public class LayerFieldPropertyDrawer : PropertyDrawer {
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) { public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
property.intValue = EditorGUI.LayerField(position, label, property.intValue); property.intValue = EditorGUI.LayerField(position, label, property.intValue);
} }
} }
} }
} }

View File

@ -1,443 +1,443 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
[RequireComponent(typeof(SkeletonRenderer))] [RequireComponent(typeof(SkeletonRenderer))]
public class SkeletonRagdoll : MonoBehaviour { public class SkeletonRagdoll : MonoBehaviour {
static Transform parentSpaceHelper; static Transform parentSpaceHelper;
#region Inspector #region Inspector
[Header("Hierarchy")] [Header("Hierarchy")]
[SpineBone] [SpineBone]
public string startingBoneName = ""; public string startingBoneName = "";
[SpineBone] [SpineBone]
public List<string> stopBoneNames = new List<string>(); public List<string> stopBoneNames = new List<string>();
[Header("Parameters")] [Header("Parameters")]
public bool applyOnStart; public bool applyOnStart;
[Tooltip("Warning! You will have to re-enable and tune mix values manually if attempting to remove the ragdoll system.")] [Tooltip("Warning! You will have to re-enable and tune mix values manually if attempting to remove the ragdoll system.")]
public bool disableIK = true; public bool disableIK = true;
public bool disableOtherConstraints = false; public bool disableOtherConstraints = false;
[Space(18)] [Space(18)]
[Tooltip("Set RootRigidbody IsKinematic to true when Apply is called.")] [Tooltip("Set RootRigidbody IsKinematic to true when Apply is called.")]
public bool pinStartBone; public bool pinStartBone;
[Tooltip("Enable Collision between adjacent ragdoll elements (IE: Neck and Head)")] [Tooltip("Enable Collision between adjacent ragdoll elements (IE: Neck and Head)")]
public bool enableJointCollision; public bool enableJointCollision;
public bool useGravity = true; public bool useGravity = true;
[Tooltip("If no BoundingBox Attachment is attached to a bone, this becomes the default Width or Radius of a Bone's ragdoll Rigidbody")] [Tooltip("If no BoundingBox Attachment is attached to a bone, this becomes the default Width or Radius of a Bone's ragdoll Rigidbody")]
public float thickness = 0.125f; public float thickness = 0.125f;
[Tooltip("Default rotational limit value. Min is negative this value, Max is this value.")] [Tooltip("Default rotational limit value. Min is negative this value, Max is this value.")]
public float rotationLimit = 20; public float rotationLimit = 20;
public float rootMass = 20; public float rootMass = 20;
[Tooltip("If your ragdoll seems unstable or uneffected by limits, try lowering this value.")] [Tooltip("If your ragdoll seems unstable or uneffected by limits, try lowering this value.")]
[Range(0.01f, 1f)] [Range(0.01f, 1f)]
public float massFalloffFactor = 0.4f; public float massFalloffFactor = 0.4f;
[Tooltip("The layer assigned to all of the rigidbody parts.")] [Tooltip("The layer assigned to all of the rigidbody parts.")]
public int colliderLayer = 0; public int colliderLayer = 0;
[Range(0, 1)] [Range(0, 1)]
public float mix = 1; public float mix = 1;
public bool oldRagdollBehaviour = false; public bool oldRagdollBehaviour = false;
#endregion #endregion
ISkeletonAnimation targetSkeletonComponent; ISkeletonAnimation targetSkeletonComponent;
Skeleton skeleton; Skeleton skeleton;
struct BoneFlipEntry { struct BoneFlipEntry {
public BoneFlipEntry (bool flipX, bool flipY) { public BoneFlipEntry (bool flipX, bool flipY) {
this.flipX = flipX; this.flipX = flipX;
this.flipY = flipY; this.flipY = flipY;
} }
public bool flipX; public bool flipX;
public bool flipY; public bool flipY;
} }
Dictionary<Bone, Transform> boneTable = new Dictionary<Bone, Transform>(); Dictionary<Bone, Transform> boneTable = new Dictionary<Bone, Transform>();
Dictionary<Bone, BoneFlipEntry> boneFlipTable = new Dictionary<Bone, BoneFlipEntry>(); Dictionary<Bone, BoneFlipEntry> boneFlipTable = new Dictionary<Bone, BoneFlipEntry>();
Transform ragdollRoot; Transform ragdollRoot;
public Rigidbody RootRigidbody { get; private set; } public Rigidbody RootRigidbody { get; private set; }
public Bone StartingBone { get; private set; } public Bone StartingBone { get; private set; }
Vector3 rootOffset; Vector3 rootOffset;
public Vector3 RootOffset { get { return this.rootOffset; } } public Vector3 RootOffset { get { return this.rootOffset; } }
bool isActive; bool isActive;
public bool IsActive { get { return this.isActive; } } public bool IsActive { get { return this.isActive; } }
IEnumerator Start () { IEnumerator Start () {
if (parentSpaceHelper == null) { if (parentSpaceHelper == null) {
parentSpaceHelper = (new GameObject("Parent Space Helper")).transform; parentSpaceHelper = (new GameObject("Parent Space Helper")).transform;
parentSpaceHelper.hideFlags = HideFlags.HideInHierarchy; parentSpaceHelper.hideFlags = HideFlags.HideInHierarchy;
} }
targetSkeletonComponent = GetComponent<SkeletonRenderer>() as ISkeletonAnimation; targetSkeletonComponent = GetComponent<SkeletonRenderer>() as ISkeletonAnimation;
if (targetSkeletonComponent == null) Debug.LogError("Attached Spine component does not implement ISkeletonAnimation. This script is not compatible."); if (targetSkeletonComponent == null) Debug.LogError("Attached Spine component does not implement ISkeletonAnimation. This script is not compatible.");
skeleton = targetSkeletonComponent.Skeleton; skeleton = targetSkeletonComponent.Skeleton;
if (applyOnStart) { if (applyOnStart) {
yield return null; yield return null;
Apply(); Apply();
} }
} }
#region API #region API
public Rigidbody[] RigidbodyArray { public Rigidbody[] RigidbodyArray {
get { get {
if (!isActive) if (!isActive)
return new Rigidbody[0]; return new Rigidbody[0];
Rigidbody[] rigidBodies = new Rigidbody[boneTable.Count]; Rigidbody[] rigidBodies = new Rigidbody[boneTable.Count];
int i = 0; int i = 0;
foreach (Transform t in boneTable.Values) { foreach (Transform t in boneTable.Values) {
rigidBodies[i] = t.GetComponent<Rigidbody>(); rigidBodies[i] = t.GetComponent<Rigidbody>();
i++; i++;
} }
return rigidBodies; return rigidBodies;
} }
} }
public Vector3 EstimatedSkeletonPosition { public Vector3 EstimatedSkeletonPosition {
get { return RootRigidbody.position - rootOffset; } get { return RootRigidbody.position - rootOffset; }
} }
/// <summary>Instantiates the ragdoll simulation and applies its transforms to the skeleton.</summary> /// <summary>Instantiates the ragdoll simulation and applies its transforms to the skeleton.</summary>
public void Apply () { public void Apply () {
isActive = true; isActive = true;
mix = 1; mix = 1;
StartingBone = skeleton.FindBone(startingBoneName); StartingBone = skeleton.FindBone(startingBoneName);
RecursivelyCreateBoneProxies(StartingBone); RecursivelyCreateBoneProxies(StartingBone);
RootRigidbody = boneTable[StartingBone].GetComponent<Rigidbody>(); RootRigidbody = boneTable[StartingBone].GetComponent<Rigidbody>();
RootRigidbody.isKinematic = pinStartBone; RootRigidbody.isKinematic = pinStartBone;
RootRigidbody.mass = rootMass; RootRigidbody.mass = rootMass;
List<Collider> boneColliders = new List<Collider>(); List<Collider> boneColliders = new List<Collider>();
foreach (KeyValuePair<Bone, Transform> pair in boneTable) { foreach (KeyValuePair<Bone, Transform> pair in boneTable) {
Bone b = pair.Key; Bone b = pair.Key;
Transform t = pair.Value; Transform t = pair.Value;
Transform parentTransform; Transform parentTransform;
boneColliders.Add(t.GetComponent<Collider>()); boneColliders.Add(t.GetComponent<Collider>());
if (b == StartingBone) { if (b == StartingBone) {
ragdollRoot = new GameObject("RagdollRoot").transform; ragdollRoot = new GameObject("RagdollRoot").transform;
ragdollRoot.SetParent(transform, false); ragdollRoot.SetParent(transform, false);
if (b == skeleton.RootBone) { // RagdollRoot is skeleton root's parent, thus the skeleton's scale and position. if (b == skeleton.RootBone) { // RagdollRoot is skeleton root's parent, thus the skeleton's scale and position.
ragdollRoot.localPosition = new Vector3(skeleton.X, skeleton.Y, 0); ragdollRoot.localPosition = new Vector3(skeleton.X, skeleton.Y, 0);
ragdollRoot.localRotation = (skeleton.ScaleX < 0) ? Quaternion.Euler(0, 0, 180.0f) : Quaternion.identity; ragdollRoot.localRotation = (skeleton.ScaleX < 0) ? Quaternion.Euler(0, 0, 180.0f) : Quaternion.identity;
} else { } else {
ragdollRoot.localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0); ragdollRoot.localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0);
ragdollRoot.localRotation = Quaternion.Euler(0, 0, b.Parent.WorldRotationX - b.Parent.ShearX); ragdollRoot.localRotation = Quaternion.Euler(0, 0, b.Parent.WorldRotationX - b.Parent.ShearX);
} }
parentTransform = ragdollRoot; parentTransform = ragdollRoot;
rootOffset = t.position - transform.position; rootOffset = t.position - transform.position;
} else { } else {
parentTransform = boneTable[b.Parent]; parentTransform = boneTable[b.Parent];
} }
// Add joint and attach to parent. // Add joint and attach to parent.
Rigidbody rbParent = parentTransform.GetComponent<Rigidbody>(); Rigidbody rbParent = parentTransform.GetComponent<Rigidbody>();
if (rbParent != null) { if (rbParent != null) {
HingeJoint joint = t.gameObject.AddComponent<HingeJoint>(); HingeJoint joint = t.gameObject.AddComponent<HingeJoint>();
joint.connectedBody = rbParent; joint.connectedBody = rbParent;
Vector3 localPos = parentTransform.InverseTransformPoint(t.position); Vector3 localPos = parentTransform.InverseTransformPoint(t.position);
localPos.x *= 1; localPos.x *= 1;
joint.connectedAnchor = localPos; joint.connectedAnchor = localPos;
joint.axis = Vector3.forward; joint.axis = Vector3.forward;
joint.GetComponent<Rigidbody>().mass = joint.connectedBody.mass * massFalloffFactor; joint.GetComponent<Rigidbody>().mass = joint.connectedBody.mass * massFalloffFactor;
joint.limits = new JointLimits { joint.limits = new JointLimits {
min = -rotationLimit, min = -rotationLimit,
max = rotationLimit, max = rotationLimit,
}; };
joint.useLimits = true; joint.useLimits = true;
joint.enableCollision = enableJointCollision; joint.enableCollision = enableJointCollision;
} }
} }
// Ignore collisions among bones. // Ignore collisions among bones.
for (int x = 0; x < boneColliders.Count; x++) { for (int x = 0; x < boneColliders.Count; x++) {
for (int y = 0; y < boneColliders.Count; y++) { for (int y = 0; y < boneColliders.Count; y++) {
if (x == y) continue; if (x == y) continue;
Physics.IgnoreCollision(boneColliders[x], boneColliders[y]); Physics.IgnoreCollision(boneColliders[x], boneColliders[y]);
} }
} }
// Destroy existing override-mode SkeletonUtilityBones. // Destroy existing override-mode SkeletonUtilityBones.
SkeletonUtilityBone[] utilityBones = GetComponentsInChildren<SkeletonUtilityBone>(); SkeletonUtilityBone[] utilityBones = GetComponentsInChildren<SkeletonUtilityBone>();
if (utilityBones.Length > 0) { if (utilityBones.Length > 0) {
List<string> destroyedUtilityBoneNames = new List<string>(); List<string> destroyedUtilityBoneNames = new List<string>();
foreach (SkeletonUtilityBone ub in utilityBones) { foreach (SkeletonUtilityBone ub in utilityBones) {
if (ub.mode == SkeletonUtilityBone.Mode.Override) { if (ub.mode == SkeletonUtilityBone.Mode.Override) {
destroyedUtilityBoneNames.Add(ub.gameObject.name); destroyedUtilityBoneNames.Add(ub.gameObject.name);
Destroy(ub.gameObject); Destroy(ub.gameObject);
} }
} }
if (destroyedUtilityBoneNames.Count > 0) { if (destroyedUtilityBoneNames.Count > 0) {
string msg = "Destroyed Utility Bones: "; string msg = "Destroyed Utility Bones: ";
for (int i = 0; i < destroyedUtilityBoneNames.Count; i++) { for (int i = 0; i < destroyedUtilityBoneNames.Count; i++) {
msg += destroyedUtilityBoneNames[i]; msg += destroyedUtilityBoneNames[i];
if (i != destroyedUtilityBoneNames.Count - 1) { if (i != destroyedUtilityBoneNames.Count - 1) {
msg += ","; msg += ",";
} }
} }
Debug.LogWarning(msg); Debug.LogWarning(msg);
} }
} }
// Disable skeleton constraints. // Disable skeleton constraints.
if (disableIK) { if (disableIK) {
ExposedList<IkConstraint> ikConstraints = skeleton.IkConstraints; ExposedList<IkConstraint> ikConstraints = skeleton.IkConstraints;
for (int i = 0, n = ikConstraints.Count; i < n; i++) for (int i = 0, n = ikConstraints.Count; i < n; i++)
ikConstraints.Items[i].Mix = 0; ikConstraints.Items[i].Mix = 0;
} }
if (disableOtherConstraints) { if (disableOtherConstraints) {
ExposedList<TransformConstraint> transformConstraints = skeleton.TransformConstraints; ExposedList<TransformConstraint> transformConstraints = skeleton.TransformConstraints;
for (int i = 0, n = transformConstraints.Count; i < n; i++) { for (int i = 0, n = transformConstraints.Count; i < n; i++) {
transformConstraints.Items[i].MixRotate = 0; transformConstraints.Items[i].MixRotate = 0;
transformConstraints.Items[i].MixScaleX = 0; transformConstraints.Items[i].MixScaleX = 0;
transformConstraints.Items[i].MixScaleY = 0; transformConstraints.Items[i].MixScaleY = 0;
transformConstraints.Items[i].MixShearY = 0; transformConstraints.Items[i].MixShearY = 0;
transformConstraints.Items[i].MixX = 0; transformConstraints.Items[i].MixX = 0;
transformConstraints.Items[i].MixY = 0; transformConstraints.Items[i].MixY = 0;
} }
ExposedList<PathConstraint> pathConstraints = skeleton.PathConstraints; ExposedList<PathConstraint> pathConstraints = skeleton.PathConstraints;
for (int i = 0, n = pathConstraints.Count; i < n; i++) { for (int i = 0, n = pathConstraints.Count; i < n; i++) {
pathConstraints.Items[i].MixRotate = 0; pathConstraints.Items[i].MixRotate = 0;
pathConstraints.Items[i].MixX = 0; pathConstraints.Items[i].MixX = 0;
pathConstraints.Items[i].MixY = 0; pathConstraints.Items[i].MixY = 0;
} }
} }
targetSkeletonComponent.UpdateWorld += UpdateSpineSkeleton; targetSkeletonComponent.UpdateWorld += UpdateSpineSkeleton;
} }
/// <summary>Transitions the mix value from the current value to a target value.</summary> /// <summary>Transitions the mix value from the current value to a target value.</summary>
public Coroutine SmoothMix (float target, float duration) { public Coroutine SmoothMix (float target, float duration) {
return StartCoroutine(SmoothMixCoroutine(target, duration)); return StartCoroutine(SmoothMixCoroutine(target, duration));
} }
IEnumerator SmoothMixCoroutine (float target, float duration) { IEnumerator SmoothMixCoroutine (float target, float duration) {
float startTime = Time.time; float startTime = Time.time;
float startMix = mix; float startMix = mix;
while (mix > 0) { while (mix > 0) {
skeleton.SetBonesToSetupPose(); skeleton.SetBonesToSetupPose();
mix = Mathf.SmoothStep(startMix, target, (Time.time - startTime) / duration); mix = Mathf.SmoothStep(startMix, target, (Time.time - startTime) / duration);
yield return null; yield return null;
} }
} }
/// <summary>Set the transform world position while preserving the ragdoll parts world position.</summary> /// <summary>Set the transform world position while preserving the ragdoll parts world position.</summary>
public void SetSkeletonPosition (Vector3 worldPosition) { public void SetSkeletonPosition (Vector3 worldPosition) {
if (!isActive) { if (!isActive) {
Debug.LogWarning("Can't call SetSkeletonPosition while Ragdoll is not active!"); Debug.LogWarning("Can't call SetSkeletonPosition while Ragdoll is not active!");
return; return;
} }
Vector3 offset = worldPosition - transform.position; Vector3 offset = worldPosition - transform.position;
transform.position = worldPosition; transform.position = worldPosition;
foreach (Transform t in boneTable.Values) foreach (Transform t in boneTable.Values)
t.position -= offset; t.position -= offset;
UpdateSpineSkeleton(null); UpdateSpineSkeleton(null);
skeleton.UpdateWorldTransform(); skeleton.UpdateWorldTransform(Skeleton.Physics.Update);
} }
/// <summary>Removes the ragdoll instance and effect from the animated skeleton.</summary> /// <summary>Removes the ragdoll instance and effect from the animated skeleton.</summary>
public void Remove () { public void Remove () {
isActive = false; isActive = false;
foreach (Transform t in boneTable.Values) foreach (Transform t in boneTable.Values)
Destroy(t.gameObject); Destroy(t.gameObject);
Destroy(ragdollRoot.gameObject); Destroy(ragdollRoot.gameObject);
boneTable.Clear(); boneTable.Clear();
targetSkeletonComponent.UpdateWorld -= UpdateSpineSkeleton; targetSkeletonComponent.UpdateWorld -= UpdateSpineSkeleton;
} }
public Rigidbody GetRigidbody (string boneName) { public Rigidbody GetRigidbody (string boneName) {
Bone bone = skeleton.FindBone(boneName); Bone bone = skeleton.FindBone(boneName);
return (bone != null && boneTable.ContainsKey(bone)) ? boneTable[bone].GetComponent<Rigidbody>() : null; return (bone != null && boneTable.ContainsKey(bone)) ? boneTable[bone].GetComponent<Rigidbody>() : null;
} }
#endregion #endregion
void RecursivelyCreateBoneProxies (Bone b) { void RecursivelyCreateBoneProxies (Bone b) {
string boneName = b.Data.Name; string boneName = b.Data.Name;
if (stopBoneNames.Contains(boneName)) if (stopBoneNames.Contains(boneName))
return; return;
GameObject boneGameObject = new GameObject(boneName); GameObject boneGameObject = new GameObject(boneName);
boneGameObject.layer = colliderLayer; boneGameObject.layer = colliderLayer;
Transform t = boneGameObject.transform; Transform t = boneGameObject.transform;
boneTable.Add(b, t); boneTable.Add(b, t);
t.parent = transform; t.parent = transform;
t.localPosition = new Vector3(b.WorldX, b.WorldY, 0); t.localPosition = new Vector3(b.WorldX, b.WorldY, 0);
t.localRotation = Quaternion.Euler(0, 0, b.WorldRotationX - b.ShearX); t.localRotation = Quaternion.Euler(0, 0, b.WorldRotationX - b.ShearX);
t.localScale = new Vector3(b.WorldScaleX, b.WorldScaleY, 1); t.localScale = new Vector3(b.WorldScaleX, b.WorldScaleY, 1);
List<Collider> colliders = AttachBoundingBoxRagdollColliders(b); List<Collider> colliders = AttachBoundingBoxRagdollColliders(b);
if (colliders.Count == 0) { if (colliders.Count == 0) {
float length = b.Data.Length; float length = b.Data.Length;
if (length == 0) { if (length == 0) {
SphereCollider ball = boneGameObject.AddComponent<SphereCollider>(); SphereCollider ball = boneGameObject.AddComponent<SphereCollider>();
ball.radius = thickness * 0.5f; ball.radius = thickness * 0.5f;
} else { } else {
BoxCollider box = boneGameObject.AddComponent<BoxCollider>(); BoxCollider box = boneGameObject.AddComponent<BoxCollider>();
box.size = new Vector3(length, thickness, thickness); box.size = new Vector3(length, thickness, thickness);
box.center = new Vector3(length * 0.5f, 0); box.center = new Vector3(length * 0.5f, 0);
} }
} }
Rigidbody rb = boneGameObject.AddComponent<Rigidbody>(); Rigidbody rb = boneGameObject.AddComponent<Rigidbody>();
rb.constraints = RigidbodyConstraints.FreezePositionZ; rb.constraints = RigidbodyConstraints.FreezePositionZ;
foreach (Bone child in b.Children) foreach (Bone child in b.Children)
RecursivelyCreateBoneProxies(child); RecursivelyCreateBoneProxies(child);
} }
void UpdateSpineSkeleton (ISkeletonAnimation skeletonRenderer) { void UpdateSpineSkeleton (ISkeletonAnimation skeletonRenderer) {
bool parentFlipX; bool parentFlipX;
bool parentFlipY; bool parentFlipY;
GetStartBoneParentFlipState(out parentFlipX, out parentFlipY); GetStartBoneParentFlipState(out parentFlipX, out parentFlipY);
foreach (KeyValuePair<Bone, Transform> pair in boneTable) { foreach (KeyValuePair<Bone, Transform> pair in boneTable) {
Bone b = pair.Key; Bone b = pair.Key;
Transform t = pair.Value; Transform t = pair.Value;
bool isStartingBone = b == StartingBone; bool isStartingBone = b == StartingBone;
Bone parentBone = b.Parent; Bone parentBone = b.Parent;
Transform parentTransform = isStartingBone ? ragdollRoot : boneTable[parentBone]; Transform parentTransform = isStartingBone ? ragdollRoot : boneTable[parentBone];
if (!isStartingBone) { if (!isStartingBone) {
BoneFlipEntry parentBoneFlip = boneFlipTable[parentBone]; BoneFlipEntry parentBoneFlip = boneFlipTable[parentBone];
parentFlipX = parentBoneFlip.flipX; parentFlipX = parentBoneFlip.flipX;
parentFlipY = parentBoneFlip.flipY; parentFlipY = parentBoneFlip.flipY;
} }
bool flipX = parentFlipX ^ (b.ScaleX < 0); bool flipX = parentFlipX ^ (b.ScaleX < 0);
bool flipY = parentFlipY ^ (b.ScaleY < 0); bool flipY = parentFlipY ^ (b.ScaleY < 0);
BoneFlipEntry boneFlip; BoneFlipEntry boneFlip;
boneFlipTable.TryGetValue(b, out boneFlip); boneFlipTable.TryGetValue(b, out boneFlip);
boneFlip.flipX = flipX; boneFlip.flipX = flipX;
boneFlip.flipY = flipY; boneFlip.flipY = flipY;
boneFlipTable[b] = boneFlip; boneFlipTable[b] = boneFlip;
bool flipXOR = flipX ^ flipY; bool flipXOR = flipX ^ flipY;
bool parentFlipXOR = parentFlipX ^ parentFlipY; bool parentFlipXOR = parentFlipX ^ parentFlipY;
if (!oldRagdollBehaviour && isStartingBone) { if (!oldRagdollBehaviour && isStartingBone) {
if (b != skeleton.RootBone) { // RagdollRoot is not skeleton root. if (b != skeleton.RootBone) { // RagdollRoot is not skeleton root.
ragdollRoot.localPosition = new Vector3(parentBone.WorldX, parentBone.WorldY, 0); ragdollRoot.localPosition = new Vector3(parentBone.WorldX, parentBone.WorldY, 0);
ragdollRoot.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX); ragdollRoot.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX);
ragdollRoot.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1); ragdollRoot.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1);
} }
} }
Vector3 parentTransformWorldPosition = parentTransform.position; Vector3 parentTransformWorldPosition = parentTransform.position;
Quaternion parentTransformWorldRotation = parentTransform.rotation; Quaternion parentTransformWorldRotation = parentTransform.rotation;
parentSpaceHelper.position = parentTransformWorldPosition; parentSpaceHelper.position = parentTransformWorldPosition;
parentSpaceHelper.rotation = parentTransformWorldRotation; parentSpaceHelper.rotation = parentTransformWorldRotation;
parentSpaceHelper.localScale = parentTransform.lossyScale; parentSpaceHelper.localScale = parentTransform.lossyScale;
if (oldRagdollBehaviour) { if (oldRagdollBehaviour) {
if (isStartingBone && b != skeleton.RootBone) { if (isStartingBone && b != skeleton.RootBone) {
Vector3 localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0); Vector3 localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0);
parentSpaceHelper.position = ragdollRoot.TransformPoint(localPosition); parentSpaceHelper.position = ragdollRoot.TransformPoint(localPosition);
parentSpaceHelper.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX); parentSpaceHelper.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX);
parentSpaceHelper.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1); parentSpaceHelper.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1);
} }
} }
Vector3 boneWorldPosition = t.position; Vector3 boneWorldPosition = t.position;
Vector3 right = parentSpaceHelper.InverseTransformDirection(t.right); Vector3 right = parentSpaceHelper.InverseTransformDirection(t.right);
Vector3 boneLocalPosition = parentSpaceHelper.InverseTransformPoint(boneWorldPosition); Vector3 boneLocalPosition = parentSpaceHelper.InverseTransformPoint(boneWorldPosition);
float boneLocalRotation = Mathf.Atan2(right.y, right.x) * Mathf.Rad2Deg; float boneLocalRotation = Mathf.Atan2(right.y, right.x) * Mathf.Rad2Deg;
if (flipXOR) boneLocalPosition.y *= -1f; if (flipXOR) boneLocalPosition.y *= -1f;
if (parentFlipXOR != flipXOR) boneLocalPosition.y *= -1f; if (parentFlipXOR != flipXOR) boneLocalPosition.y *= -1f;
if (parentFlipXOR) boneLocalRotation *= -1f; if (parentFlipXOR) boneLocalRotation *= -1f;
if (parentFlipX != flipX) boneLocalRotation += 180; if (parentFlipX != flipX) boneLocalRotation += 180;
b.X = Mathf.Lerp(b.X, boneLocalPosition.x, mix); b.X = Mathf.Lerp(b.X, boneLocalPosition.x, mix);
b.Y = Mathf.Lerp(b.Y, boneLocalPosition.y, mix); b.Y = Mathf.Lerp(b.Y, boneLocalPosition.y, mix);
b.Rotation = Mathf.Lerp(b.Rotation, boneLocalRotation, mix); b.Rotation = Mathf.Lerp(b.Rotation, boneLocalRotation, mix);
//b.AppliedRotation = Mathf.Lerp(b.AppliedRotation, boneLocalRotation, mix); //b.AppliedRotation = Mathf.Lerp(b.AppliedRotation, boneLocalRotation, mix);
} }
} }
void GetStartBoneParentFlipState (out bool parentFlipX, out bool parentFlipY) { void GetStartBoneParentFlipState (out bool parentFlipX, out bool parentFlipY) {
parentFlipX = skeleton.ScaleX < 0; parentFlipX = skeleton.ScaleX < 0;
parentFlipY = skeleton.ScaleY < 0; parentFlipY = skeleton.ScaleY < 0;
Bone parent = this.StartingBone == null ? null : this.StartingBone.Parent; Bone parent = this.StartingBone == null ? null : this.StartingBone.Parent;
while (parent != null) { while (parent != null) {
parentFlipX ^= parent.ScaleX < 0; parentFlipX ^= parent.ScaleX < 0;
parentFlipY ^= parent.ScaleY < 0; parentFlipY ^= parent.ScaleY < 0;
parent = parent.Parent; parent = parent.Parent;
} }
} }
List<Collider> AttachBoundingBoxRagdollColliders (Bone b) { List<Collider> AttachBoundingBoxRagdollColliders (Bone b) {
const string AttachmentNameMarker = "ragdoll"; const string AttachmentNameMarker = "ragdoll";
List<Collider> colliders = new List<Collider>(); List<Collider> colliders = new List<Collider>();
Transform t = boneTable[b]; Transform t = boneTable[b];
GameObject go = t.gameObject; GameObject go = t.gameObject;
Skin skin = skeleton.Skin ?? skeleton.Data.DefaultSkin; Skin skin = skeleton.Skin ?? skeleton.Data.DefaultSkin;
List<Skin.SkinEntry> skinEntries = new List<Skin.SkinEntry>(); List<Skin.SkinEntry> skinEntries = new List<Skin.SkinEntry>();
foreach (Slot s in skeleton.Slots) { foreach (Slot s in skeleton.Slots) {
if (s.Bone == b) { if (s.Bone == b) {
skin.GetAttachments(skeleton.Slots.IndexOf(s), skinEntries); skin.GetAttachments(skeleton.Slots.IndexOf(s), skinEntries);
foreach (Skin.SkinEntry entry in skinEntries) { foreach (Skin.SkinEntry entry in skinEntries) {
BoundingBoxAttachment bbAttachment = entry.Attachment as BoundingBoxAttachment; BoundingBoxAttachment bbAttachment = entry.Attachment as BoundingBoxAttachment;
if (bbAttachment != null) { if (bbAttachment != null) {
if (!entry.Name.ToLower().Contains(AttachmentNameMarker)) if (!entry.Name.ToLower().Contains(AttachmentNameMarker))
continue; continue;
BoxCollider bbCollider = go.AddComponent<BoxCollider>(); BoxCollider bbCollider = go.AddComponent<BoxCollider>();
Bounds bounds = SkeletonUtility.GetBoundingBoxBounds(bbAttachment, thickness); Bounds bounds = SkeletonUtility.GetBoundingBoxBounds(bbAttachment, thickness);
bbCollider.center = bounds.center; bbCollider.center = bounds.center;
bbCollider.size = bounds.size; bbCollider.size = bounds.size;
colliders.Add(bbCollider); colliders.Add(bbCollider);
} }
} }
} }
} }
return colliders; return colliders;
} }
public class LayerFieldAttribute : PropertyAttribute { } public class LayerFieldAttribute : PropertyAttribute { }
} }
} }

View File

@ -1,472 +1,472 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
// Contributed by: Mitch Thompson // Contributed by: Mitch Thompson
#if UNITY_2019_2 || UNITY_2019_3 || UNITY_2019_4 || UNITY_2020_1 || UNITY_2020_2 // note: 2020.3+ uses old bahavior again #if UNITY_2019_2 || UNITY_2019_3 || UNITY_2019_4 || UNITY_2020_1 || UNITY_2020_2 // note: 2020.3+ uses old bahavior again
#define HINGE_JOINT_2019_BEHAVIOUR #define HINGE_JOINT_2019_BEHAVIOUR
#endif #endif
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
[RequireComponent(typeof(SkeletonRenderer))] [RequireComponent(typeof(SkeletonRenderer))]
public class SkeletonRagdoll2D : MonoBehaviour { public class SkeletonRagdoll2D : MonoBehaviour {
static Transform parentSpaceHelper; static Transform parentSpaceHelper;
#region Inspector #region Inspector
[Header("Hierarchy")] [Header("Hierarchy")]
[SpineBone] [SpineBone]
public string startingBoneName = ""; public string startingBoneName = "";
[SpineBone] [SpineBone]
public List<string> stopBoneNames = new List<string>(); public List<string> stopBoneNames = new List<string>();
[Header("Parameters")] [Header("Parameters")]
public bool applyOnStart; public bool applyOnStart;
[Tooltip("Warning! You will have to re-enable and tune mix values manually if attempting to remove the ragdoll system.")] [Tooltip("Warning! You will have to re-enable and tune mix values manually if attempting to remove the ragdoll system.")]
public bool disableIK = true; public bool disableIK = true;
public bool disableOtherConstraints = false; public bool disableOtherConstraints = false;
[Space] [Space]
[Tooltip("Set RootRigidbody IsKinematic to true when Apply is called.")] [Tooltip("Set RootRigidbody IsKinematic to true when Apply is called.")]
public bool pinStartBone; public bool pinStartBone;
public float gravityScale = 1; public float gravityScale = 1;
[Tooltip("If no BoundingBox Attachment is attached to a bone, this becomes the default Width or Radius of a Bone's ragdoll Rigidbody")] [Tooltip("If no BoundingBox Attachment is attached to a bone, this becomes the default Width or Radius of a Bone's ragdoll Rigidbody")]
public float thickness = 0.125f; public float thickness = 0.125f;
[Tooltip("Default rotational limit value. Min is negative this value, Max is this value.")] [Tooltip("Default rotational limit value. Min is negative this value, Max is this value.")]
public float rotationLimit = 20; public float rotationLimit = 20;
public float rootMass = 20; public float rootMass = 20;
[Tooltip("If your ragdoll seems unstable or uneffected by limits, try lowering this value.")] [Tooltip("If your ragdoll seems unstable or uneffected by limits, try lowering this value.")]
[Range(0.01f, 1f)] [Range(0.01f, 1f)]
public float massFalloffFactor = 0.4f; public float massFalloffFactor = 0.4f;
[Tooltip("The layer assigned to all of the rigidbody parts.")] [Tooltip("The layer assigned to all of the rigidbody parts.")]
[SkeletonRagdoll.LayerField] [SkeletonRagdoll.LayerField]
public int colliderLayer = 0; public int colliderLayer = 0;
[Range(0, 1)] [Range(0, 1)]
public float mix = 1; public float mix = 1;
public bool oldRagdollBehaviour = false; public bool oldRagdollBehaviour = false;
#endregion #endregion
ISkeletonAnimation targetSkeletonComponent; ISkeletonAnimation targetSkeletonComponent;
Skeleton skeleton; Skeleton skeleton;
struct BoneFlipEntry { struct BoneFlipEntry {
public BoneFlipEntry (bool flipX, bool flipY) { public BoneFlipEntry (bool flipX, bool flipY) {
this.flipX = flipX; this.flipX = flipX;
this.flipY = flipY; this.flipY = flipY;
} }
public bool flipX; public bool flipX;
public bool flipY; public bool flipY;
} }
Dictionary<Bone, Transform> boneTable = new Dictionary<Bone, Transform>(); Dictionary<Bone, Transform> boneTable = new Dictionary<Bone, Transform>();
Dictionary<Bone, BoneFlipEntry> boneFlipTable = new Dictionary<Bone, BoneFlipEntry>(); Dictionary<Bone, BoneFlipEntry> boneFlipTable = new Dictionary<Bone, BoneFlipEntry>();
Transform ragdollRoot; Transform ragdollRoot;
public Rigidbody2D RootRigidbody { get; private set; } public Rigidbody2D RootRigidbody { get; private set; }
public Bone StartingBone { get; private set; } public Bone StartingBone { get; private set; }
Vector2 rootOffset; Vector2 rootOffset;
public Vector3 RootOffset { get { return this.rootOffset; } } public Vector3 RootOffset { get { return this.rootOffset; } }
bool isActive; bool isActive;
public bool IsActive { get { return this.isActive; } } public bool IsActive { get { return this.isActive; } }
IEnumerator Start () { IEnumerator Start () {
if (parentSpaceHelper == null) { if (parentSpaceHelper == null) {
parentSpaceHelper = (new GameObject("Parent Space Helper")).transform; parentSpaceHelper = (new GameObject("Parent Space Helper")).transform;
} }
targetSkeletonComponent = GetComponent<SkeletonRenderer>() as ISkeletonAnimation; targetSkeletonComponent = GetComponent<SkeletonRenderer>() as ISkeletonAnimation;
if (targetSkeletonComponent == null) Debug.LogError("Attached Spine component does not implement ISkeletonAnimation. This script is not compatible."); if (targetSkeletonComponent == null) Debug.LogError("Attached Spine component does not implement ISkeletonAnimation. This script is not compatible.");
skeleton = targetSkeletonComponent.Skeleton; skeleton = targetSkeletonComponent.Skeleton;
if (applyOnStart) { if (applyOnStart) {
yield return null; yield return null;
Apply(); Apply();
} }
} }
#region API #region API
public Rigidbody2D[] RigidbodyArray { public Rigidbody2D[] RigidbodyArray {
get { get {
if (!isActive) if (!isActive)
return new Rigidbody2D[0]; return new Rigidbody2D[0];
Rigidbody2D[] rigidBodies = new Rigidbody2D[boneTable.Count]; Rigidbody2D[] rigidBodies = new Rigidbody2D[boneTable.Count];
int i = 0; int i = 0;
foreach (Transform t in boneTable.Values) { foreach (Transform t in boneTable.Values) {
rigidBodies[i] = t.GetComponent<Rigidbody2D>(); rigidBodies[i] = t.GetComponent<Rigidbody2D>();
i++; i++;
} }
return rigidBodies; return rigidBodies;
} }
} }
public Vector3 EstimatedSkeletonPosition { public Vector3 EstimatedSkeletonPosition {
get { return this.RootRigidbody.position - rootOffset; } get { return this.RootRigidbody.position - rootOffset; }
} }
/// <summary>Instantiates the ragdoll simulation and applies its transforms to the skeleton.</summary> /// <summary>Instantiates the ragdoll simulation and applies its transforms to the skeleton.</summary>
public void Apply () { public void Apply () {
isActive = true; isActive = true;
mix = 1; mix = 1;
Bone startingBone = this.StartingBone = skeleton.FindBone(startingBoneName); Bone startingBone = this.StartingBone = skeleton.FindBone(startingBoneName);
RecursivelyCreateBoneProxies(startingBone); RecursivelyCreateBoneProxies(startingBone);
RootRigidbody = boneTable[startingBone].GetComponent<Rigidbody2D>(); RootRigidbody = boneTable[startingBone].GetComponent<Rigidbody2D>();
RootRigidbody.isKinematic = pinStartBone; RootRigidbody.isKinematic = pinStartBone;
RootRigidbody.mass = rootMass; RootRigidbody.mass = rootMass;
List<Collider2D> boneColliders = new List<Collider2D>(); List<Collider2D> boneColliders = new List<Collider2D>();
foreach (KeyValuePair<Bone, Transform> pair in boneTable) { foreach (KeyValuePair<Bone, Transform> pair in boneTable) {
Bone b = pair.Key; Bone b = pair.Key;
Transform t = pair.Value; Transform t = pair.Value;
Transform parentTransform; Transform parentTransform;
boneColliders.Add(t.GetComponent<Collider2D>()); boneColliders.Add(t.GetComponent<Collider2D>());
if (b == startingBone) { if (b == startingBone) {
ragdollRoot = new GameObject("RagdollRoot").transform; ragdollRoot = new GameObject("RagdollRoot").transform;
ragdollRoot.SetParent(transform, false); ragdollRoot.SetParent(transform, false);
if (b == skeleton.RootBone) { // RagdollRoot is skeleton root's parent, thus the skeleton's scale and position. if (b == skeleton.RootBone) { // RagdollRoot is skeleton root's parent, thus the skeleton's scale and position.
ragdollRoot.localPosition = new Vector3(skeleton.X, skeleton.Y, 0); ragdollRoot.localPosition = new Vector3(skeleton.X, skeleton.Y, 0);
ragdollRoot.localRotation = (skeleton.ScaleX < 0) ? Quaternion.Euler(0, 0, 180.0f) : Quaternion.identity; ragdollRoot.localRotation = (skeleton.ScaleX < 0) ? Quaternion.Euler(0, 0, 180.0f) : Quaternion.identity;
} else { } else {
ragdollRoot.localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0); ragdollRoot.localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0);
ragdollRoot.localRotation = Quaternion.Euler(0, 0, b.Parent.WorldRotationX - b.Parent.ShearX); ragdollRoot.localRotation = Quaternion.Euler(0, 0, b.Parent.WorldRotationX - b.Parent.ShearX);
} }
parentTransform = ragdollRoot; parentTransform = ragdollRoot;
rootOffset = t.position - transform.position; rootOffset = t.position - transform.position;
} else { } else {
parentTransform = boneTable[b.Parent]; parentTransform = boneTable[b.Parent];
} }
// Add joint and attach to parent. // Add joint and attach to parent.
Rigidbody2D rbParent = parentTransform.GetComponent<Rigidbody2D>(); Rigidbody2D rbParent = parentTransform.GetComponent<Rigidbody2D>();
if (rbParent != null) { if (rbParent != null) {
HingeJoint2D joint = t.gameObject.AddComponent<HingeJoint2D>(); HingeJoint2D joint = t.gameObject.AddComponent<HingeJoint2D>();
joint.connectedBody = rbParent; joint.connectedBody = rbParent;
Vector3 localPos = parentTransform.InverseTransformPoint(t.position); Vector3 localPos = parentTransform.InverseTransformPoint(t.position);
joint.connectedAnchor = localPos; joint.connectedAnchor = localPos;
joint.GetComponent<Rigidbody2D>().mass = joint.connectedBody.mass * massFalloffFactor; joint.GetComponent<Rigidbody2D>().mass = joint.connectedBody.mass * massFalloffFactor;
#if HINGE_JOINT_2019_BEHAVIOUR #if HINGE_JOINT_2019_BEHAVIOUR
float referenceAngle = (rbParent.transform.eulerAngles.z - t.eulerAngles.z + 360f) % 360f; float referenceAngle = (rbParent.transform.eulerAngles.z - t.eulerAngles.z + 360f) % 360f;
float minAngle = referenceAngle - rotationLimit; float minAngle = referenceAngle - rotationLimit;
float maxAngle = referenceAngle + rotationLimit; float maxAngle = referenceAngle + rotationLimit;
if (maxAngle > 180f) { if (maxAngle > 180f) {
minAngle -= 360f; minAngle -= 360f;
maxAngle -= 360f; maxAngle -= 360f;
} }
#else #else
float minAngle = -rotationLimit; float minAngle = -rotationLimit;
float maxAngle = rotationLimit; float maxAngle = rotationLimit;
#endif #endif
joint.limits = new JointAngleLimits2D { joint.limits = new JointAngleLimits2D {
min = minAngle, min = minAngle,
max = maxAngle max = maxAngle
}; };
joint.useLimits = true; joint.useLimits = true;
} }
} }
// Ignore collisions among bones. // Ignore collisions among bones.
for (int x = 0; x < boneColliders.Count; x++) { for (int x = 0; x < boneColliders.Count; x++) {
for (int y = 0; y < boneColliders.Count; y++) { for (int y = 0; y < boneColliders.Count; y++) {
if (x == y) continue; if (x == y) continue;
Physics2D.IgnoreCollision(boneColliders[x], boneColliders[y]); Physics2D.IgnoreCollision(boneColliders[x], boneColliders[y]);
} }
} }
// Destroy existing override-mode SkeletonUtility bones. // Destroy existing override-mode SkeletonUtility bones.
SkeletonUtilityBone[] utilityBones = GetComponentsInChildren<SkeletonUtilityBone>(); SkeletonUtilityBone[] utilityBones = GetComponentsInChildren<SkeletonUtilityBone>();
if (utilityBones.Length > 0) { if (utilityBones.Length > 0) {
List<string> destroyedUtilityBoneNames = new List<string>(); List<string> destroyedUtilityBoneNames = new List<string>();
foreach (SkeletonUtilityBone ub in utilityBones) { foreach (SkeletonUtilityBone ub in utilityBones) {
if (ub.mode == SkeletonUtilityBone.Mode.Override) { if (ub.mode == SkeletonUtilityBone.Mode.Override) {
destroyedUtilityBoneNames.Add(ub.gameObject.name); destroyedUtilityBoneNames.Add(ub.gameObject.name);
Destroy(ub.gameObject); Destroy(ub.gameObject);
} }
} }
if (destroyedUtilityBoneNames.Count > 0) { if (destroyedUtilityBoneNames.Count > 0) {
string msg = "Destroyed Utility Bones: "; string msg = "Destroyed Utility Bones: ";
for (int i = 0; i < destroyedUtilityBoneNames.Count; i++) { for (int i = 0; i < destroyedUtilityBoneNames.Count; i++) {
msg += destroyedUtilityBoneNames[i]; msg += destroyedUtilityBoneNames[i];
if (i != destroyedUtilityBoneNames.Count - 1) { if (i != destroyedUtilityBoneNames.Count - 1) {
msg += ","; msg += ",";
} }
} }
Debug.LogWarning(msg); Debug.LogWarning(msg);
} }
} }
// Disable skeleton constraints. // Disable skeleton constraints.
if (disableIK) { if (disableIK) {
ExposedList<IkConstraint> ikConstraints = skeleton.IkConstraints; ExposedList<IkConstraint> ikConstraints = skeleton.IkConstraints;
for (int i = 0, n = ikConstraints.Count; i < n; i++) for (int i = 0, n = ikConstraints.Count; i < n; i++)
ikConstraints.Items[i].Mix = 0; ikConstraints.Items[i].Mix = 0;
} }
if (disableOtherConstraints) { if (disableOtherConstraints) {
ExposedList<TransformConstraint> transformConstraints = skeleton.TransformConstraints; ExposedList<TransformConstraint> transformConstraints = skeleton.TransformConstraints;
for (int i = 0, n = transformConstraints.Count; i < n; i++) { for (int i = 0, n = transformConstraints.Count; i < n; i++) {
transformConstraints.Items[i].MixRotate = 0; transformConstraints.Items[i].MixRotate = 0;
transformConstraints.Items[i].MixScaleX = 0; transformConstraints.Items[i].MixScaleX = 0;
transformConstraints.Items[i].MixScaleY = 0; transformConstraints.Items[i].MixScaleY = 0;
transformConstraints.Items[i].MixShearY = 0; transformConstraints.Items[i].MixShearY = 0;
transformConstraints.Items[i].MixX = 0; transformConstraints.Items[i].MixX = 0;
transformConstraints.Items[i].MixY = 0; transformConstraints.Items[i].MixY = 0;
} }
ExposedList<PathConstraint> pathConstraints = skeleton.PathConstraints; ExposedList<PathConstraint> pathConstraints = skeleton.PathConstraints;
for (int i = 0, n = pathConstraints.Count; i < n; i++) { for (int i = 0, n = pathConstraints.Count; i < n; i++) {
pathConstraints.Items[i].MixRotate = 0; pathConstraints.Items[i].MixRotate = 0;
pathConstraints.Items[i].MixX = 0; pathConstraints.Items[i].MixX = 0;
pathConstraints.Items[i].MixY = 0; pathConstraints.Items[i].MixY = 0;
} }
} }
targetSkeletonComponent.UpdateWorld += UpdateSpineSkeleton; targetSkeletonComponent.UpdateWorld += UpdateSpineSkeleton;
} }
/// <summary>Transitions the mix value from the current value to a target value.</summary> /// <summary>Transitions the mix value from the current value to a target value.</summary>
public Coroutine SmoothMix (float target, float duration) { public Coroutine SmoothMix (float target, float duration) {
return StartCoroutine(SmoothMixCoroutine(target, duration)); return StartCoroutine(SmoothMixCoroutine(target, duration));
} }
IEnumerator SmoothMixCoroutine (float target, float duration) { IEnumerator SmoothMixCoroutine (float target, float duration) {
float startTime = Time.time; float startTime = Time.time;
float startMix = mix; float startMix = mix;
while (mix > 0) { while (mix > 0) {
skeleton.SetBonesToSetupPose(); skeleton.SetBonesToSetupPose();
mix = Mathf.SmoothStep(startMix, target, (Time.time - startTime) / duration); mix = Mathf.SmoothStep(startMix, target, (Time.time - startTime) / duration);
yield return null; yield return null;
} }
} }
/// <summary>Set the transform world position while preserving the ragdoll parts world position.</summary> /// <summary>Set the transform world position while preserving the ragdoll parts world position.</summary>
public void SetSkeletonPosition (Vector3 worldPosition) { public void SetSkeletonPosition (Vector3 worldPosition) {
if (!isActive) { if (!isActive) {
Debug.LogWarning("Can't call SetSkeletonPosition while Ragdoll is not active!"); Debug.LogWarning("Can't call SetSkeletonPosition while Ragdoll is not active!");
return; return;
} }
Vector3 offset = worldPosition - transform.position; Vector3 offset = worldPosition - transform.position;
transform.position = worldPosition; transform.position = worldPosition;
foreach (Transform t in boneTable.Values) foreach (Transform t in boneTable.Values)
t.position -= offset; t.position -= offset;
UpdateSpineSkeleton(null); UpdateSpineSkeleton(null);
skeleton.UpdateWorldTransform(); skeleton.UpdateWorldTransform(Skeleton.Physics.Update);
} }
/// <summary>Removes the ragdoll instance and effect from the animated skeleton.</summary> /// <summary>Removes the ragdoll instance and effect from the animated skeleton.</summary>
public void Remove () { public void Remove () {
isActive = false; isActive = false;
foreach (Transform t in boneTable.Values) foreach (Transform t in boneTable.Values)
Destroy(t.gameObject); Destroy(t.gameObject);
Destroy(ragdollRoot.gameObject); Destroy(ragdollRoot.gameObject);
boneTable.Clear(); boneTable.Clear();
targetSkeletonComponent.UpdateWorld -= UpdateSpineSkeleton; targetSkeletonComponent.UpdateWorld -= UpdateSpineSkeleton;
} }
public Rigidbody2D GetRigidbody (string boneName) { public Rigidbody2D GetRigidbody (string boneName) {
Bone bone = skeleton.FindBone(boneName); Bone bone = skeleton.FindBone(boneName);
return (bone != null && boneTable.ContainsKey(bone)) ? boneTable[bone].GetComponent<Rigidbody2D>() : null; return (bone != null && boneTable.ContainsKey(bone)) ? boneTable[bone].GetComponent<Rigidbody2D>() : null;
} }
#endregion #endregion
/// <summary>Generates the ragdoll simulation's Transform and joint setup.</summary> /// <summary>Generates the ragdoll simulation's Transform and joint setup.</summary>
void RecursivelyCreateBoneProxies (Bone b) { void RecursivelyCreateBoneProxies (Bone b) {
string boneName = b.Data.Name; string boneName = b.Data.Name;
if (stopBoneNames.Contains(boneName)) if (stopBoneNames.Contains(boneName))
return; return;
GameObject boneGameObject = new GameObject(boneName); GameObject boneGameObject = new GameObject(boneName);
boneGameObject.layer = this.colliderLayer; boneGameObject.layer = this.colliderLayer;
Transform t = boneGameObject.transform; Transform t = boneGameObject.transform;
boneTable.Add(b, t); boneTable.Add(b, t);
t.parent = transform; t.parent = transform;
t.localPosition = new Vector3(b.WorldX, b.WorldY, 0); t.localPosition = new Vector3(b.WorldX, b.WorldY, 0);
t.localRotation = Quaternion.Euler(0, 0, b.WorldRotationX - b.ShearX); t.localRotation = Quaternion.Euler(0, 0, b.WorldRotationX - b.ShearX);
t.localScale = new Vector3(b.WorldScaleX, b.WorldScaleY, 1); t.localScale = new Vector3(b.WorldScaleX, b.WorldScaleY, 1);
List<Collider2D> colliders = AttachBoundingBoxRagdollColliders(b, boneGameObject, skeleton, this.gravityScale); List<Collider2D> colliders = AttachBoundingBoxRagdollColliders(b, boneGameObject, skeleton, this.gravityScale);
if (colliders.Count == 0) { if (colliders.Count == 0) {
float length = b.Data.Length; float length = b.Data.Length;
if (length == 0) { if (length == 0) {
CircleCollider2D circle = boneGameObject.AddComponent<CircleCollider2D>(); CircleCollider2D circle = boneGameObject.AddComponent<CircleCollider2D>();
circle.radius = thickness * 0.5f; circle.radius = thickness * 0.5f;
} else { } else {
BoxCollider2D box = boneGameObject.AddComponent<BoxCollider2D>(); BoxCollider2D box = boneGameObject.AddComponent<BoxCollider2D>();
box.size = new Vector2(length, thickness); box.size = new Vector2(length, thickness);
box.offset = new Vector2(length * 0.5f, 0); // box.center in UNITY_4 box.offset = new Vector2(length * 0.5f, 0); // box.center in UNITY_4
} }
} }
Rigidbody2D rb = boneGameObject.GetComponent<Rigidbody2D>(); Rigidbody2D rb = boneGameObject.GetComponent<Rigidbody2D>();
if (rb == null) rb = boneGameObject.AddComponent<Rigidbody2D>(); if (rb == null) rb = boneGameObject.AddComponent<Rigidbody2D>();
rb.gravityScale = this.gravityScale; rb.gravityScale = this.gravityScale;
foreach (Bone child in b.Children) foreach (Bone child in b.Children)
RecursivelyCreateBoneProxies(child); RecursivelyCreateBoneProxies(child);
} }
/// <summary>Performed every skeleton animation update to translate Unity Transforms positions into Spine bone transforms.</summary> /// <summary>Performed every skeleton animation update to translate Unity Transforms positions into Spine bone transforms.</summary>
void UpdateSpineSkeleton (ISkeletonAnimation animatedSkeleton) { void UpdateSpineSkeleton (ISkeletonAnimation animatedSkeleton) {
bool parentFlipX; bool parentFlipX;
bool parentFlipY; bool parentFlipY;
Bone startingBone = this.StartingBone; Bone startingBone = this.StartingBone;
GetStartBoneParentFlipState(out parentFlipX, out parentFlipY); GetStartBoneParentFlipState(out parentFlipX, out parentFlipY);
foreach (KeyValuePair<Bone, Transform> pair in boneTable) { foreach (KeyValuePair<Bone, Transform> pair in boneTable) {
Bone b = pair.Key; Bone b = pair.Key;
Transform t = pair.Value; Transform t = pair.Value;
bool isStartingBone = (b == startingBone); bool isStartingBone = (b == startingBone);
Bone parentBone = b.Parent; Bone parentBone = b.Parent;
Transform parentTransform = isStartingBone ? ragdollRoot : boneTable[parentBone]; Transform parentTransform = isStartingBone ? ragdollRoot : boneTable[parentBone];
if (!isStartingBone) { if (!isStartingBone) {
BoneFlipEntry parentBoneFlip = boneFlipTable[parentBone]; BoneFlipEntry parentBoneFlip = boneFlipTable[parentBone];
parentFlipX = parentBoneFlip.flipX; parentFlipX = parentBoneFlip.flipX;
parentFlipY = parentBoneFlip.flipY; parentFlipY = parentBoneFlip.flipY;
} }
bool flipX = parentFlipX ^ (b.ScaleX < 0); bool flipX = parentFlipX ^ (b.ScaleX < 0);
bool flipY = parentFlipY ^ (b.ScaleY < 0); bool flipY = parentFlipY ^ (b.ScaleY < 0);
BoneFlipEntry boneFlip; BoneFlipEntry boneFlip;
boneFlipTable.TryGetValue(b, out boneFlip); boneFlipTable.TryGetValue(b, out boneFlip);
boneFlip.flipX = flipX; boneFlip.flipX = flipX;
boneFlip.flipY = flipY; boneFlip.flipY = flipY;
boneFlipTable[b] = boneFlip; boneFlipTable[b] = boneFlip;
bool flipXOR = flipX ^ flipY; bool flipXOR = flipX ^ flipY;
bool parentFlipXOR = parentFlipX ^ parentFlipY; bool parentFlipXOR = parentFlipX ^ parentFlipY;
if (!oldRagdollBehaviour && isStartingBone) { if (!oldRagdollBehaviour && isStartingBone) {
if (b != skeleton.RootBone) { // RagdollRoot is not skeleton root. if (b != skeleton.RootBone) { // RagdollRoot is not skeleton root.
ragdollRoot.localPosition = new Vector3(parentBone.WorldX, parentBone.WorldY, 0); ragdollRoot.localPosition = new Vector3(parentBone.WorldX, parentBone.WorldY, 0);
ragdollRoot.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX); ragdollRoot.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX);
ragdollRoot.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1); ragdollRoot.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1);
} }
} }
Vector3 parentTransformWorldPosition = parentTransform.position; Vector3 parentTransformWorldPosition = parentTransform.position;
Quaternion parentTransformWorldRotation = parentTransform.rotation; Quaternion parentTransformWorldRotation = parentTransform.rotation;
parentSpaceHelper.position = parentTransformWorldPosition; parentSpaceHelper.position = parentTransformWorldPosition;
parentSpaceHelper.rotation = parentTransformWorldRotation; parentSpaceHelper.rotation = parentTransformWorldRotation;
parentSpaceHelper.localScale = parentTransform.lossyScale; parentSpaceHelper.localScale = parentTransform.lossyScale;
if (oldRagdollBehaviour) { if (oldRagdollBehaviour) {
if (isStartingBone && b != skeleton.RootBone) { if (isStartingBone && b != skeleton.RootBone) {
Vector3 localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0); Vector3 localPosition = new Vector3(b.Parent.WorldX, b.Parent.WorldY, 0);
parentSpaceHelper.position = ragdollRoot.TransformPoint(localPosition); parentSpaceHelper.position = ragdollRoot.TransformPoint(localPosition);
parentSpaceHelper.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX); parentSpaceHelper.localRotation = Quaternion.Euler(0, 0, parentBone.WorldRotationX - parentBone.ShearX);
parentSpaceHelper.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1); parentSpaceHelper.localScale = new Vector3(parentBone.WorldScaleX, parentBone.WorldScaleY, 1);
} }
} }
Vector3 boneWorldPosition = t.position; Vector3 boneWorldPosition = t.position;
Vector3 right = parentSpaceHelper.InverseTransformDirection(t.right); Vector3 right = parentSpaceHelper.InverseTransformDirection(t.right);
Vector3 boneLocalPosition = parentSpaceHelper.InverseTransformPoint(boneWorldPosition); Vector3 boneLocalPosition = parentSpaceHelper.InverseTransformPoint(boneWorldPosition);
float boneLocalRotation = Mathf.Atan2(right.y, right.x) * Mathf.Rad2Deg; float boneLocalRotation = Mathf.Atan2(right.y, right.x) * Mathf.Rad2Deg;
if (flipXOR) boneLocalPosition.y *= -1f; if (flipXOR) boneLocalPosition.y *= -1f;
if (parentFlipXOR != flipXOR) boneLocalPosition.y *= -1f; if (parentFlipXOR != flipXOR) boneLocalPosition.y *= -1f;
if (parentFlipXOR) boneLocalRotation *= -1f; if (parentFlipXOR) boneLocalRotation *= -1f;
if (parentFlipX != flipX) boneLocalRotation += 180; if (parentFlipX != flipX) boneLocalRotation += 180;
b.X = Mathf.Lerp(b.X, boneLocalPosition.x, mix); b.X = Mathf.Lerp(b.X, boneLocalPosition.x, mix);
b.Y = Mathf.Lerp(b.Y, boneLocalPosition.y, mix); b.Y = Mathf.Lerp(b.Y, boneLocalPosition.y, mix);
b.Rotation = Mathf.Lerp(b.Rotation, boneLocalRotation, mix); b.Rotation = Mathf.Lerp(b.Rotation, boneLocalRotation, mix);
//b.AppliedRotation = Mathf.Lerp(b.AppliedRotation, boneLocalRotation, mix); //b.AppliedRotation = Mathf.Lerp(b.AppliedRotation, boneLocalRotation, mix);
} }
} }
void GetStartBoneParentFlipState (out bool parentFlipX, out bool parentFlipY) { void GetStartBoneParentFlipState (out bool parentFlipX, out bool parentFlipY) {
parentFlipX = skeleton.ScaleX < 0; parentFlipX = skeleton.ScaleX < 0;
parentFlipY = skeleton.ScaleY < 0; parentFlipY = skeleton.ScaleY < 0;
Bone parent = this.StartingBone == null ? null : this.StartingBone.Parent; Bone parent = this.StartingBone == null ? null : this.StartingBone.Parent;
while (parent != null) { while (parent != null) {
parentFlipX ^= parent.ScaleX < 0; parentFlipX ^= parent.ScaleX < 0;
parentFlipY ^= parent.ScaleY < 0; parentFlipY ^= parent.ScaleY < 0;
parent = parent.Parent; parent = parent.Parent;
} }
} }
static List<Collider2D> AttachBoundingBoxRagdollColliders (Bone b, GameObject go, Skeleton skeleton, float gravityScale) { static List<Collider2D> AttachBoundingBoxRagdollColliders (Bone b, GameObject go, Skeleton skeleton, float gravityScale) {
const string AttachmentNameMarker = "ragdoll"; const string AttachmentNameMarker = "ragdoll";
List<Collider2D> colliders = new List<Collider2D>(); List<Collider2D> colliders = new List<Collider2D>();
Skin skin = skeleton.Skin ?? skeleton.Data.DefaultSkin; Skin skin = skeleton.Skin ?? skeleton.Data.DefaultSkin;
List<Skin.SkinEntry> skinEntries = new List<Skin.SkinEntry>(); List<Skin.SkinEntry> skinEntries = new List<Skin.SkinEntry>();
foreach (Slot slot in skeleton.Slots) { foreach (Slot slot in skeleton.Slots) {
if (slot.Bone == b) { if (slot.Bone == b) {
skin.GetAttachments(skeleton.Slots.IndexOf(slot), skinEntries); skin.GetAttachments(skeleton.Slots.IndexOf(slot), skinEntries);
bool bbAttachmentAdded = false; bool bbAttachmentAdded = false;
foreach (Skin.SkinEntry entry in skinEntries) { foreach (Skin.SkinEntry entry in skinEntries) {
BoundingBoxAttachment bbAttachment = entry.Attachment as BoundingBoxAttachment; BoundingBoxAttachment bbAttachment = entry.Attachment as BoundingBoxAttachment;
if (bbAttachment != null) { if (bbAttachment != null) {
if (!entry.Name.ToLower().Contains(AttachmentNameMarker)) if (!entry.Name.ToLower().Contains(AttachmentNameMarker))
continue; continue;
bbAttachmentAdded = true; bbAttachmentAdded = true;
PolygonCollider2D bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(bbAttachment, slot, go, isTrigger: false); PolygonCollider2D bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(bbAttachment, slot, go, isTrigger: false);
colliders.Add(bbCollider); colliders.Add(bbCollider);
} }
} }
if (bbAttachmentAdded) if (bbAttachmentAdded)
SkeletonUtility.AddBoneRigidbody2D(go, isKinematic: false, gravityScale: gravityScale); SkeletonUtility.AddBoneRigidbody2D(go, isKinematic: false, gravityScale: gravityScale);
} }
} }
return colliders; return colliders;
} }
static Vector3 FlipScale (bool flipX, bool flipY) { static Vector3 FlipScale (bool flipX, bool flipY) {
return new Vector3(flipX ? -1f : 1f, flipY ? -1f : 1f, 1f); return new Vector3(flipX ? -1f : 1f, flipY ? -1f : 1f, 1f);
} }
#if UNITY_EDITOR #if UNITY_EDITOR
void OnDrawGizmosSelected () { void OnDrawGizmosSelected () {
if (isActive) { if (isActive) {
Gizmos.DrawWireSphere(transform.position, thickness * 1.2f); Gizmos.DrawWireSphere(transform.position, thickness * 1.2f);
Vector3 newTransformPos = RootRigidbody.position - rootOffset; Vector3 newTransformPos = RootRigidbody.position - rootOffset;
Gizmos.DrawLine(transform.position, newTransformPos); Gizmos.DrawLine(transform.position, newTransformPos);
Gizmos.DrawWireSphere(newTransformPos, thickness * 1.2f); Gizmos.DrawWireSphere(newTransformPos, thickness * 1.2f);
} }
} }
#endif #endif
} }
} }

View File

@ -1,84 +1,84 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System.Collections; using System.Collections;
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
public class SkeletonUtilityEyeConstraint : SkeletonUtilityConstraint { public class SkeletonUtilityEyeConstraint : SkeletonUtilityConstraint {
public Transform[] eyes; public Transform[] eyes;
public float radius = 0.5f; public float radius = 0.5f;
public Transform target; public Transform target;
public Vector3 targetPosition; public Vector3 targetPosition;
public float speed = 10; public float speed = 10;
Vector3[] origins; Vector3[] origins;
Vector3 centerPoint; Vector3 centerPoint;
protected override void OnEnable () { protected override void OnEnable () {
if (!Application.isPlaying) return; if (!Application.isPlaying) return;
base.OnEnable(); base.OnEnable();
Bounds centerBounds = new Bounds(eyes[0].localPosition, Vector3.zero); Bounds centerBounds = new Bounds(eyes[0].localPosition, Vector3.zero);
origins = new Vector3[eyes.Length]; origins = new Vector3[eyes.Length];
for (int i = 0; i < eyes.Length; i++) { for (int i = 0; i < eyes.Length; i++) {
origins[i] = eyes[i].localPosition; origins[i] = eyes[i].localPosition;
centerBounds.Encapsulate(origins[i]); centerBounds.Encapsulate(origins[i]);
} }
centerPoint = centerBounds.center; centerPoint = centerBounds.center;
} }
protected override void OnDisable () { protected override void OnDisable () {
if (!Application.isPlaying) return; if (!Application.isPlaying) return;
for (int i = 0; i < eyes.Length; i++) { for (int i = 0; i < eyes.Length; i++) {
eyes[i].localPosition = origins[i]; eyes[i].localPosition = origins[i];
} }
base.OnDisable(); base.OnDisable();
} }
public override void DoUpdate () { public override void DoUpdate () {
if (target != null) targetPosition = target.position; if (target != null) targetPosition = target.position;
Vector3 goal = targetPosition; Vector3 goal = targetPosition;
Vector3 center = transform.TransformPoint(centerPoint); Vector3 center = transform.TransformPoint(centerPoint);
Vector3 dir = goal - center; Vector3 dir = goal - center;
if (dir.magnitude > 1) if (dir.magnitude > 1)
dir.Normalize(); dir.Normalize();
for (int i = 0; i < eyes.Length; i++) { for (int i = 0; i < eyes.Length; i++) {
center = transform.TransformPoint(origins[i]); center = transform.TransformPoint(origins[i]);
eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius * hierarchy.PositionScale), eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius * hierarchy.PositionScale),
speed * hierarchy.PositionScale * Time.deltaTime); speed * hierarchy.PositionScale * Time.deltaTime);
} }
} }
} }
} }

View File

@ -1,140 +1,140 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated September 24, 2021. Replaces all prior versions. * Last updated July 28, 2023. Replaces all prior versions.
* *
* Copyright (c) 2013-2021, Esoteric Software LLC * Copyright (c) 2013-2023, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software or
* or otherwise create derivative works of the Spine Runtimes (collectively, * otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER #if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM #define NEW_PREFAB_SYSTEM
#endif #endif
using UnityEngine; using UnityEngine;
namespace Spine.Unity.Examples { namespace Spine.Unity.Examples {
#if NEW_PREFAB_SYSTEM #if NEW_PREFAB_SYSTEM
[ExecuteAlways] [ExecuteAlways]
#else #else
[ExecuteInEditMode] [ExecuteInEditMode]
#endif #endif
[RequireComponent(typeof(SkeletonUtilityBone))] [RequireComponent(typeof(SkeletonUtilityBone))]
public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint { public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint {
[Tooltip("LayerMask for what objects to raycast against")] [Tooltip("LayerMask for what objects to raycast against")]
public LayerMask groundMask; public LayerMask groundMask;
[Tooltip("Use 2D")] [Tooltip("Use 2D")]
public bool use2D = false; public bool use2D = false;
[Tooltip("Uses SphereCast for 3D mode and CircleCast for 2D mode")] [Tooltip("Uses SphereCast for 3D mode and CircleCast for 2D mode")]
public bool useRadius = false; public bool useRadius = false;
[Tooltip("The Radius")] [Tooltip("The Radius")]
public float castRadius = 0.1f; public float castRadius = 0.1f;
[Tooltip("How high above the target bone to begin casting from")] [Tooltip("How high above the target bone to begin casting from")]
public float castDistance = 5f; public float castDistance = 5f;
[Tooltip("X-Axis adjustment")] [Tooltip("X-Axis adjustment")]
public float castOffset = 0; public float castOffset = 0;
[Tooltip("Y-Axis adjustment")] [Tooltip("Y-Axis adjustment")]
public float groundOffset = 0; public float groundOffset = 0;
[Tooltip("How fast the target IK position adjusts to the ground. Use smaller values to prevent snapping")] [Tooltip("How fast the target IK position adjusts to the ground. Use smaller values to prevent snapping")]
public float adjustSpeed = 5; public float adjustSpeed = 5;
Vector3 rayOrigin; Vector3 rayOrigin;
Vector3 rayDir = new Vector3(0, -1, 0); Vector3 rayDir = new Vector3(0, -1, 0);
float hitY; float hitY;
float lastHitY; float lastHitY;
protected override void OnEnable () { protected override void OnEnable () {
base.OnEnable(); base.OnEnable();
lastHitY = transform.position.y; lastHitY = transform.position.y;
} }
public override void DoUpdate () { public override void DoUpdate () {
rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0); rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0);
float positionScale = hierarchy.PositionScale; float positionScale = hierarchy.PositionScale;
float adjustDistanceThisFrame = adjustSpeed * positionScale * Time.deltaTime; float adjustDistanceThisFrame = adjustSpeed * positionScale * Time.deltaTime;
hitY = float.MinValue; hitY = float.MinValue;
if (use2D) { if (use2D) {
RaycastHit2D hit; RaycastHit2D hit;
if (useRadius) if (useRadius)
hit = Physics2D.CircleCast(rayOrigin, castRadius, rayDir, castDistance + groundOffset, groundMask); hit = Physics2D.CircleCast(rayOrigin, castRadius, rayDir, castDistance + groundOffset, groundMask);
else else
hit = Physics2D.Raycast(rayOrigin, rayDir, castDistance + groundOffset, groundMask); hit = Physics2D.Raycast(rayOrigin, rayDir, castDistance + groundOffset, groundMask);
if (hit.collider != null) { if (hit.collider != null) {
hitY = hit.point.y + groundOffset; hitY = hit.point.y + groundOffset;
if (Application.isPlaying) if (Application.isPlaying)
hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame); hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame);
} else { } else {
if (Application.isPlaying) if (Application.isPlaying)
hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame); hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame);
} }
} else { } else {
RaycastHit hit; RaycastHit hit;
bool validHit = false; bool validHit = false;
if (useRadius) if (useRadius)
validHit = Physics.SphereCast(rayOrigin, castRadius, rayDir, out hit, castDistance + groundOffset, groundMask); validHit = Physics.SphereCast(rayOrigin, castRadius, rayDir, out hit, castDistance + groundOffset, groundMask);
else else
validHit = Physics.Raycast(rayOrigin, rayDir, out hit, castDistance + groundOffset, groundMask); validHit = Physics.Raycast(rayOrigin, rayDir, out hit, castDistance + groundOffset, groundMask);
if (validHit) { if (validHit) {
hitY = hit.point.y + groundOffset; hitY = hit.point.y + groundOffset;
if (Application.isPlaying) if (Application.isPlaying)
hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame); hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame);
} else { } else {
if (Application.isPlaying) if (Application.isPlaying)
hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame); hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame);
} }
} }
Vector3 v = transform.position; Vector3 v = transform.position;
v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue); v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue);
transform.position = v; transform.position = v;
bone.bone.X = transform.localPosition.x / hierarchy.PositionScale; bone.bone.X = transform.localPosition.x / hierarchy.PositionScale;
bone.bone.Y = transform.localPosition.y / hierarchy.PositionScale; bone.bone.Y = transform.localPosition.y / hierarchy.PositionScale;
lastHitY = hitY; lastHitY = hitY;
} }
void OnDrawGizmos () { void OnDrawGizmos () {
Vector3 hitEnd = rayOrigin + (rayDir * Mathf.Min(castDistance, rayOrigin.y - hitY)); Vector3 hitEnd = rayOrigin + (rayDir * Mathf.Min(castDistance, rayOrigin.y - hitY));
Vector3 clearEnd = rayOrigin + (rayDir * castDistance); Vector3 clearEnd = rayOrigin + (rayDir * castDistance);
Gizmos.DrawLine(rayOrigin, hitEnd); Gizmos.DrawLine(rayOrigin, hitEnd);
if (useRadius) { if (useRadius) {
Gizmos.DrawLine(new Vector3(hitEnd.x - castRadius, hitEnd.y - groundOffset, hitEnd.z), new Vector3(hitEnd.x + castRadius, hitEnd.y - groundOffset, hitEnd.z)); Gizmos.DrawLine(new Vector3(hitEnd.x - castRadius, hitEnd.y - groundOffset, hitEnd.z), new Vector3(hitEnd.x + castRadius, hitEnd.y - groundOffset, hitEnd.z));
Gizmos.DrawLine(new Vector3(clearEnd.x - castRadius, clearEnd.y, clearEnd.z), new Vector3(clearEnd.x + castRadius, clearEnd.y, clearEnd.z)); Gizmos.DrawLine(new Vector3(clearEnd.x - castRadius, clearEnd.y, clearEnd.z), new Vector3(clearEnd.x + castRadius, clearEnd.y, clearEnd.z));
} }
Gizmos.color = Color.red; Gizmos.color = Color.red;
Gizmos.DrawLine(hitEnd, clearEnd); Gizmos.DrawLine(hitEnd, clearEnd);
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More