-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1301 lines (1126 loc) · 242 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>崎径 其镜</title>
<subtitle>求学道路上的行车记录仪</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://www.z16388.top/"/>
<updated>2021-05-20T14:09:44.035Z</updated>
<id>http://www.z16388.top/</id>
<author>
<name>Anqi Zhao</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>xlua学习笔记</title>
<link href="http://www.z16388.top/2021/05/18/xlua/"/>
<id>http://www.z16388.top/2021/05/18/xlua/</id>
<published>2021-05-18T11:05:07.000Z</published>
<updated>2021-05-20T14:09:44.035Z</updated>
<content type="html"><![CDATA[<h1 id="文件加载"><a href="#文件加载" class="headerlink" title="文件加载"></a>文件加载</h1><p>使用LuaEnv中的DoString方法来执行Lua脚本。<br>因为创建一个LuaEnv相当于创建了一个lua虚拟机,所以一个游戏最好只有一个LuaEnv。</p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 执行lua代码</span></div><div class="line">env.DoString(<span class="string">"print(\"Hello World\")"</span>);</div><div class="line"></div><div class="line"><span class="comment">// 通过文件执行lua代码</span></div><div class="line">TextAsset ta = Resources.Load<TextAsset>(<span class="string">"Lua/helloworld.lua"</span>);</div><div class="line">env.DoString(ta.text);</div><div class="line"></div><div class="line"><span class="comment">// 通过默认Loader执行lua代码</span></div><div class="line">env.DoString(<span class="string">"require 'Lua/helloworld'"</span>);</div><div class="line"></div><div class="line"><span class="comment">// 通过自定义Loader执行lua代码</span></div><div class="line"><span class="comment">// require实际上是调一个个的Loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">byte</span>[] <span class="title">LuaLoader</span>(<span class="params"><span class="keyword">ref</span> <span class="keyword">string</span> filePath</span>)</span></div><div class="line">{</div><div class="line"> <span class="keyword">string</span> path = <span class="string">"Lua/"</span> + filePath + <span class="string">".lua"</span>;</div><div class="line"> print(path);</div><div class="line"> TextAsset ta = Resources.Load<TextAsset>(path);</div><div class="line"> <span class="keyword">return</span> System.Text.Encoding.UTF8.GetBytes(ta.text);</div><div class="line">}</div><div class="line"></div><div class="line">env.AddLoader(LuaLoader);</div><div class="line">env.DoString(<span class="string">"require 'helloworld'"</span>);</div></pre></td></tr></table></figure>
<p>官方建议的加载Lua脚本方式是:整个程序就一个DoString(“require ‘main’”),然后在main.lua加载其它脚本(类似lua脚本的命令行执行:lua main.lua)。</p>
<h1 id="C-访问Lua普通全局变量"><a href="#C-访问Lua普通全局变量" class="headerlink" title="C#访问Lua普通全局变量"></a>C#访问Lua普通全局变量</h1><p>先加载lua脚本,再通过LuaEnv.Global.Get获取变量。</p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">TextAsset ta = Resources.Load<TextAsset>(<span class="string">"Lua/variable.lua"</span>);</div><div class="line">env.DoString(ta.text);</div><div class="line"></div><div class="line"><span class="keyword">int</span> g_int = env.Global.Get<<span class="keyword">int</span>>(<span class="string">"g_int"</span>);</div><div class="line"><span class="keyword">string</span> g_str = env.Global.Get<<span class="keyword">string</span>>(<span class="string">"g_str"</span>);</div><div class="line"><span class="keyword">bool</span> g_bool = env.Global.Get<<span class="keyword">bool</span>>(<span class="string">"g_bool"</span>);</div></pre></td></tr></table></figure>
<h1 id="C-访问Lua-table的四种方法"><a href="#C-访问Lua-table的四种方法" class="headerlink" title="C#访问Lua table的四种方法"></a>C#访问Lua table的四种方法</h1><p>需要注意的是,在构建C#中对应的结构时,接口一定要是public修饰,否则会报错。类最好也是,但是经测试,没有报错。</p>
<p><strong>映射到普通class或struct</strong></p>
<p>table的属性可以多于或者少于class的属性,也就是不一定都需要做映射。这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Person</span></div><div class="line">{</div><div class="line"> <span class="keyword">public</span> <span class="keyword">string</span> name;</div><div class="line"> <span class="keyword">public</span> <span class="keyword">int</span> age;</div><div class="line">}</div><div class="line"></div><div class="line">Person p = env.Global.Get<Person>(<span class="string">"g_tbl"</span>);</div></pre></td></tr></table></figure></p>
<p><strong>映射到接口</strong></p>
<p>一定要加[CSharpCallLua]和public,否则会报错。<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">g_int = <span class="number">1</span></div><div class="line">g_str = <span class="string">"Hello World Variable"</span></div><div class="line">g_bool = <span class="keyword">false</span></div><div class="line">g_tbl = {name = <span class="string">"Juhnny"</span>, age = <span class="number">12</span>}</div><div class="line">g_tbl.say = <span class="function"><span class="keyword">function</span><span class="params">(this, str)</span></span></div><div class="line"> <span class="built_in">print</span>(str)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">[CSharpCallLua]</div><div class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title">IPerson</span></div><div class="line">{</div><div class="line"> <span class="keyword">string</span> name { <span class="keyword">get</span>; <span class="keyword">set</span>; }</div><div class="line"> <span class="keyword">int</span> age { <span class="keyword">get</span>; <span class="keyword">set</span>; }</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">say</span>(<span class="params"><span class="keyword">string</span> str</span>)</span>;</div><div class="line">}</div><div class="line"></div><div class="line">IPerson p = env.Global.Get<IPerson>(<span class="string">"g_tbl"</span>);</div><div class="line">p.say(<span class="string">"Yahoo"</span>);</div></pre></td></tr></table></figure>
<p><strong>映射到Dictionary和List</strong></p>
<p>这种方法较方法2更为轻量级,但是要求table下key和value类型一致。<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">g_dic = {apple = <span class="string">"iPhone"</span>, flower = <span class="string">"Huawei"</span>}</div><div class="line">g_list = {<span class="number">1</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">9</span>}</div></pre></td></tr></table></figure></p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">Dictionary<<span class="keyword">string</span>, <span class="keyword">string</span>> dic = env.Global.Get<Dictionary<<span class="keyword">string</span>, <span class="keyword">string</span>>>(<span class="string">"g_dic"</span>);</div><div class="line"><span class="keyword">foreach</span> (<span class="keyword">var</span> child <span class="keyword">in</span> dic)</div><div class="line">{</div><div class="line"> print(<span class="keyword">string</span>.Format(<span class="string">"Key is {0}, Value is {1}"</span>, child.Key, child.Value));</div><div class="line">}</div><div class="line"></div><div class="line">List<<span class="keyword">int</span>> list = env.Global.Get<List<<span class="keyword">int</span>>>(<span class="string">"g_list"</span>);</div><div class="line"><span class="keyword">foreach</span> (<span class="keyword">var</span> v <span class="keyword">in</span> list)</div><div class="line">{</div><div class="line"> print(v);</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>映射到LuaTable</strong></p>
<p>这种方法比较慢,而且没有类型检查,不推荐使用。<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">LuaTable tab = env.Global.Get<LuaTable>(<span class="string">"g_tbl"</span>);</div><div class="line"><span class="keyword">string</span> name = tab.Get<<span class="keyword">string</span>>(<span class="string">"name"</span>);</div><div class="line"><span class="keyword">int</span> age = tab.Get<<span class="keyword">int</span>>(<span class="string">"age"</span>);</div><div class="line">print(<span class="keyword">string</span>.Format(<span class="string">"Name is {0}, age is {1}"</span>, name, age));</div><div class="line"><span class="keyword">foreach</span> (<span class="keyword">string</span> key <span class="keyword">in</span> tab.GetKeys())</div><div class="line">{</div><div class="line"> print(tab.Get<<span class="keyword">object</span>>(key));</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h1 id="C-访问Lua全局函数"><a href="#C-访问Lua全局函数" class="headerlink" title="C#访问Lua全局函数"></a>C#访问Lua全局函数</h1><p><strong>使用delegate映射</strong></p>
<p>这种是建议的方式,性能好很多,而且类型安全,但是要生成代码。支持带返回值,多返回值,甚至返回值都可以是delegate。<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">g_func1 = <span class="function"><span class="keyword">function</span><span class="params">()</span></span></div><div class="line"> <span class="built_in">print</span>(<span class="string">"FF"</span>)</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line">g_func2 = <span class="function"><span class="keyword">function</span><span class="params">(num)</span></span></div><div class="line"> <span class="built_in">print</span>(num)</div><div class="line"> <span class="keyword">return</span> num, <span class="string">"Yoshida"</span>, <span class="string">"SE"</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">[CSharpCallLua]</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">delegate</span> <span class="keyword">int</span> <span class="title">Func2</span>(<span class="params"><span class="keyword">int</span> num, <span class="keyword">out</span> <span class="keyword">string</span> name, <span class="keyword">out</span> <span class="keyword">string</span> company</span>)</span>;</div><div class="line"><span class="comment">// 声明委托时,一定要加public和[CSharpCallLua]</span></div><div class="line"></div><div class="line"><span class="comment">// 无返回</span></div><div class="line">Action func1 = env.Global.Get<Action>(<span class="string">"g_func1"</span>);</div><div class="line">func1();</div><div class="line">func1 = <span class="literal">null</span>;</div><div class="line"></div><div class="line"><span class="comment">// 单返回值</span></div><div class="line">Func2 func2 = env.Global.Get<Func2>(<span class="string">"g_func2"</span>);</div><div class="line"><span class="keyword">int</span> num = func2(<span class="number">14</span>);</div><div class="line">func2 = <span class="literal">null</span></div><div class="line"></div><div class="line"><span class="comment">// 多返回值</span></div><div class="line">Func2 func2 = env.Global.Get<Func2>(<span class="string">"g_func2"</span>);</div><div class="line"><span class="keyword">string</span> name;</div><div class="line"><span class="keyword">string</span> company;</div><div class="line"><span class="keyword">int</span> num = func2(<span class="number">14</span>, <span class="keyword">out</span> name, <span class="keyword">out</span> company);</div><div class="line">func2 = <span class="literal">null</span></div></pre></td></tr></table></figure>
<p>在过去的一些版本中,需要在不使用后,将接收到的函数销毁,否则会在LuaEnv.Dispose的时候报错。</p>
<p><strong>使用LuaFunction</strong></p>
<p>与上一种方法优缺点相反,不推荐使用。<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">LuaFunction func = env.Global.Get<LuaFunction>(<span class="string">"g_func2"</span>);</div><div class="line"><span class="keyword">object</span>[] res = func.Call(<span class="number">14</span>);</div></pre></td></tr></table></figure></p>
<h1 id="Lua调用C"><a href="#Lua调用C" class="headerlink" title="Lua调用C"></a>Lua调用C</h1><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 读静态属性</span></div><div class="line">CS.UnityEngine.Time.deltaTime</div><div class="line"></div><div class="line"><span class="comment">// 写静态属性</span></div><div class="line">CS.UnityEngine.Time.timeScale = <span class="number">0.5</span></div><div class="line"></div><div class="line"><span class="comment">// 调用静态方法</span></div><div class="line">CS.UnityEngine.GameObject.Find(<span class="string">'helloworld'</span>)</div><div class="line"></div><div class="line"><span class="comment">// 读写成员属性类似,但是访问成员方法要使用:</span></div><div class="line">testobj:DMFunc()</div></pre></td></tr></table></figure>
<h1 id="其它注意事项"><a href="#其它注意事项" class="headerlink" title="其它注意事项"></a>其它注意事项</h1><p><strong>方法的参数处理</strong><br>Lua调用侧的参数处理规则:C#的普通参数算一个输入形参,ref修饰的算一个输入形参,out不算,然后从左往右对应lua 调用侧的实参列表。</p>
<p>Lua调用侧的返回值处理规则:C#函数的返回值(如果有的话)算一个返回值,out算一个返回值,ref算一个返回值,然后从左往右对应lua的多返回值。</p>
<p><strong>可变参数的处理</strong><br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 对于C#的如下方法:</span></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">VariableParamsFunc</span>(<span class="params"><span class="keyword">int</span> a, <span class="keyword">params</span> <span class="keyword">string</span>[] strs</span>)</span></div><div class="line"></div><div class="line"><span class="comment">// 可以在lua里头这样调用:</span></div><div class="line">testobj:<span class="title">VariableParamsFunc</span>(<span class="params"><span class="number">5</span>, <span class="string">'hello'</span>, <span class="string">'john'</span></span>)</div></pre></td></tr></table></figure></p>
<p><strong>枚举</strong><br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 枚举值就像枚举类型下的静态属性一样。</span></div><div class="line"></div><div class="line"> testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)</div><div class="line"></div><div class="line">上面的EnumTestFunc函数参数是Tutorial.TestEnum类型的。</div><div class="line"></div><div class="line">枚举类支持__CastFrom方法,可以实现从一个整数或者字符串到枚举值的转换,例如:</div><div class="line"></div><div class="line"> CS.Tutorial.TestEnum.__CastFrom(<span class="number">1</span>)</div><div class="line"> CS.Tutorial.TestEnum.__CastFrom(<span class="string">'E1'</span>)</div></pre></td></tr></table></figure></p>
<p><strong>委托</strong></p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">-- 使用+-号来实现委托</span></div><div class="line"><span class="comment">-- 比如testobj里头有个事件定义是这样:public event Action TestEvent;</span></div><div class="line"></div><div class="line"><span class="comment">-- 增加事件回调</span></div><div class="line">testobj:TestEvent(<span class="string">'+'</span>, lua_event_callback)</div><div class="line"></div><div class="line"><span class="comment">--移除事件回调</span></div><div class="line">testobj:TestEvent(<span class="string">'-'</span>, lua_event_callback)</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<h1 id="文件加载"><a href="#文件加载" class="headerlink" title="文件加载"></a>文件加载</h1><p>使用LuaEnv中的DoString方法来执行Lua脚本。<br>因为创建一个LuaEnv相当于创建了一个lua虚拟机,所以
</summary>
<category term="游戏" scheme="http://www.z16388.top/tags/%E6%B8%B8%E6%88%8F/"/>
<category term="xlua" scheme="http://www.z16388.top/tags/xlua/"/>
<category term="热更新" scheme="http://www.z16388.top/tags/%E7%83%AD%E6%9B%B4%E6%96%B0/"/>
</entry>
<entry>
<title>Lua新知</title>
<link href="http://www.z16388.top/2021/05/10/luanew/"/>
<id>http://www.z16388.top/2021/05/10/luanew/</id>
<published>2021-05-10T03:42:01.000Z</published>
<updated>2021-05-20T14:31:48.078Z</updated>
<content type="html"><![CDATA[<p>两年没有碰过Lua了,总觉得得要捡起来。现在从头到尾再过一遍,总结一些东西。之前根据菜鸟学的时候,使用了5.1.1的版本。与现在常用的版本相悖。因此这次我使用了:zerobrane studio,它可以方便切换版本,能实现很好的练习效果。</p>
<h1 id="关于多行注释的安全问题"><a href="#关于多行注释的安全问题" class="headerlink" title="关于多行注释的安全问题"></a>关于多行注释的安全问题</h1><p>如果直接使用默认的<code>–[[</code>和<code>–]]</code>来进行多行注释的时候,如果遇到table包table的情况会直接结束注释:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">--[[</span></div><div class="line">a = [];</div><div class="line">b = [a];</div><div class="line">a[b[1]]</div><div class="line">a = <span class="number">1</span></div><div class="line"><span class="comment">--]]</span></div></pre></td></tr></table></figure></p>
<p>可以使用另一种方法来进行多行注释,避免这个问题:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">--[=[</span></div><div class="line">a = [];</div><div class="line">b = [a];</div><div class="line">a[b[1]]</div><div class="line">a = <span class="number">1</span></div><div class="line">]=]</div></pre></td></tr></table></figure></p>
<p>当然,最安全的方法还是使用IDE的快捷键进行注释.IDE会在每行的前面加单行注释,避免错误的发生.</p>
<h1 id="多行字符串安全问题"><a href="#多行字符串安全问题" class="headerlink" title="多行字符串安全问题"></a>多行字符串安全问题</h1><p>多行字符串,也会出现类似于上面的情况:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">str = </div><div class="line"><span class="string">[[</span></div><div class="line">话说</div><div class="line">这个东西</div><div class="line">好像打印不出来</div><div class="line">就是这个</div><div class="line">table[table[idx]]</div><div class="line">咋办啊</div><div class="line">]]</div><div class="line"><span class="built_in">print</span>(str)</div></pre></td></tr></table></figure></p>
<h1 id="运算符相关"><a href="#运算符相关" class="headerlink" title="运算符相关"></a>运算符相关</h1><p>#运算符取的是最大索引的值,如果删除了中间的值,获得的结果不会改变:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">tb_a = {<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}</div><div class="line"><span class="built_in">print</span> (#tb_a)</div><div class="line"></div><div class="line">tb_a[<span class="number">2</span>] = <span class="keyword">nil</span></div><div class="line"><span class="built_in">print</span> (#tb_a)</div></pre></td></tr></table></figure></p>
<p>但是这种情况仅限于Lua 5.1 ,Lua5.3和Lua5.4结果是1。</p>
<p>模拟三目运算符的<code>and…or…</code>,在第二个参数为false时,始终返回c,会出现问题:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">a = <span class="keyword">true</span></div><div class="line"><span class="built_in">print</span> (a <span class="keyword">and</span> <span class="keyword">false</span> <span class="keyword">or</span> <span class="keyword">true</span>)</div></pre></td></tr></table></figure></p>
<p>输出结果会是true 而不是三目运算符应该返回的false。<br>这时候,可以将三目运算符的后面两个部分转换成table,运算结束后再取第一个元素,即可实现:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">a = <span class="keyword">true</span></div><div class="line">b = (a <span class="keyword">and</span> {<span class="keyword">false</span>} <span class="keyword">or</span> {<span class="keyword">true</span>})[<span class="number">1</span>]</div><div class="line"><span class="keyword">if</span> b <span class="keyword">then</span></div><div class="line"> <span class="built_in">print</span>(<span class="string">"true"</span>)</div><div class="line"><span class="keyword">else</span></div><div class="line"> <span class="built_in">print</span>(<span class="string">"false"</span>)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<h1 id="自定义迭代器"><a href="#自定义迭代器" class="headerlink" title="自定义迭代器"></a>自定义迭代器</h1><p>自定义迭代器的格式:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> 变量列表 <span class="keyword">in</span> 迭代函数, 状态变量, 控制变量 <span class="keyword">do</span></div><div class="line"> <span class="comment">-- 循环体</span></div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>自定义无状态迭代器<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">square</span><span class="params">(iteratorMaxCount, currentNumber)</span></span></div><div class="line"> <span class="keyword">if</span> currentNumber < iteratorMaxCount <span class="keyword">then</span></div><div class="line"> currentNumber = currentNumber + <span class="number">1</span></div><div class="line"> <span class="keyword">return</span> currentNumber, currentNumber * currentNumber</div><div class="line"> <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"><span class="keyword">for</span> i, n <span class="keyword">in</span> square, <span class="number">3</span>, <span class="number">0</span></div><div class="line"><span class="keyword">do</span></div><div class="line"> <span class="built_in">print</span>(i, n)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<p>多状态迭代器:<br>多个状态可以存放在table,因此只需要一个参数即可:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">array = {<span class="string">"Google"</span>, <span class="string">"Runoob"</span>}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">elementIterator</span> <span class="params">(collection)</span></span></div><div class="line"> <span class="keyword">local</span> index = <span class="number">0</span></div><div class="line"> <span class="keyword">local</span> count = #collection</div><div class="line"> <span class="comment">-- 闭包函数</span></div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="params">()</span></span></div><div class="line"> index = index + <span class="number">1</span></div><div class="line"> <span class="keyword">if</span> index <= count <span class="keyword">then</span></div><div class="line"> <span class="comment">-- 返回迭代器的当前元素</span></div><div class="line"> <span class="keyword">return</span> collection[index]</div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"><span class="keyword">for</span> element <span class="keyword">in</span> elementIterator(array) <span class="keyword">do</span></div><div class="line"> <span class="built_in">print</span>(element)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<h1 id="循环时的goto语句"><a href="#循环时的goto语句" class="headerlink" title="循环时的goto语句"></a>循环时的goto语句</h1><p>可以使用goto语句来实现continue:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> i=<span class="number">1</span>, <span class="number">3</span> <span class="keyword">do</span></div><div class="line"> <span class="keyword">if</span> i <= <span class="number">2</span> <span class="keyword">then</span></div><div class="line"> <span class="built_in">print</span>(i, <span class="string">"yes continue"</span>)</div><div class="line"> goto continue</div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="built_in">print</span>(i, <span class="string">" no continue"</span>)</div><div class="line"> ::continue::</div><div class="line"> <span class="built_in">print</span>(<span class="string">[[i'm end]]</span>)</div><div class="line"><span class="keyword">end</span></div></pre></td></tr></table></figure></p>
<h1 id="元表"><a href="#元表" class="headerlink" title="元表"></a>元表</h1><p>Lua可以通过设置元表,定义元方法的方式,改变table的一些行为:</p>
<p><strong>index元方法,可以修改按索引取值的逻辑。<br>若</strong>index内容是一个表的话,如果table里没有值,会从元表中对应的索引去取:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">t_table = <span class="built_in">setmetatable</span>({k1 = <span class="string">"v1"</span>}, {__index = {k2 = <span class="string">"v2"</span>}})</div><div class="line"><span class="built_in">print</span>(t_table[<span class="string">"k1"</span>])</div><div class="line"><span class="built_in">print</span>(t_table[<span class="string">"k2"</span>])</div><div class="line">t_table[<span class="string">"k2"</span>] = <span class="string">"v3"</span></div><div class="line"><span class="built_in">print</span>(t_table[<span class="string">"k2"</span>])</div><div class="line"><span class="comment">--[[</span></div><div class="line">输出是:</div><div class="line">v1</div><div class="line">v2</div><div class="line">v3</div><div class="line">--]]</div></pre></td></tr></table></figure></p>
<p>若__index内容是一个函数,则可以定义返回逻辑:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line">t_table = <span class="built_in">setmetatable</span>({}, {__index =</div><div class="line"> <span class="function"><span class="keyword">function</span><span class="params">(t_table, key)</span></span></div><div class="line"> <span class="keyword">if</span> key == <span class="number">1</span> <span class="keyword">then</span></div><div class="line"> <span class="keyword">return</span> <span class="string">"true"</span></div><div class="line"> <span class="keyword">else</span></div><div class="line"> <span class="keyword">return</span> <span class="string">"false"</span></div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="keyword">end</span></div><div class="line">})</div><div class="line"></div><div class="line"><span class="built_in">print</span>(t_table[<span class="number">1</span>])</div><div class="line"><span class="built_in">print</span>(t_table[<span class="number">2</span>])</div><div class="line"><span class="built_in">print</span>(t_table[<span class="number">3</span>])</div><div class="line"></div><div class="line">t_table = {<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}</div><div class="line"></div><div class="line"><span class="built_in">print</span>(t_table[<span class="number">1</span>])</div><div class="line"><span class="built_in">print</span>(t_table[<span class="number">2</span>])</div><div class="line"><span class="built_in">print</span>(t_table[<span class="number">3</span>])</div><div class="line"><span class="comment">--[[</span></div><div class="line">输出是:</div><div class="line">true</div><div class="line">false</div><div class="line">false</div><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">--]]</div></pre></td></tr></table></figure></p>
<p>__newindex元方法,可以修改追加索引时的逻辑<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">t_table = <span class="built_in">setmetatable</span>({k1 = <span class="string">"v1"</span>}, {</div><div class="line"> __newindex =</div><div class="line"> <span class="function"><span class="keyword">function</span><span class="params">(t_table, key, value)</span></span></div><div class="line"> <span class="built_in">rawset</span>(t_table, key, <span class="string">"\"v"</span> .. value .. <span class="string">"\""</span>)</div><div class="line"> <span class="keyword">end</span></div><div class="line">})</div><div class="line"></div><div class="line">t_table[<span class="string">"k2"</span>] = <span class="number">2</span></div><div class="line"></div><div class="line"><span class="built_in">print</span>(t_table[<span class="string">"k1"</span>])</div><div class="line"><span class="built_in">print</span>(t_table[<span class="string">"k2"</span>])</div><div class="line"></div><div class="line"><span class="comment">--[[</span></div><div class="line">输出是:</div><div class="line">v1</div><div class="line">"v2"</div><div class="line">--]]</div></pre></td></tr></table></figure></p>
<p>其它的规则:<br>|元表|运算符|<br>|:–:|:–:|<br>|<strong>add|+|<br>|</strong>sub|-|<br>|<strong>mul|*|<br>|</strong>div|/|<br>|<strong>mod|%|<br>|</strong>unm|-(相反数)|<br>|<strong>concat|..|<br>|</strong>eq|==|<br>|<strong>lt|<|<br>|</strong>le|<=|</p>
<p><strong>add和</strong>tostring:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line">t_table = <span class="built_in">setmetatable</span>({<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}, {__add =</div><div class="line"> <span class="function"><span class="keyword">function</span><span class="params">(t_table, data)</span></span></div><div class="line"> t_table[#t_table + <span class="number">1</span>] = data</div><div class="line"> <span class="keyword">return</span> t_table</div><div class="line"> <span class="keyword">end</span>,</div><div class="line"> __tostring =</div><div class="line"> <span class="function"><span class="keyword">function</span><span class="params">(t_table)</span></span></div><div class="line"> <span class="keyword">local</span> res = <span class="string">""</span></div><div class="line"> <span class="keyword">for</span> _, v <span class="keyword">in</span> <span class="built_in">pairs</span>(t_table) <span class="keyword">do</span></div><div class="line"> res = res .. v</div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="keyword">return</span> res</div><div class="line"> <span class="keyword">end</span></div><div class="line">})</div><div class="line"><span class="built_in">print</span>(t_table)</div><div class="line"><span class="built_in">print</span>(t_table + <span class="number">4</span>)</div><div class="line"><span class="comment">--[[</span></div><div class="line">输出:</div><div class="line">123</div><div class="line">1234</div><div class="line">--]]</div></pre></td></tr></table></figure></p>
<p>需要注意的是,关系运算符,比较的两端,元表必须相同。如果只有一方有元表,另一方没有,又或者是两方拥有不同的元表,会导致比较报错:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">a_metatable =</div><div class="line">{</div><div class="line"> __gt = <span class="function"><span class="keyword">function</span><span class="params">(a_table, b_table)</span></span></div><div class="line"> <span class="keyword">return</span> a_table[<span class="number">1</span>] > b_table[<span class="number">1</span>]</div><div class="line"> <span class="keyword">end</span>,</div><div class="line"> __lt = <span class="function"><span class="keyword">function</span><span class="params">(a_table, b_table)</span></span></div><div class="line"> <span class="keyword">return</span> a_table[<span class="number">1</span>] < b_table[<span class="number">1</span>]</div><div class="line"> <span class="keyword">end</span></div><div class="line">}</div><div class="line">b_metatable =</div><div class="line">{</div><div class="line"> __gt = <span class="function"><span class="keyword">function</span><span class="params">(a_table, b_table)</span></span></div><div class="line"> <span class="keyword">return</span> b_table[<span class="number">1</span>] > a_table[<span class="number">1</span>]</div><div class="line"> <span class="keyword">end</span>,</div><div class="line"> __lt = <span class="function"><span class="keyword">function</span><span class="params">(a_table, b_table)</span></span></div><div class="line"> <span class="keyword">return</span> b_table[<span class="number">1</span>] < a_table[<span class="number">1</span>]</div><div class="line"> <span class="keyword">end</span></div><div class="line">}</div><div class="line">a_table = <span class="built_in">setmetatable</span>({<span class="number">0</span>}, a_metatable)</div><div class="line">b_table = <span class="built_in">setmetatable</span>({<span class="number">1</span>}, b_metatable)</div><div class="line"><span class="built_in">print</span>(a_table<b_table)</div><div class="line"><span class="comment">--[[</span></div><div class="line">报错内容是:</div><div class="line">attempt to compare two table values</div><div class="line">--]]</div></pre></td></tr></table></figure></p>
<p>重写取反操作<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line">a_metatable =</div><div class="line">{</div><div class="line"> __unm = <span class="function"><span class="keyword">function</span><span class="params">(a_table)</span></span></div><div class="line"> <span class="keyword">local</span> _temp_table = {}</div><div class="line"> <span class="keyword">for</span> i = #a_table, <span class="number">1</span>, <span class="number">-1</span> <span class="keyword">do</span></div><div class="line"> _temp_table[#a_table + <span class="number">1</span> - i] = a_table[i]</div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="keyword">return</span> _temp_table</div><div class="line"> <span class="keyword">end</span></div><div class="line">}</div><div class="line">p_metatable =</div><div class="line">{</div><div class="line"> __tostring =</div><div class="line"> <span class="function"><span class="keyword">function</span><span class="params">(a_table)</span></span></div><div class="line"> <span class="keyword">local</span> res = <span class="string">""</span></div><div class="line"> <span class="keyword">for</span> _, v <span class="keyword">in</span> <span class="built_in">pairs</span>(a_table) <span class="keyword">do</span></div><div class="line"> res = res .. v</div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="keyword">return</span> res</div><div class="line"> <span class="keyword">end</span></div><div class="line">}</div><div class="line">a_table = <span class="built_in">setmetatable</span>({<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>}, a_metatable)</div><div class="line">b_table = <span class="built_in">setmetatable</span>(-a_table, p_metatable)</div><div class="line"><span class="built_in">print</span>(b_table)</div></pre></td></tr></table></figure></p>
<p>__call比较有意思,可以让table可以变得和函数一样可以执行。因此可以写成如下的极其过分的形式:<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">function_content =</div><div class="line">{</div><div class="line"> __call = <span class="function"><span class="keyword">function</span><span class="params">(a_table, a_data)</span></span></div><div class="line"> <span class="built_in">print</span>(a_data)</div><div class="line"> <span class="keyword">end</span></div><div class="line">}</div><div class="line"></div><div class="line"></div><div class="line">func_print = <span class="built_in">setmetatable</span>({}, function_content)</div><div class="line">b = func_print(<span class="number">4</span>)</div></pre></td></tr></table></figure></p>
<h1 id="协程"><a href="#协程" class="headerlink" title="协程"></a>协程</h1><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">sleep</span><span class="params">(n)</span></span></div><div class="line"> <span class="keyword">local</span> t0 = <span class="built_in">os</span>.clock()</div><div class="line"> <span class="keyword">while</span> <span class="built_in">os</span>.clock() - t0 <= n <span class="keyword">do</span> <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div><div class="line"><span class="comment">-- 这里的sleep会占用大量资源 正常逻辑不能使用</span></div><div class="line"></div><div class="line">test_coroutine = <span class="built_in">coroutine</span>.create(</div><div class="line"> <span class="function"><span class="keyword">function</span><span class="params">()</span></span></div><div class="line"> <span class="keyword">for</span> i = <span class="number">1</span>, <span class="number">10</span>, <span class="number">1</span> <span class="keyword">do</span></div><div class="line"> <span class="built_in">print</span>(i)</div><div class="line"> sleep(<span class="number">0.1</span>)</div><div class="line"> <span class="built_in">coroutine</span>.yield()</div><div class="line"> <span class="keyword">end</span></div><div class="line"> <span class="keyword">end</span></div><div class="line">)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">do_cro</span><span class="params">(co)</span></span></div><div class="line"> <span class="keyword">while</span>(<span class="built_in">coroutine</span>.status(co) ~=<span class="string">"dead"</span>) <span class="keyword">do</span></div><div class="line"> <span class="built_in">coroutine</span>.resume(co)</div><div class="line"> <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line">do_cro(test_coroutine)</div></pre></td></tr></table></figure>
<h1 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h1><p>用table实现了类与继承<br><figure class="highlight lua"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="comment">-- 类</span></div><div class="line"><span class="comment">-- 类管理器 </span></div><div class="line">CClassManager = {}</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">CClassManager.ctor</span><span class="params">(cls, ...)</span></span></div><div class="line"> <span class="keyword">local</span> this = {}</div><div class="line"> <span class="built_in">setmetatable</span>(this, cls)</div><div class="line"> cls.__index = cls <span class="comment">-- 将元表的__index设为自身,访问表的属性不存在时会搜索元表</span></div><div class="line"> cls.init(this, ...)</div><div class="line"> <span class="keyword">return</span> this</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">CClassManager.VInit</span><span class="params">(self, ...)</span></span></div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">CClassManager.init</span><span class="params">(self, ...)</span></span></div><div class="line"> self:VInit(...)</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">CClassManager.dtor</span><span class="params">(cls)</span></span></div><div class="line"> <span class="comment">-- do sth</span></div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="comment">-- 通过继承实现的类的定义</span></div><div class="line">ClassT = CClassManager:ctor()</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">ClassT.VInit</span><span class="params">(self, word)</span></span></div><div class="line"> self.word = word</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">ClassT.say</span><span class="params">(self)</span></span></div><div class="line"> <span class="built_in">print</span>(self.word)</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line">test = ClassT:ctor(<span class="string">"B"</span>)</div><div class="line">test:say()</div><div class="line">test:dtor()</div><div class="line">test:say()</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<p>两年没有碰过Lua了,总觉得得要捡起来。现在从头到尾再过一遍,总结一些东西。之前根据菜鸟学的时候,使用了5.1.1的版本。与现在常用的版本相悖。因此这次我使用了:zerobrane studio,它可以方便切换版本,能实现很好的练习效果。</p>
<h1 id="关于多行注
</summary>
<category term="Lua" scheme="http://www.z16388.top/tags/Lua/"/>
<category term="游戏" scheme="http://www.z16388.top/tags/%E6%B8%B8%E6%88%8F/"/>
</entry>
<entry>
<title>EFK日志分析系统的搭建</title>
<link href="http://www.z16388.top/2021/05/06/efk/"/>
<id>http://www.z16388.top/2021/05/06/efk/</id>
<published>2021-05-06T09:22:01.000Z</published>
<updated>2021-05-20T14:00:28.439Z</updated>
<content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><blockquote>
<p>EFK 是三个开源软件的缩写,Elasticsearch,FileBeat,Kibana。其中 ELasticsearch 负责日志分析和存储,FileBeat 负责日志收集,Kibana 负责界面展示。它们之间互相配合使用,完美衔接,高效的满足了很多场合的应用,是目前主流的一种日志分析系统解决方案。</p>
<p>EFK 和 ELK 只有一个区别, 收集日志的组件由 Logstash 替换成了 FileBeat,因为 Filebeat 相对于 Logstash 来说有2个好处:<br>1.侵入低,无需修改 elasticsearch 和 kibana 的配置;<br>2.性能高,IO 占用率比 logstash 小太多</p>
<p>当然 Logstash 相比于 FileBeat 也有一定的优势,比如 Logstash 对于日志的格式化处理能力,FileBeat 只是将日志从日志文件中读取出来,当然如果收集的日志本身是有一定格式的,FileBeat 也可以格式化,但是相对于Logstash 来说,效果差很多。</p>
</blockquote>
<h2 id="部署步骤"><a href="#部署步骤" class="headerlink" title="部署步骤"></a>部署步骤</h2><p><strong>1 . 安装Docker</strong></p>
<p><strong>2 . 下载所需镜像</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">docker pull elasticsearch:7.12.0</div><div class="line">docker pull kibana:7.12.0</div><div class="line">docker pull store/elastic/filebeat:7.12.0</div></pre></td></tr></table></figure></p>
<p><strong>3 . 创建自定义网络</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker network create elk_net</div></pre></td></tr></table></figure></p>
<p><strong>4 . 启动Elasticsearch和Kibana</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">docker run -d --name elasticsearch --net elk_net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.12.0</div><div class="line">docker run -d --name kibana --net elk_net -p 5601:5601 kibana:7.12.0</div></pre></td></tr></table></figure></p>
<p>如果希望使用中文界面(中文化不完全,不推荐使用),可以进入kibana的容器里,修改排至文件,在现有配置文件中加一行中文相关的配置即可:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">server.name: kibana</div><div class="line">server.host: "0"</div><div class="line">elasticsearch.hosts: [ "http://elasticsearch:9200" ]</div><div class="line">monitoring.ui.container.elasticsearch.enabled: true</div><div class="line">// 设置语言为中文↓</div><div class="line">i18n.locale: "zh-CN"</div></pre></td></tr></table></figure></p>
<p>进入docker容器的指令为:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker exec -it kibana /bin/bash</div></pre></td></tr></table></figure></p>
<p><strong>5 . 配置日志解析规则</strong><br>日志解析的规则,是存放在Elasticsearch中的。只要通过curl命令即可实现向es中插入数据。<br>新建json文件:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> "grok": {</div><div class="line"> "field": "message",</div><div class="line"> "patterns": [</div><div class="line"> "%{TIMESTAMP_ISO8601:Time}\\s\\s*\\[%{DATA:ServerType}\\]*\\[%{DATA:ServerID}\\]*\\[%{LOGLEVEL:Level}\\s+\\]*\\[%{DATA:Func}\\]%{GREEDYDATA:Log}"</div><div class="line"> ],</div><div class="line"> "pattern_definitions": {</div><div class="line"> "ALL_CODE": "(.|\\n)*"</div><div class="line"> }</div><div class="line"> }</div><div class="line">},</div><div class="line">{</div><div class="line"> "date": {</div><div class="line"> "field": "Time",</div><div class="line"> "formats": [</div><div class="line"> "ISO8601"</div><div class="line"> ],</div><div class="line"> "target_field": "@timestamp",</div><div class="line"> "timezone": "Asia/Shanghai"</div><div class="line"> }</div><div class="line">},</div><div class="line">{</div><div class="line"> "remove": {</div><div class="line"> "field": "message"</div><div class="line"> }</div><div class="line">},</div><div class="line">{</div><div class="line"> "remove": {</div><div class="line"> "field": "Time"</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>patterns部分为解析每行日志的正则表达式,pattern_definitions是处理换行标志。<br>测试可以使用kibana自带的grok测试工具,在设置界面会有。<br>下方的date部分,是通过对上方产生的Time字段,存放到默认的时间戳上,用于处理排序。<br>处理完成后,把多余的字段删除,特别是输入的message,有利于缩减入库数据的量。<br>需要注意的是,json文件里的反斜杠一定要进行转义。</p>
<p>执行命令:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">curl -H "Content-Type: application/json" -XPUT 'http://192.168.3.67:9200/_ingest/pipeline/lmyzpip' -d@/home/docker/pipline/pip.json</div></pre></td></tr></table></figure></p>
<p>除此之外,可以登录Kibana界面,通过可视化界面配置解析。</p>
<ul>
<li>点击左侧的三条线按钮,进入Stack Management->Ingest Node Pipelines->Create a pipeline</li>
<li>输入名称和描述</li>
<li>点击下方Add a processor,增加处理方式</li>
<li>填写相关参数,点击Add保存</li>
</ul>
<p>右侧Add documents可以填写测试用例,测试相关配置是否正确(通过直接写入ES的配置也可以在此测试)。</p>
<p>测试数据的格式为:</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">[</div><div class="line"> {<span class="attr">"_index"</span>:<span class="string">"index"</span>,</div><div class="line"> <span class="attr">"_id"</span>:<span class="string">"id"</span>,</div><div class="line"> <span class="attr">"_source"</span>:{<span class="attr">"message"</span>:<span class="string">"2021-04-29T15:42:05.000000 [Game][4][DEBUG ][CNetManager::_SendServerConfigRequest]Request for server-config, Stream-{Game: 4-0}. ServerConfig<2> DBConfig<0> RedisConfig<0>"</span>}</div><div class="line"> }</div><div class="line">]</div></pre></td></tr></table></figure>
<p><strong>6 . 安装filebeat</strong><br>新增配置文件filebeat.docker.yml:</p>
<figure class="highlight yml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#=========================== Filebeat inputs ==============</span></div><div class="line">filebeat.inputs:</div><div class="line"></div><div class="line"><span class="attr">- type:</span> log</div><div class="line"></div><div class="line"><span class="attr"> enabled:</span> <span class="literal">true</span></div><div class="line"> <span class="comment">##配置你要收集的日志目录,可以配置多个目录</span></div><div class="line"><span class="attr"> paths:</span></div><div class="line"><span class="bullet"> -</span> /home/docker/logs/*.log</div><div class="line"></div><div class="line"><span class="comment">## 设置kibana的地址,开始filebeat的可视化 </span></div><div class="line">setup.kibana.host: <span class="string">"http://kibana:5601"</span></div><div class="line">setup.dashboards.enabled: <span class="literal">true</span></div><div class="line"><span class="comment">#-------------------------- Elasticsearch output ---------</span></div><div class="line">output.elasticsearch:</div><div class="line"><span class="attr"> hosts:</span> [<span class="string">"elasticsearch:9200"</span>]</div><div class="line"><span class="attr"> pipeline:</span> <span class="string">"lmyzpip"</span></div><div class="line"></div><div class="line">setup.template.name: <span class="string">"my-log"</span></div><div class="line">setup.template.pattern: <span class="string">"my-log-*"</span></div><div class="line">json.keys_under_root: <span class="literal">false</span></div><div class="line">json.overwrite_keys: <span class="literal">true</span></div></pre></td></tr></table></figure>
<p>其中需要注意的是,如果filebeat和前面的EK两个东西,没有部署在同一台机器上,需要把容器名改成对应的ip地址。</p>
<p>运行Filebeat:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">docker run -d --net elk_net -v /home/docker/filebeat/filebeat.docker.yml:/usr/share/filebeat/filebeat.yml -v /home/docker/logs/:/home/docker/logs/ --link elasticsearch:elasticsearch --link kibana:kibana --name filebeat docker.io/store/elastic/filebeat:7.12.0</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><blockquote>
<p>EFK 是三个开源软件的缩写,Elasticsearch,FileBeat,Kibana。其中 ELasticse
</summary>
<category term="ELK" scheme="http://www.z16388.top/tags/ELK/"/>
<category term="运维" scheme="http://www.z16388.top/tags/%E8%BF%90%E7%BB%B4/"/>
</entry>
<entry>
<title>使用贝塞尔曲线实现道具随机飞动效果</title>
<link href="http://www.z16388.top/2020/12/12/bezier/"/>
<id>http://www.z16388.top/2020/12/12/bezier/</id>
<published>2020-12-12T13:03:53.000Z</published>
<updated>2021-05-20T13:51:15.596Z</updated>
<content type="html"><![CDATA[<p>工作中,遇到了一个需求是要实现获得道具和货币的飞动效果:</p>
<ol>
<li>根据道具的多少生成不同数目的道具</li>
<li>货币首先要有一个炸开的效果,然后向一个点汇集;道具从原位置沿直线飞过去</li>
<li>balabala</li>
</ol>
<p>这里只讨论货币飞行路线的问题。</p>
<p>贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。PS中的钢笔工具就是使用贝塞尔曲线来绘制矢量曲线的。</p>
<p>这里使用简单的,四个点确定的贝塞尔曲线来实现飞行轨迹。首先p0和p3分别是移动的起点和终点。为了模拟爆炸效果,可以通过随机选取以p0为圆心,长度为R的圆上的点,调整曲线的第一次弯折位置实现。这一点定为P1。最后,根据P1点和P0点之间的关系,进行x轴或者y轴的修正,实现曲线平滑延申到p3,这一点是p2点。</p>
<p>p1点(爆炸点)的获取方式:<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Vector3 <span class="title">GetRandomPosition</span>(<span class="params">Vector3 vec</span>)</span></div><div class="line">{</div><div class="line"> <span class="keyword">float</span> sita = UnityEngine.Random.Range(-Mathf.PI, Mathf.PI);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Vector3(vec.x + Mathf.Cos(sita) * Screen.width / <span class="number">8</span>, vec.y + Mathf.Sin(sita) * Screen.width / <span class="number">8</span>);</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>p2点(修正点)的获取方式:<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Vector3 <span class="title">GetFixedPoint</span>(<span class="params">Vector3 start, Vector3 end</span>)</span></div><div class="line">{</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Vector3(start.x + <span class="number">3</span>*(end.x - start.x)/<span class="number">4</span>, start.y + <span class="number">3</span> * (end.y - start.y) / <span class="number">4</span> + p1.y > start.y ? Screen.height / <span class="number">15</span> : - Screen.height / <span class="number">15</span>);</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>根据已知的四个点,实现物体延贝塞尔曲线移动的效果。</p>
<figure class="highlight cs"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag"><summary></span></span></div><div class="line"><span class="comment"><span class="doctag">///</span> 延贝塞尔曲线移动</span></div><div class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag"></summary></span></span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> IEnumerator <span class="title">MoveBezier</span>(<span class="params">GComponent gcom, <span class="keyword">float</span> time, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3</span>)</span></div><div class="line">{</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">float</span> t = <span class="number">0</span>; t < time; t += Time.deltaTime)</div><div class="line"> {</div><div class="line"> gcom.position = CalculateCubicBezierPoint(t / time, p0, p1, p2, p3);</div><div class="line"> <span class="keyword">yield</span> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line"> }</div><div class="line"> gcom.position = p3;</div><div class="line"> gcom.Dispose();</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag"><summary></span></span></div><div class="line"><span class="comment"><span class="doctag">///</span> 计算贝塞尔曲线点的坐标</span></div><div class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag"></summary></span></span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Vector3 <span class="title">CalculateCubicBezierPoint</span>(<span class="params"><span class="keyword">float</span> t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3</span>)</span></div><div class="line">{</div><div class="line"> <span class="keyword">float</span> u = <span class="number">1</span> - t;</div><div class="line"> <span class="keyword">float</span> tt = t * t;</div><div class="line"> <span class="keyword">float</span> uu = u * u;</div><div class="line"> <span class="keyword">float</span> uuu = uu * u;</div><div class="line"> <span class="keyword">float</span> ttt = tt * t;</div><div class="line"></div><div class="line"> Vector3 p = uuu * p0;</div><div class="line"> p += <span class="number">3</span> * uu * t * p1;</div><div class="line"> p += <span class="number">3</span> * u * tt * p2;</div><div class="line"> p += ttt * p3;</div><div class="line"></div><div class="line"> <span class="keyword">return</span> p;</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>工作中,遇到了一个需求是要实现获得道具和货币的飞动效果:</p>
<ol>
<li>根据道具的多少生成不同数目的道具</li>
<li>货币首先要有一个炸开的效果,然后向一个点汇集;道具从原位置沿直线飞过去</li>
<li>balabala</li>
</ol>
<p>这
</summary>
<category term="Unity" scheme="http://www.z16388.top/tags/Unity/"/>
<category term="游戏" scheme="http://www.z16388.top/tags/%E6%B8%B8%E6%88%8F/"/>
</entry>
<entry>
<title>震惊,JS不加分号会造成错误!?</title>
<link href="http://www.z16388.top/2019/12/02/%E9%9C%87%E6%83%8Ajs/"/>
<id>http://www.z16388.top/2019/12/02/震惊js/</id>
<published>2019-12-01T16:12:19.000Z</published>
<updated>2021-05-20T15:00:59.476Z</updated>
<content type="html"><![CDATA[<p>在之前的工作中,我遇到了一个奇怪的问题。明明在语法上没有问题,找同事也看了,但是程序依旧会产生奇怪的错误。最后通过一步一步断点,定为了错误位置,才找到了造成这个错误的原因———在一个不需要分号的语言中,句末不加分号居然报错了。</p>
<p>不卖关子了,这个错误是多返回值函数造成了对上一句值的影响。下面举个例子:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">func</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> [<span class="number">1</span>, <span class="number">2</span>]</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">let</span> b = <span class="number">0</span></div><div class="line"><span class="keyword">let</span> c = <span class="number">0</span></div><div class="line"><span class="keyword">let</span> a = <span class="number">3</span></div><div class="line">[b, c] = func();</div><div class="line"><span class="built_in">console</span>.log(<span class="string">"a is :"</span> + a)</div><div class="line"><span class="built_in">console</span>.log(<span class="string">"b is :"</span> + b + <span class="string">" c is :"</span> + c)</div></pre></td></tr></table></figure>
<p>运行的结果将会是这样:</p>
<blockquote>
<p>a is :1,2<br>b is :0 c is :0</p>
</blockquote>
<p>很容易看到,我们函数的返回值给了上一行的a。这是因为我们的编译器将代码认为了:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> a = <span class="number">3</span> ,[b, c] = func();</div></pre></td></tr></table></figure>
<p>避免这种情况,还是要多加分号吧——虽然它并不会报错。</p>
]]></content>
<summary type="html">
<p>在之前的工作中,我遇到了一个奇怪的问题。明明在语法上没有问题,找同事也看了,但是程序依旧会产生奇怪的错误。最后通过一步一步断点,定为了错误位置,才找到了造成这个错误的原因———在一个不需要分号的语言中,句末不加分号居然报错了。</p>
<p>不卖关子了,这个错误是多返回值函
</summary>
<category term="JavaScript" scheme="http://www.z16388.top/tags/JavaScript/"/>
</entry>
<entry>
<title>Linux升级Python</title>
<link href="http://www.z16388.top/2019/11/28/linuxuppy/"/>
<id>http://www.z16388.top/2019/11/28/linuxuppy/</id>
<published>2019-11-28T04:12:19.000Z</published>
<updated>2019-12-01T17:10:37.987Z</updated>
<content type="html"><![CDATA[<p>11月底,腾讯云搞了一波双11返场活动,我买了三年的服务器。</p>
<p>和买了新的电脑或者做了新系统一样,得先把生产环境搞好。</p>
<p>距离Python2.x停止维护大概只有5个月了吧,所以第一要务是升级Python的版本。但是yum是依赖Python2的,所以升级还是会有一些顾虑的。下面是升级的过程:</p>
<h1 id="下载、解压"><a href="#下载、解压" class="headerlink" title="下载、解压"></a>下载、解压</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">wget https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz</div><div class="line">tar -zxvf Python-3.8.0.tgz</div></pre></td></tr></table></figure>
<h1 id="安装编译环境"><a href="#安装编译环境" class="headerlink" title="安装编译环境"></a>安装编译环境</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">yum install make build-essential libssl-dev zlib1g-dev libbz2-dev</div><div class="line">yum install zlib</div></pre></td></tr></table></figure>
<h1 id="编译、安装"><a href="#编译、安装" class="headerlink" title="编译、安装"></a>编译、安装</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">yum install -y make build-essential libssl-dev zlib1g-dev libbz2-dev</div><div class="line">yum -y install zlib</div><div class="line"></div><div class="line">cd Python-3.8.0</div><div class="line">./configure</div><div class="line">make && make install</div></pre></td></tr></table></figure>
<h1 id="备份与配置"><a href="#备份与配置" class="headerlink" title="备份与配置"></a>备份与配置</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">mv /usr/bin/python /usr/bin/python.bak</div><div class="line">ln -s /usr/local/bin/python3 /usr/bin/python</div></pre></td></tr></table></figure>
<h1 id="保证yum可用"><a href="#保证yum可用" class="headerlink" title="保证yum可用"></a>保证yum可用</h1><p>将下面文件中的配置修改为Python2.x版本的路径。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">/usr/bin/yum</div><div class="line">/usr/libexec/urlgrabber-ext-down</div></pre></td></tr></table></figure>
<h1 id="安装pip"><a href="#安装pip" class="headerlink" title="安装pip"></a>安装pip</h1><p>pip需要依赖setuptools,所以要先安装setuptools。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">wget https://files.pythonhosted.org/packages/ce/1d/96320b9784b04943c924a9f1c6fa49124a1542039ce098a5f9a369227bad/setuptools-42.0.1.zip</div><div class="line">unzip setuptools-42.0.1.zip</div><div class="line">cd setuptools-42.0.1</div><div class="line">python setup.py build</div><div class="line">python setup.py install</div><div class="line"></div><div class="line">wget https://files.pythonhosted.org/packages/ce/ea/9b445176a65ae4ba22dce1d93e4b5fe182f953df71a145f557cffaffc1bf/pip-19.3.1.tar.gz</div><div class="line">tar -zxvf pip-19.3.1.tar.gz</div><div class="line">cd pip-19.3.1</div><div class="line">python setup.py build</div><div class="line">python setup.py install</div></pre></td></tr></table></figure>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><a href="https://www.cnblogs.com/zhangym/p/6226435.html" target="_blank" rel="external">https://www.cnblogs.com/zhangym/p/6226435.html</a><br><a href="https://www.cnblogs.com/fjping0606/p/9156344.html" target="_blank" rel="external">https://www.cnblogs.com/fjping0606/p/9156344.html</a><br><a href="https://www.cnblogs.com/fyly/p/11112169.html" target="_blank" rel="external">https://www.cnblogs.com/fyly/p/11112169.html</a></p>
]]></content>
<summary type="html">
<p>11月底,腾讯云搞了一波双11返场活动,我买了三年的服务器。</p>
<p>和买了新的电脑或者做了新系统一样,得先把生产环境搞好。</p>
<p>距离Python2.x停止维护大概只有5个月了吧,所以第一要务是升级Python的版本。但是yum是依赖Python2的,所以升
</summary>
<category term="Python" scheme="http://www.z16388.top/tags/Python/"/>
<category term="Linux" scheme="http://www.z16388.top/tags/Linux/"/>
</entry>
<entry>
<title>Github图床工具</title>
<link href="http://www.z16388.top/2019/11/17/picupdate/"/>
<id>http://www.z16388.top/2019/11/17/picupdate/</id>
<published>2019-11-17T10:32:44.000Z</published>
<updated>2019-11-17T10:33:15.419Z</updated>
<content type="html"><![CDATA[<p>这是一个上传图片到github的工具,目前还不是很成熟,不过已经可以实现压缩并上传图片的目的了,对于写博客来说已经够用了。</p>
<h1 id="使用步骤"><a href="#使用步骤" class="headerlink" title="使用步骤"></a>使用步骤</h1><ol>
<li>创建todo目录</li>
<li>创建pic目录,在github上创建一个空项目,然后pull到这里</li>
<li>修改配置文件,将git_url修改为上一步新建的项目</li>
<li>将图片放到todo文件夹下</li>
<li>执行工具</li>
</ol>
<p>需要注意的是,因为图床需要一个git目录,同时代码也需要。在使用部分git管理工具时会禁止这种目录的嵌套。因此最好将代码独立运行。可以自己打包,也可以使用我打好的可执行程序。</p>
<p>在这里需要提一句,一般如果只想要下载github上项目的一个目录或者一个文件,可以使用svn进行下载。将文件路径中的<code>文件名/master</code>替换为<code>trunk</code>即可使用下载。</p>
<p>经过配置之后,以后只需要将图片放到todo目录下,执行脚本即可。</p>
<p>编译时需要安装以下运行库</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">pip install pyyaml</div><div class="line">pip install gitpython</div><div class="line">pip install pillow</div></pre></td></tr></table></figure>
<h1 id="更新文档"><a href="#更新文档" class="headerlink" title="更新文档"></a>更新文档</h1><p>Ver.0.2 2019-11-17 提交编译的可执行程序;增加配置文件</p>
<p>Ver.0.1 2019-11-12 提交项目</p>
]]></content>
<summary type="html">
<p>这是一个上传图片到github的工具,目前还不是很成熟,不过已经可以实现压缩并上传图片的目的了,对于写博客来说已经够用了。</p>
<h1 id="使用步骤"><a href="#使用步骤" class="headerlink" title="使用步骤"></a>使用步骤<
</summary>
<category term="Python" scheme="http://www.z16388.top/tags/Python/"/>
<category term="Github" scheme="http://www.z16388.top/tags/Github/"/>
</entry>
<entry>
<title>JS使用replace()函数全部替换</title>
<link href="http://www.z16388.top/2019/11/16/jsreplace/"/>
<id>http://www.z16388.top/2019/11/16/jsreplace/</id>
<published>2019-11-16T14:03:56.000Z</published>
<updated>2019-11-16T14:03:21.249Z</updated>
<content type="html"><![CDATA[<p>在处理爬虫爬取下来的数据时,遇到了在文字中出现了经过转义的换行符,在文中显示出了\n,很影响观赏效果。因此,我对内容做了处理。</p>
<p>但是在刷库的过程中,我发现,我总不能一次处理完所有的数据。后来发现是JavaScript的Replace函数的问题,这个函数默认只能替换第一个匹配到的项目。如果需要处理全部的,需要使用正则表达式:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">string.replace(<span class="regexp">/\\n/g</span>, <span class="string">"\n"</span>)</div></pre></td></tr></table></figure>
<p>除此之外,下面是一些处理爬取内容常用操作,包含了html的转义:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">string.replace(<span class="regexp">/&nbsp;/g</span>, <span class="string">' '</span>)</div><div class="line">string.replace(<span class="regexp">/&lt;/g</span>, <span class="string">'<'</span>)</div><div class="line">string.replace(<span class="regexp">/&gt;/g</span>, <span class="string">'>'</span>)</div><div class="line">string.replace(<span class="regexp">/&amp;/g</span>, <span class="string">'&'</span>)</div><div class="line">string.replace(<span class="regexp">/&quot;/g</span>, <span class="string">'"'</span>)</div><div class="line"> string.replace(<span class="regexp">/&#x3D;/g</span>, <span class="string">'='</span>)</div><div class="line"> string.replace(<span class="regexp">/\[.*?\]/g</span>,<span class="string">''</span>)</div><div class="line"> string.replace(<span class="string">"\\n"</span>,<span class="string">"\n"</span>)</div><div class="line"> string.replace(<span class="string">"\\t"</span>,<span class="string">""</span>)</div><div class="line"> string.replace(<span class="string">"\\r"</span>,<span class="string">""</span>)</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>在处理爬虫爬取下来的数据时,遇到了在文字中出现了经过转义的换行符,在文中显示出了\n,很影响观赏效果。因此,我对内容做了处理。</p>
<p>但是在刷库的过程中,我发现,我总不能一次处理完所有的数据。后来发现是JavaScript的Replace函数的问题,这个函数默认只能
</summary>
<category term="JavaScript" scheme="http://www.z16388.top/tags/JavaScript/"/>
</entry>
<entry>
<title>JS使用Splice()函数操作数组</title>
<link href="http://www.z16388.top/2019/11/16/jssplice/"/>
<id>http://www.z16388.top/2019/11/16/jssplice/</id>
<published>2019-11-16T13:59:56.000Z</published>
<updated>2019-11-16T14:00:02.652Z</updated>
<content type="html"><![CDATA[<p>在js的使用过程中,有一次需要对数组进行各种操作,一时间迫使我想要去使用链表。后来通过查阅资料,总结了下面的一些方法,主要使用了splice()函数。</p>
<p>下面的方法主要是使用下标进行操作。如果是用值的话,可以通过<code>indexOf()</code>函数来获取下标。若不存在则返回-1。</p>
<p>值交换</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">swap_arr</span>(<span class="params">a_list, index1, index2</span>) </span>{</div><div class="line"> a_list[index1] = a_list.splice(index2, <span class="number">1</span>, a_list[index1])[<span class="number">0</span>];</div><div class="line"> <span class="keyword">return</span> a_list;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>置顶</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">up_arr</span>(<span class="params">a_list, index</span>)</span>{</div><div class="line"> <span class="keyword">if</span>(index!=<span class="number">0</span> && index!=<span class="number">-1</span>){</div><div class="line"> a_list[index] = a_list.splice(index<span class="number">-1</span>, <span class="number">1</span>, a_list[index])[<span class="number">0</span>];</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>下移</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">down_arr</span>(<span class="params">a_list, index</span>) </span>{</div><div class="line"> <span class="keyword">if</span>(index!=a_list.length<span class="number">-1</span> && index!=<span class="number">-1</span>){</div><div class="line"> a_list[index] = a_list.splice(index+<span class="number">1</span>, <span class="number">1</span>, a_list[index])[<span class="number">0</span>];</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>插入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">ins_arr</span>(<span class="params">a_list, index, a_data</span>) </span>{</div><div class="line"> <span class="keyword">if</span>(index!=<span class="number">-1</span>){</div><div class="line"> <span class="keyword">if</span> (a_list.indexOf(a_data)==<span class="number">-1</span>) {</div><div class="line"> a_list.splice(index+<span class="number">1</span>, <span class="number">0</span>, a_data);</div><div class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>在顶部插入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">topins_arr</span>(<span class="params">a_list, a_data</span>) </span>{</div><div class="line"> a_list.splice(<span class="number">0</span>, <span class="number">0</span>, a_data)</div><div class="line">}</div></pre></td></tr></table></figure>
<p>删除元素</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">del_arr</span>(<span class="params">a_list, a_data_list</span>) </span>{</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> ele <span class="keyword">of</span> a_data_list) {</div><div class="line"> <span class="keyword">let</span> index = a_list.indexOf(ele);</div><div class="line"> <span class="keyword">if</span>(index!=<span class="number">-1</span>){</div><div class="line"> a_list.splice(index, <span class="number">1</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>在js的使用过程中,有一次需要对数组进行各种操作,一时间迫使我想要去使用链表。后来通过查阅资料,总结了下面的一些方法,主要使用了splice()函数。</p>
<p>下面的方法主要是使用下标进行操作。如果是用值的话,可以通过<code>indexOf()</code>函数来
</summary>
<category term="JavaScript" scheme="http://www.z16388.top/tags/JavaScript/"/>
</entry>
<entry>
<title>当你的程序连接Mysql然后崩溃时</title>
<link href="http://www.z16388.top/2019/11/16/mysqltimeout/"/>
<id>http://www.z16388.top/2019/11/16/mysqltimeout/</id>
<published>2019-11-16T13:43:56.000Z</published>
<updated>2019-11-16T13:47:13.465Z</updated>
<content type="html"><![CDATA[<p>之前写过一个监控mysql数据库更新状态的预警程序,总是莫名其妙的报一个连接错误的错,然后程序死掉。后来在系统趋于稳定之后,我就没再继续维护这个工具了。</p>
<p>但是最近我在写另一个工具时,遇到了一个奇怪的问题,就是:tick总在27000多左右的时候崩溃。</p>
<p>我进行了一系列的猜测,比如tick的代码,或者是逻辑有问题,最后我把思路放在了之前遇到的这个错误上。查阅资料后发现,MySQL数据库在连接之后,如果超过一个设定的时间戳之后,会断开。这个值叫<code>WAIT_TIMEOUT</code>,默认值是28800,也就是说如果连上MySQL数据库之后,8小时内没有进行操作,这个连接便会断开。</p>
<p>网上很多连接MySQL数据库的代码没有处理过超时连接的问题,就连JS的官方代码好像也是在17年之后才更新的。以往这个问题,大家都是通过修改这个值来进行规避的。比如改成300天。修改有两种方式,一种是修改配置文件,这样在启动时便会使用这个配置;另一种是修改这个值,或者全局,或者当次生效。</p>
<p>下面是我在使用JavaScript语言链接MySQL数据库时,处理超时重连问题的代码:</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line">this.config = {</div><div class="line"> "host": "x.x.x.x",</div><div class="line"> "port": xxxx,</div><div class="line"> "user": "root",</div><div class="line"> "password": "pass",</div><div class="line"> "database": "name""</div><div class="line">} </div><div class="line"></div><div class="line">async connect() {</div><div class="line"> let self = this;</div><div class="line"> console.log("connect mysql success with", JSON.stringify(this.config))</div><div class="line"> // 创建连接</div><div class="line"> this.db_mysql = mysql.createConnection(</div><div class="line"> this.config</div><div class="line"> );</div><div class="line"> // 连接数据库</div><div class="line"> await this.db_mysql.connect();</div><div class="line"> // 错误处理</div><div class="line"> this.db_mysql.on('error', function(err) {</div><div class="line"> if (err) {</div><div class="line"> if (err.code === 'PROTOCOL_CONNECTION_LOST') {</div><div class="line"> // 处理超时</div><div class="line"> console.warning("start reconnect mysql");</div><div class="line"> self.connect();</div><div class="line"> } else {</div><div class="line"> console.error(err.stack || err);</div><div class="line"> console.warning("start reconnect mysql");</div><div class="line"> self.connect();</div><div class="line"> }</div><div class="line"> }</div><div class="line"> });</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>之前写过一个监控mysql数据库更新状态的预警程序,总是莫名其妙的报一个连接错误的错,然后程序死掉。后来在系统趋于稳定之后,我就没再继续维护这个工具了。</p>
<p>但是最近我在写另一个工具时,遇到了一个奇怪的问题,就是:tick总在27000多左右的时候崩溃。</p>
</summary>
<category term="JavaScript" scheme="http://www.z16388.top/tags/JavaScript/"/>
<category term="MySQL" scheme="http://www.z16388.top/tags/MySQL/"/>
</entry>
<entry>
<title>安卓应用闪屏</title>
<link href="http://www.z16388.top/2019/11/16/AndroidSplash/"/>
<id>http://www.z16388.top/2019/11/16/AndroidSplash/</id>
<published>2019-11-16T13:19:56.000Z</published>
<updated>2019-11-16T13:41:45.264Z</updated>
<content type="html"><![CDATA[<p>去年在接入安卓SDK时,会有部分渠道有要求手写闪屏的情况,下面是当时的笔记,这只是最简单的一种方法。</p>
<h1 id="参考资料:"><a href="#参考资料:" class="headerlink" title="参考资料:"></a>参考资料:</h1><p>很好的例子:</p>
<p><a href="https://www.jianshu.com/p/a609f510b19a" target="_blank" rel="external">https://www.jianshu.com/p/a609f510b19a</a></p>
<p><a href="https://blog.csdn.net/l799069596/article/details/47094731" target="_blank" rel="external">https://blog.csdn.net/l799069596/article/details/47094731</a></p>
<p>安卓动画:<a href="https://blog.csdn.net/IO_Field/article/details/53101499" target="_blank" rel="external">https://blog.csdn.net/IO_Field/article/details/53101499</a></p>
<h1 id="背景:"><a href="#背景:" class="headerlink" title="背景:"></a>背景:</h1><p>除去游戏本身的闪屏之外,有的渠道会要求,有额外的渠道闪屏。为了使用一套资源出不同渠道包,我们可以对接渠道的AS工程进行处理,单独设置闪屏。</p>
<p>首先,创建一个闪屏Activity,为你的主Activity,这样在游戏的一开始你就可以看到闪屏了。</p>
<p>这里需要注意的是,你原先的Activit也需要在Manifest中注册打开日志,否则在打包的时候会找不到,报错:</p>
<p><a href="https://blog.csdn.net/qq_28301007/article/details/52265775" target="_blank" rel="external">https://blog.csdn.net/qq_28301007/article/details/52265775</a></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">activity</span> <span class="attr">android:name</span>=<span class="string">"...Activity"</span>/></span></div></pre></td></tr></table></figure>
<p>下面是主Activity,也就是闪屏Activity的代码,需要根据AS的提示import缺少的部分。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> android.animation.ObjectAnimator;</div><div class="line"><span class="keyword">import</span> android.animation.ValueAnimator;</div><div class="line"><span class="keyword">import</span> android.app.Activity;</div><div class="line"><span class="keyword">import</span> android.content.Intent;</div><div class="line"><span class="keyword">import</span> android.os.Bundle;</div><div class="line"><span class="keyword">import</span> android.os.Handler;</div><div class="line"><span class="keyword">import</span> android.view.WindowManager;</div><div class="line"><span class="keyword">import</span> android.widget.ImageView;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SplashActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span> </span>{</div><div class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> TimeAnimDurning = <span class="number">2000</span>;</div><div class="line"> <span class="keyword">private</span> <span class="keyword">int</span> displayDeviceWidth;</div><div class="line"> ImageView iv_splash;</div><div class="line"> <span class="keyword">private</span> ObjectAnimator objAnim;</div><div class="line"></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</div><div class="line"> displayDeviceWidth = getResources().getDisplayMetrics().widthPixels;</div><div class="line"> setContentView(R.layout.activity_splash);</div><div class="line"> iv_splash = (ImageView) findViewById(R.id.splash);</div><div class="line"> objAnim = ObjectAnimator.ofFloat(iv_splash,<span class="string">"alpha"</span>,<span class="number">1</span>,<span class="number">0</span>);</div><div class="line"> objAnim.setDuration(TimeAnimDurning);</div><div class="line"></div><div class="line"> <span class="keyword">new</span> Handler().postDelayed(<span class="keyword">new</span> Runnable() {</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</div><div class="line"> objAnim.addUpdateListener(<span class="keyword">new</span> ValueAnimator.AnimatorUpdateListener() {</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onAnimationUpdate</span><span class="params">(ValueAnimator animation)</span> </span>{</div><div class="line"> <span class="keyword">if</span>((<span class="keyword">int</span>)animation.getAnimatedFraction() == <span class="number">1</span>){</div><div class="line"> getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);</div><div class="line"> startActivity(<span class="keyword">new</span> Intent(SplashActivity.<span class="keyword">this</span> , .YouActivity.class));</div><div class="line"> finish();</div><div class="line"> <span class="keyword">return</span> ;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> });</div><div class="line"> objAnim.start();</div><div class="line"> }</div><div class="line"></div><div class="line"> }, <span class="number">2000</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><span class="tag"><<span class="name">RelativeLayout</span></span></div><div class="line"> <span class="attr">xmlns:android</span>=<span class="string">"http://schemas.android.com/apk/res/android"</span></div><div class="line"> <span class="attr">xmlns:tools</span>=<span class="string">"http://schemas.android.com/tools"</span></div><div class="line"> <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></div><div class="line"> <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></div><div class="line"> <span class="attr">android:background</span>=<span class="string">"@color/white"</span></div><div class="line"> <span class="attr">tools:context</span>=<span class="string">"com.unity3d.player.SplashActivity"</span>></div><div class="line"></div><div class="line"><span class="tag"><<span class="name">LinearLayout</span></span></div><div class="line"> <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></div><div class="line"> <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></div><div class="line"> <span class="attr">android:visibility</span>=<span class="string">"visible"</span>></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">ImageView</span></span></div><div class="line"> <span class="attr">android:id</span>=<span class="string">"@+id/splash"</span></div><div class="line"> <span class="attr">android:layout_width</span>=<span class="string">"0dp"</span></div><div class="line"> <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></div><div class="line"> <span class="attr">android:layout_weight</span>=<span class="string">"1"</span></div><div class="line"> <span class="attr">android:scaleType</span>=<span class="string">"fitXY"</span></div><div class="line"> <span class="attr">android:src</span>=<span class="string">"@drawable/splash"</span> /></div><div class="line"></div><div class="line"><span class="tag"></<span class="name">LinearLayout</span>></span></div><div class="line"><span class="tag"></<span class="name">RelativeLayout</span>></span></div></pre></td></tr></table></figure>
<p>在上面控制闪屏格式的style.xml中,可以看到闪屏的背景色设置为了白色。这里有一些常用的颜色xml:<a href="https://blog.csdn.net/sundaysunshine/article/details/53509854" target="_blank" rel="external">https://blog.csdn.net/sundaysunshine/article/details/53509854</a></p>
<p>除了这两处之外,还需要根据style.xml中的配置,放好闪屏图片,设置闪屏背景。</p>
<p>整个闪屏的原理就是创建一个动画,在动画播放完成之后,去执行一个新的activity。在补全报错的部分之后,还是有一些细节部分需要注意的。</p>
<p>首先是结束时间的判定。判定时机总共有两种,一种是获取动画的进度,就像这里的例子,使用<code>(int)animation.getAnimatedFraction()</code>进行获取一个从0~1的数,来表示目前的动画的播放进度。除此之外还可以获取播放的时间,这个函数是:<code>getAnimatedValue()</code>,它可以获取属性的当前值。使用这两个函数可以很方便地控制动画的时间和动作。</p>
<p>除此之外,在调起另一个Activity之后,我结束了这个Activity。这是因为如果使用默认的LaunchMode,在重新唤醒应用时,闪屏会再次启动,然后走完动画,应用重启。这就造成了应用无法关闭的状况,只能后台强制杀掉。解决办法就是让闪屏只执行一次。</p>
]]></content>
<summary type="html">
<p>去年在接入安卓SDK时,会有部分渠道有要求手写闪屏的情况,下面是当时的笔记,这只是最简单的一种方法。</p>
<h1 id="参考资料:"><a href="#参考资料:" class="headerlink" title="参考资料:"></a>参考资料:</h1><p>
</summary>
<category term="Android" scheme="http://www.z16388.top/tags/Android/"/>
</entry>
<entry>
<title>安卓各渠道SDK接入体验</title>
<link href="http://www.z16388.top/2019/11/12/mostsdk/"/>
<id>http://www.z16388.top/2019/11/12/mostsdk/</id>
<published>2019-11-12T15:00:23.000Z</published>
<updated>2019-11-12T15:13:25.279Z</updated>
<content type="html"><![CDATA[<p>去年的这个时候,我在忙于接入各种SDK。接渠道SDK,是一件十分薛定谔的事情。你觉得很容易,的确很容易,但是,也很容易遇到问题。然后我就陷入了长期的自闭状态,再加上偷懒,然后博客就断更了一年。现在回头来回忆一下,去年的这个时候,接入SDK时的那些体验。</p>
<blockquote>
<p>1.酷派</p>
</blockquote>
<p>充值之后,服务器收不到消息,对接也没有人。</p>
<p>现在看来很明显,已然黄了。</p>
<blockquote>
<p>2.应用宝</p>
</blockquote>
<p>传说中的5000人大群只有2个技术的大渠道。每天上午问问题会施舍你两句,下午是肯定不会回答问题的,团建能团建半个月。这个渠道我是使用聚合sdk接入的。需要注意的是,接入时有测试阶段,和正式阶段之分,游戏货币名不能修改,同时还必须接入腾讯的信鸽推送SDK,否则无法过审,手动接入成本极高。</p>
<blockquote>
<p>3.金立</p>
</blockquote>
<p>高版本会造成初次进入闪退,主动获取权限也不行,必须低版本编译。<br>华为手机会出现渲染错误,游戏变成紫红色。<br>需要安装支付插件。<br>现在也应该没有接入的必要了。</p>
<blockquote>
<p>4.华为</p>
</blockquote>
<p>相当棒的渠道,文档详细,对接起来体验也很不错。充值错误的时候,每一步骤,原因都会有显示。<br>但是不支持第三方工具接入。<br>需要安装支付插件。</p>
<blockquote>
<p>5.魅族</p>
</blockquote>
<p>商品id配置不明,会出现莫名的变动,很不靠谱。<br>支付回调生效需要1天的时间,需要对商品进行映射,对接很麻烦的渠道。<br>需要安装支付插件。</p>
<blockquote>
<p>6.360</p>
</blockquote>
<p>包体最大,足足有50多k的方法数,不分包就是死。</p>
<blockquote>
<p>7.百度</p>
</blockquote>
<p>方法数排名第二,仅次于360。<br>高版本编译会无法使用闪屏。<br>提审体验极差。说好的SDK不强用更,但是等到提审后告诉你不合格。</p>
<blockquote>
<p>8.联想</p>
</blockquote>
<p>商品id为自动生成,需要做好映射。<br>AnySDK接入需要注意参数顺序。</p>
<blockquote>
<p>9.UC</p>
</blockquote>
<p>无法使用第三方工具进行接入。<br>闪屏比较蛋疼,在sdk初始化时自动播放。首次运行时无法正常显示,时机不一定,容易和应用闪屏覆盖。</p>
<blockquote>
<p>10.OPPO、VIVO</p>
</blockquote>
<p>无法使用第三方工具进行接入。<br>需要安装支付插件。</p>
<blockquote>
<p>11.小七</p>
</blockquote>
<p>文档描述不明确,注意对登陆回调的处理方式,注重切换账号的测试。<br>SDK的Manifest中,最高宽高比设置为2.2。如果游戏中有对这个参数进行修改,需要进行统一。</p>
<blockquote>
<p>12.拇指玩</p>
</blockquote>
<p>sdk默认背景为透明,会造成有些版本的手机唤起sdk时会显示桌面为背景。或者是切换到主屏后,再回来,只有单独的sdk页面。<br>解决方式是把style.xml中的windowIsTranslucent值置为为false。<br>回调处理方式与其他sdk略有不同,Log与执行功能部分的代码进行了分离。<br>目前版本,无法使用qq登陆等方式,在登陆界面仍没有去掉该入口。</p>
<blockquote>
<p>其他:</p>
</blockquote>
<p>在运营过程中,小米、UC、应用宝和魅族会不同频率出现无法登录的问题,属正常现象,是他们的SDK服务器抽风了,会报一些很可怕的错误,比如应用不存在,应用id无效之类的。这时候只需要稳定好用户的心态即可,没有任何解决办法。 </p>
]]></content>
<summary type="html">
<p>去年的这个时候,我在忙于接入各种SDK。接渠道SDK,是一件十分薛定谔的事情。你觉得很容易,的确很容易,但是,也很容易遇到问题。然后我就陷入了长期的自闭状态,再加上偷懒,然后博客就断更了一年。现在回头来回忆一下,去年的这个时候,接入SDK时的那些体验。</p>
<block
</summary>
<category term="Android" scheme="http://www.z16388.top/tags/Android/"/>
</entry>
<entry>
<title>某微信爬虫工具多开方案</title>
<link href="http://www.z16388.top/2019/11/12/most_wechat/"/>
<id>http://www.z16388.top/2019/11/12/most_wechat/</id>
<published>2019-11-12T13:15:53.000Z</published>
<updated>2019-11-12T13:28:07.569Z</updated>
<content type="html"><![CDATA[<p>之前因为需求找到了这个超级好用的微信爬虫工具<a href="https://github.com/striver-ing/wechat-spider" target="_blank" rel="external">https://github.com/striver-ing/wechat-spider</a>,目前已经开源。工具可以很方便地实现爬取微信文章,获取点赞、评论等功能。</p>
<p>最近,微信针对文章历史接口做了调整:PC版限制了爬取的次数,访问间隔应该控制在8分钟以上,移动端则是在两个月前直接干掉了这个功能。文章评论则没有改变。因此,这个工具目前最好的使用方式就是多开,分别爬不同的文章,再单开一个用来爬需要爬的评论。</p>
<p>工具的具体使用方法在原工程中都有提到,这里就不再赘述了。</p>
<p>在工具的使用方法中,我们知道,作者是使用全局代理,将所有的https消息都强制走了本机的8080端口,然后通过Python的mitmproxy来截取消息内容来实现的这个工具。那么,我可以使用局部代理,将制定的微信客户端,走制定端口,即可实现工具的多开。</p>
<p>有了这个思路,那么我们就只需要解决两个问题:</p>
<ol>
<li>微信的多开</li>
<li>多个微信走多个局部代理</li>
</ol>
<p>这里先说一下,我们无法使用微信PC客户端自带的代理功能。因为一旦这个功能开启,微信的所有链接都将进行加密,你得到的只会是一个格式如:<code><a href="https://xxx.xxx.xx.xx/mmtls/xxxxxx" target="_blank" rel="external">https://xxx.xxx.xx.xx/mmtls/xxxxxx</a></code>的加密链接。</p>
<h1 id="微信的多开"><a href="#微信的多开" class="headerlink" title="微信的多开"></a>微信的多开</h1><p>微信多开的实现比较简单,直接使用bat脚本打开多个微信即可。需要注意的是,要以管理员模式运行。</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">@<span class="built_in">echo</span> off</div><div class="line">start /d <span class="string">"C:\Program Files (x86)\Tencent\WeChat\" WeChat.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChat\<span class="string">" WeChat.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChat\<span class="string">" WeChat.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChat\<span class="string">" WeChat.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChat\<span class="string">" WeChat.exe</span></div><div class="line">exit</div></pre></td></tr></table></figure>
<p>这样虽然可以打开多个微信,但是在设置局部代理时,工具无法区相同路径下的相同可执行文件。因此,我们需要把微信客户端拷贝多份,以应对后面的步骤。</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">@<span class="built_in">echo</span> off</div><div class="line">start /d <span class="string">"C:\Program Files (x86)\Tencent\WeChat\" WeChat.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChatb\<span class="string">" WeChatb.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChatc\<span class="string">" WeChatc.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChatd\<span class="string">" WeChatd.exe</span></div><div class="line">start /d "C:\Program Files (x86)\Tencent\WeChate\<span class="string">" WeChate.exe</span></div><div class="line">exit</div></pre></td></tr></table></figure>
<p>需要注意的是,这样配置之后的脚本将不一定百分百执行成功,可能只打开一个客户端。一般第二次即可执行成功。</p>
<h1 id="局部代理"><a href="#局部代理" class="headerlink" title="局部代理"></a>局部代理</h1><p>这里,我使用了Proxifier工具,进行局部代理。这个工具很容易获取,x度上很容易就可以获取到免费破解汉化的版本。</p>
<p>安装之后,我们开始配置工作。</p>
<blockquote>
<p>1.配置文件->代理服务器 这里地址填本机127.0.0.1,端口填你想要转发的端口,比如8080,8081,协议类型是HTTPS。你想开多少,就填多少个。</p>
<p><img src="https://raw.githubusercontent.com/z16388/blog_pic/master/15735574693277.png" alt="图1"><br><img src="https://raw.githubusercontent.com/z16388/blog_pic/master/15735574693607.png" alt="图2"></p>
<p>2.配置文件->代理规则 这里我们把默认的全局代理给关闭,双击条目,将“是否有效”取消勾选即可。然后添加微信的代理规则,点击添加,名称随意,应用程序浏览到微信的exe文件,目标主机清空,端口清空,然后在最下方的动作中选择你上一步配置的一个端口。那么这个路径下的客户端执行时,便会代理到这个端口下了。</p>
<p><img src="https://raw.githubusercontent.com/z16388/blog_pic/master/15735574693777.png" alt="图3"><br><img src="https://raw.githubusercontent.com/z16388/blog_pic/master/15735574694007.png" alt="图4"></p>
</blockquote>
<p>微信多开之后,我们会发现多开的这几个的微信的进程名是一样的,无法进行区分。这时候可以在任务管理器中使用切换到、最小化等功能确定哪个窗口是哪个进程,转到本地文件来确定他是哪个目录下的。在开多个的时候,一定要注意区分,以防登错账号,影响爬取。</p>
<p>爬虫的配置文件中,我们最好使用不同的mysql数据库,以免产影响。当然,如果你修改了原工具的代码,那就另当别论了。</p>
]]></content>
<summary type="html">
<p>之前因为需求找到了这个超级好用的微信爬虫工具<a href="https://github.com/striver-ing/wechat-spider" target="_blank" rel="external">https://github.com/striver-in
</summary>
<category term="微信" scheme="http://www.z16388.top/tags/%E5%BE%AE%E4%BF%A1/"/>
<category term="爬虫" scheme="http://www.z16388.top/tags/%E7%88%AC%E8%99%AB/"/>
</entry>
<entry>
<title>U3D问题总结(七) lua</title>
<link href="http://www.z16388.top/2019/10/29/unity7/"/>
<id>http://www.z16388.top/2019/10/29/unity7/</id>
<published>2019-10-29T15:00:07.000Z</published>
<updated>2020-10-30T08:41:14.658Z</updated>
<content type="html"><![CDATA[<h2 id="lua实现类的继承"><a href="#lua实现类的继承" class="headerlink" title="lua实现类的继承"></a>lua实现类的继承</h2><h2 id="lua遍历查找某个数"><a href="#lua遍历查找某个数" class="headerlink" title="lua遍历查找某个数"></a>lua遍历查找某个数</h2>]]></content>
<summary type="html">
<h2 id="lua实现类的继承"><a href="#lua实现类的继承" class="headerlink" title="lua实现类的继承"></a>lua实现类的继承</h2><h2 id="lua遍历查找某个数"><a href="#lua遍历查找某个数" cla
</summary>
<category term="Unity" scheme="http://www.z16388.top/tags/Unity/"/>
</entry>
<entry>
<title>U3D问题总结(六) 优化</title>
<link href="http://www.z16388.top/2019/10/29/unity6/"/>
<id>http://www.z16388.top/2019/10/29/unity6/</id>
<published>2019-10-29T15:00:06.000Z</published>
<updated>2020-10-30T04:31:19.171Z</updated>
<content type="html"><![CDATA[<h2 id="请简述GC(垃圾回收)产生的原因,并描述如何避免(?"><a href="#请简述GC(垃圾回收)产生的原因,并描述如何避免(?" class="headerlink" title="请简述GC(垃圾回收)产生的原因,并描述如何避免(?"></a>请简述GC(垃圾回收)产生的原因,并描述如何避免(?</h2><blockquote>
<p>GC回收堆上的内存<br>避免:1.减少new产生对象的次数<br>2.使用公用的对象(静态成员)<br>3.将String换为StringBuilder</p>
</blockquote>
<h2 id="如何优化内存?"><a href="#如何优化内存?" class="headerlink" title="如何优化内存?"></a>如何优化内存?</h2><blockquote>
<p>1.压缩自带类库;<br>2.将暂时不用的以后还需要使用的物体隐藏起来而不是直接Destroy掉;<br>3.释放AssetBundle占用的资源;<br>4.降低模型的片面数,降低模型的骨骼数量,降低贴图的大小;<br>5.使用光照贴图,使用多层次细节(LOD),使用着色器(Shader),使用预设(Prefab)。<br>6.代码中少产生临时变量</p>
</blockquote>
<h2 id="UNITY3d在移动设备上的一些优化资源的方法"><a href="#UNITY3d在移动设备上的一些优化资源的方法" class="headerlink" title="UNITY3d在移动设备上的一些优化资源的方法"></a>UNITY3d在移动设备上的一些优化资源的方法</h2><blockquote>
<p>1.使用assetbundle,实现资源分离和共享,将内存控制到200m之内,同时也可以实现资源的在线更新<br>2.顶点数对渲染无论是cpu还是gpu都是压力最大的贡献者,降低顶点数到8万以下,fps稳定到了30帧左右<br>3.只使用一盏动态光,不是用阴影,不使用光照探头<br>粒子系统是cpu上的大头<br>4.剪裁粒子系统<br>5.合并同时出现的粒子系统<br>6.自己实现轻量级的粒子系统<br>animator也是一个效率奇差的地方<br>7.把不需要跟骨骼动画和动作过渡的地方全部使用animation,控制骨骼数量在30根以下<br>8.animator出视野不更新<br>9.删除无意义的animator<br>10.animator的初始化很耗时(粒子上能不能尽量不用animator)<br>11.除主角外都不要跟骨骼运动apply root motion<br>12.绝对禁止掉那些不带刚体带包围盒的物体(static collider )运动<br>NUGI的代码效率很差,基本上runtime的时候对cpu的贡献和render不相上下<br>13每帧递归的计算finalalpha改为只有初始化和变动时计算<br>14去掉法线计算<br>15不要每帧计算viewsize 和windowsize<br>16filldrawcall时构建顶点缓存使用array.copy<br>17.代码剪裁:使用strip level ,使用.net2.0 subset<br>18.尽量减少smooth group<br>19.给美术定一个严格的经过科学验证的美术标准,并在U3D里面配以相应的检查工具</p>
</blockquote>
<h2 id="场景优化"><a href="#场景优化" class="headerlink" title="场景优化"></a>场景优化</h2><blockquote>
<p>1.遮挡剔除(Occlusion Culling) 不显示被遮挡住的物体<br>2.LOD 根据相机距离远近显示不同精细程度的模型<br>3.大场景可以调节相机可视距离<br>4.小物体可以适当隐藏掉<br>5.使用光照贴图 避免动态实时的进行光照计算,提高效率</p>
</blockquote>
<h2 id="UI优化"><a href="#UI优化" class="headerlink" title="UI优化"></a>UI优化</h2><blockquote>
<p>1.将同一画面图片放到同一图集中<br>2.图片和文字尽量不要交叉,会产生多余drawcall(相同材质和纹理的UI元素是可以合并的)<br>3.UI层级尽量不要重叠太多<br>4.取消勾选不必要的射线检测RaycastTarget<br>5.将动态的UI元素和静态的UI元素放在不同的Canvas中,减少canvas网格重构频率</p>
</blockquote>
<h2 id="GC优化"><a href="#GC优化" class="headerlink" title="GC优化"></a>GC优化</h2><blockquote>
<p>1.字符串使用StringBuilder而不是string,stringBuilder在创建时会自动获取一个容量存储并逐渐扩充,string每一次改变都会创建一个新的对象。<br>2.访问物体tag的时候尽量使用Gameobject.CompareTag(),因为访问物体的tag属性会在堆上额外的分配空间<br>3.使用对象池缓存大量创建的物体<br>4.用for代替foreach,foreach每次迭代产生24字节垃圾内存</p>
</blockquote>
]]></content>
<summary type="html">
<h2 id="请简述GC(垃圾回收)产生的原因,并描述如何避免(?"><a href="#请简述GC(垃圾回收)产生的原因,并描述如何避免(?" class="headerlink" title="请简述GC(垃圾回收)产生的原因,并描述如何避免(?"></a>请简述GC(垃圾
</summary>
<category term="Unity" scheme="http://www.z16388.top/tags/Unity/"/>
</entry>
<entry>
<title>U3D问题总结(五) 渲染与光照</title>
<link href="http://www.z16388.top/2019/10/29/unity5/"/>
<id>http://www.z16388.top/2019/10/29/unity5/</id>
<published>2019-10-29T15:00:05.000Z</published>
<updated>2020-11-08T15:10:55.122Z</updated>
<content type="html"><![CDATA[<h2 id="什么是渲染管道(?"><a href="#什么是渲染管道(?" class="headerlink" title="什么是渲染管道(?"></a>什么是渲染管道(?</h2><blockquote>
<p>是指在显示器上为了显示出图像而经过的一系列必要操作。 渲染管道中的很多步骤,都要将几何物体从一个坐标系中变换到另一个坐标系中去。主要步骤有:<br>本地坐标->视图坐标->背面裁剪->光照->裁剪->投影->视图变换->光栅化</p>
</blockquote>
<h2 id="对渲染管线的理解"><a href="#对渲染管线的理解" class="headerlink" title="对渲染管线的理解"></a>对渲染管线的理解</h2><blockquote>
<p>渲染流水线流程:<br>1.应用阶段(由CPU负责,输出是渲染所需要的几何信息,即渲染图元。然后发起Draw Call,进入GPU流水线)<br>2.几何阶段(由GPU负责,处理渲染图元,这阶段中最重要的就是把顶点坐标变换屏幕空间中,交给光栅器处理<br>这阶段输出的是屏幕空间中二维顶点坐标、每个顶点对应的深度值、着色等相关信息)<br>3.光栅化阶段(由GPU,负责这一阶段会使用上个阶段传递的数据来产生屏幕上的像素,并渲染出最终的图像)<br>细节过程<a href="https://zhuanlan.zhihu.com/p/97498781" target="_blank" rel="external">https://zhuanlan.zhihu.com/p/97498781</a></p>
</blockquote>
<h2 id="什么是DrawCall?DrawCall高了又什么影响?如何降低DrawCall?"><a href="#什么是DrawCall?DrawCall高了又什么影响?如何降低DrawCall?" class="headerlink" title="什么是DrawCall?DrawCall高了又什么影响?如何降低DrawCall?"></a>什么是DrawCall?DrawCall高了又什么影响?如何降低DrawCall?</h2><blockquote>
<p>Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw Call。DrawCall越高对显卡的消耗就越大。降低DrawCall的方法:</p>
<ol>
<li>Dynamic Batching</li>
<li>Static Batching</li>
<li>高级特性Shader降级为统一的低级特性的Shader。</li>
</ol>
</blockquote>
<h2 id="什么是DrawCall,有什么方法可以减少DrawCall"><a href="#什么是DrawCall,有什么方法可以减少DrawCall" class="headerlink" title="什么是DrawCall,有什么方法可以减少DrawCall"></a>什么是DrawCall,有什么方法可以减少DrawCall</h2><blockquote>
<p>CPU通过调用绘制命令来告诉GPU开始进行一个渲染过程(一次DrawCall)。<br>CPU方面减少DrawCall:<br>1、使用Draw Call Batching 、Dynamic Batching动态批处理<br>2、纹理打包成图集减少材质使用<br>3、少用反光、阴影<br>4、设置一个合适的Fixed Timestep<br>5、不要使用网格碰撞器(Mesh Collider)<br>6、大量或频繁的字符串连接操作一定要用StringBuilder<br>7、某些可能情况,使用结构体代替类<br>8、使用对象池重复利用空间<br>9、尽量不要用foreach,用for<br>10、不要直接访问GameObjcet的tag属性<br>11、不要频繁使用GetComponent,访问一次后保留其引用<br>12、使用OnBecameVisible()和OnBecameInVisible(),控制物体update()函数的执行减少开销<br>13、使用内建数组,如Vector3.zero而不是new Vector3(0,0,0)<br>14、使用ref关键字对方法的参数进行优化<br>15、关闭所有update中的log操作<br>16、不在update中调用GetComponent、SendMessage、FindWithTag等方法<br>17、不在update中使用临时变量</p>
</blockquote>
<h2 id="GPU方面减少DrawCall"><a href="#GPU方面减少DrawCall" class="headerlink" title="GPU方面减少DrawCall"></a>GPU方面减少DrawCall</h2><blockquote>
<p>1、使用纹理图集代替一系列单独小贴图<br>2、保持材质数目尽可能少<br>3、如果使用纹理图集和共享材质,用Renderer.sharedMaterial代替Renderer.material<br>4、使用光照纹理(lightmap)而非实时灯光<br>5、使用LOD<br>6、使用mobile版的shader<br>7、尽可能减少顶点数、背面删减<br>8、压缩图片,减少显存带宽压力</p>
</blockquote>
<h2 id="什么是material,什么是shader,二者有什么关系"><a href="#什么是material,什么是shader,二者有什么关系" class="headerlink" title="什么是material,什么是shader,二者有什么关系"></a>什么是material,什么是shader,二者有什么关系</h2><blockquote>
<p>材质系统定义了如何渲染物件表面信息。shader里面使用材质信息加自身操作,最终呈现物体渲染。shader是material一部分,是根据计算即时演算生成贴图的程序,叫着色器。常用处理无法用固定贴图表现的模型。material是模型的材质,包含贴图、shader、顶点、凹凸等信息。</p>
</blockquote>
<h2 id="如何在Unity3D中查看场景的面数,顶点数和Draw-Call数?如何降低Draw-Call数"><a href="#如何在Unity3D中查看场景的面数,顶点数和Draw-Call数?如何降低Draw-Call数" class="headerlink" title="如何在Unity3D中查看场景的面数,顶点数和Draw Call数?如何降低Draw Call数"></a>如何在Unity3D中查看场景的面数,顶点数和Draw Call数?如何降低Draw Call数</h2><blockquote>
<p>在Game视图右上角点击Stats。降低Draw Call 的技术是Draw Call Batching<br>这个在5.0以后在window-》Profiler下面,快捷键是cmd + 7(ctl + 7</p>
</blockquote>
<h2 id="DrawCall和SetPass-Call"><a href="#DrawCall和SetPass-Call" class="headerlink" title="DrawCall和SetPass Call"></a>DrawCall和SetPass Call</h2><blockquote>
<p>DrawCall:meshes网格绘制应用批处理后的总数。请注意,在多次呈现对象(例如,由像素灯照明的对象),每个在一个单独的渲染结果绘制调用。</p>
<p>SetPass Call:渲染改变( passes)次数。每个改变 需要Unity运行时绑定一个新的渲染器(shader),它可能会引入 CPU 开销。</p>
</blockquote>
<h2 id="Unity3D-Shader分哪几种,有什么区别"><a href="#Unity3D-Shader分哪几种,有什么区别" class="headerlink" title="Unity3D Shader分哪几种,有什么区别"></a>Unity3D Shader分哪几种,有什么区别</h2><blockquote>
<p>表面着色器的抽象层次比较高,它可以轻松地以简洁方式实现复杂着色。表面着色器可同时在前向渲染及延迟渲染模式下正常工作。<br>顶点片段着色器可以非常灵活地实现需要的效果,但是需要编写更多的代码,并且很难与Unity的渲染管线完美集成。<br>固定功能管线着色器可以作为前两种着色器的备用选择,当硬件无法运行那些酷炫Shader的时,还可以通过固定功能管线着色器来绘制出一些基本的内容。</p>
</blockquote>
<h2 id="有A和B两组物体,有什么办法能够保证A组物体永远比B组物体先渲染?"><a href="#有A和B两组物体,有什么办法能够保证A组物体永远比B组物体先渲染?" class="headerlink" title="有A和B两组物体,有什么办法能够保证A组物体永远比B组物体先渲染?"></a>有A和B两组物体,有什么办法能够保证A组物体永远比B组物体先渲染?</h2><blockquote>
<p>把A组物体的渲染队列大于B物体的渲染队列,通过shader里面的渲染队列来渲染</p>
</blockquote>
<h2 id="问一个Terrain,分别贴3张,4张,5张地表贴图,渲染速度有什么区别?为什么?"><a href="#问一个Terrain,分别贴3张,4张,5张地表贴图,渲染速度有什么区别?为什么?" class="headerlink" title="问一个Terrain,分别贴3张,4张,5张地表贴图,渲染速度有什么区别?为什么?"></a>问一个Terrain,分别贴3张,4张,5张地表贴图,渲染速度有什么区别?为什么?</h2><blockquote>
<p>没有区别,因为不管几张贴图只渲染一次。</p>
</blockquote>
<h2 id="LOD是什么,优缺点"><a href="#LOD是什么,优缺点" class="headerlink" title="LOD是什么,优缺点(?"></a>LOD是什么,优缺点(?</h2><blockquote>
<p>LOD(Level of detail)多层次细节,是最常用的游戏优化技术。它按照模型的位置和重要程度决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。缺点是增加了内存。</p>
</blockquote>
<h2 id="MipMap是什么,作用"><a href="#MipMap是什么,作用" class="headerlink" title="MipMap是什么,作用(?"></a>MipMap是什么,作用(?</h2><blockquote>
<p>MipMapping:在三维计算机图形的贴图渲染中有常用的技术,为加快渲染进度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件,这样的贴图被称为MipMap。</p>
</blockquote>
<h2 id="什么是LightMap"><a href="#什么是LightMap" class="headerlink" title="什么是LightMap"></a>什么是LightMap</h2><blockquote>
<p>LightMap:就是指在三维软件里实现打好光,然后渲染把场景各表面的光照输出到贴图上,最后又通过引擎贴到场景上,这样就使物体有了光照的感觉。</p>
</blockquote>
<h2 id="alpha-blend工作原理"><a href="#alpha-blend工作原理" class="headerlink" title="alpha blend工作原理"></a>alpha blend工作原理</h2><blockquote>
<p>Alpha Blend 实现透明效果,不过只能针对某块区域进行alpha操作,透明度可设。</p>
<p>alpha blend 用于做半透明效果。Color = (源颜色 <em> 源系数) OP ( 目标颜色</em> 目标系数);其中OP(混合方式)有加,减,反减,取最小,取最大</p>
</blockquote>
<h2 id="Unity的Shader中,Blend-SrcAlpha-OneMinusSrcAlpha这句话是什么意思"><a href="#Unity的Shader中,Blend-SrcAlpha-OneMinusSrcAlpha这句话是什么意思" class="headerlink" title="Unity的Shader中,Blend SrcAlpha OneMinusSrcAlpha这句话是什么意思"></a>Unity的Shader中,Blend SrcAlpha OneMinusSrcAlpha这句话是什么意思</h2><blockquote>
<p>作用就是Alpha混合。公式:最终颜色 = 源颜色 x 源透明值 + 目标颜色 x(1 - 源透明值)</p>
</blockquote>
<h2 id="alpha-test在何时使用?能达到什么效果"><a href="#alpha-test在何时使用?能达到什么效果" class="headerlink" title="alpha test在何时使用?能达到什么效果"></a>alpha test在何时使用?能达到什么效果</h2><blockquote>
<p>Alpha Test ,中文就是透明度测试。简而言之就是V&F shader中最后fragment函数输出的该点颜色值(即上一讲frag的输出half4)的alpha值与固定值进行比较。AlphaTest语句通常于Pass{}中的起始位置。Alpha Test产生的效果也很极端,要么完全透明,即看不到,要么完全不透明。</p>
</blockquote>
<h2 id="Vertex-Shader是什么,怎么计算"><a href="#Vertex-Shader是什么,怎么计算" class="headerlink" title="Vertex Shader是什么,怎么计算"></a>Vertex Shader是什么,怎么计算</h2><blockquote>
<p>顶点着色器是一段执行在GPU上的程序,用来取代fixed pipeline中的transformation和lighting,Vertex Shader主要操作顶点。<br>Vertex Shader对输入顶点完成了从local space到homogeneous space(齐次空间)的变换过程,homogeneous space即projection space的下一个space。在这其间共有world transformation, view transformation和projection transformation及lighting几个过程。</p>
</blockquote>
<h2 id="写出光照计算中的diffuse(漫反射)的计算公式"><a href="#写出光照计算中的diffuse(漫反射)的计算公式" class="headerlink" title="写出光照计算中的diffuse(漫反射)的计算公式"></a>写出光照计算中的diffuse(漫反射)的计算公式</h2><blockquote>
<p>diffuse = Kd x colorLight x max(N*L,0);<br>Kd 漫反射系数、colorLight 光的颜色、N 单位法线向量、L 由点指向光源的单位向量、其中N与L点乘,如果结果小于等于0,则漫反射为0。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line">答:漫反射光(diffuse)计算公式为:Idiffuse = Dintensity*Dcolor*N.L ; (Dintensity表示漫反射强度,Dcolor表示漫反射光颜色,N为该点的法向量,L为光源向量)</div><div class="line"></div><div class="line"> 其他,3D渲染中,物体表面的光照计算公式为:</div><div class="line"></div><div class="line">I = 环境光(Iambient) + 漫反射光(Idiffuse) + 镜面高光(Ispecular);</div><div class="line"></div><div class="line"> 其中,环境光(ambient)计算公式为:</div><div class="line"></div><div class="line">Iambient= Aintensity* Acolor; (Aintensity表示环境光强度,Acolor表示环境光颜色)</div><div class="line"></div><div class="line"> 漫反射光(diffuse)计算公式为:</div><div class="line"></div><div class="line">Idiffuse = Dintensity*Dcolor*N.L ; (Dintensity表示漫反射强度,Dcolor表示漫反射光颜色,N为该点的法向量,L为光源向量)</div><div class="line"></div><div class="line">镜面光照(specular)计算公式为:</div><div class="line"></div><div class="line">Ispecular = Sintensity*Scolor*(R.V)n; (Sintensity表示镜面光照强度,Scolor表示镜面光颜色,R为光的反射向量,V为观察者向量)</div><div class="line"></div><div class="line">综上所得:整个光照公式为:</div><div class="line"></div><div class="line">I = Aintensity* Acolor+ Dintensity*Dcolor*N.L + Sintensity*Scolor*(R.V)n ;</div><div class="line"></div><div class="line">将一些值合并,并使用白色作为光照颜色,则上述公式可简化为:</div><div class="line"></div><div class="line">I = A + D*N.L + (R.V)n</div></pre></td></tr></table></figure>
<h2 id="MeshRender中material和sharedmaterial的区别"><a href="#MeshRender中material和sharedmaterial的区别" class="headerlink" title="MeshRender中material和sharedmaterial的区别(?"></a>MeshRender中material和sharedmaterial的区别(?</h2><blockquote>
<p>修改sharedMaterial将改变所有物体使用这个材质的外观,并且也改变储存在工程里的材质设置。不推荐修改由sharedMaterial返回的材质。如果你想修改渲染器的材质,使用material替代。</p>
</blockquote>
<h1 id="简述水面倒影的渲染原理"><a href="#简述水面倒影的渲染原理" class="headerlink" title="简述水面倒影的渲染原理"></a>简述水面倒影的渲染原理</h1><blockquote>
<p>原理就是对水面的贴图纹理进行扰动,以产生波光玲玲的效果。用shader可以通过GPU在像素级别作扰动,效果细腻,需要的顶点少,速度快</p>
</blockquote>
<h2 id="什么叫动态合批?跟静态合批有什么区别"><a href="#什么叫动态合批?跟静态合批有什么区别" class="headerlink" title="什么叫动态合批?跟静态合批有什么区别"></a>什么叫动态合批?跟静态合批有什么区别</h2><blockquote>
<p>如果动态物体共用着相同的材质,那么Unity会自动对这些物体进行批处理。动态批处理操作是自动完成的,并不需要你进行额外的操作。<br>区别:动态批处理一切都是自动的,不需要做任何操作,而且物体是可以移动的,但是限制很多。静态批处理:自由度很高,限制很少,缺点可能会占用更多的内存,而且经过静态批处理后的所有物体都不可以再移动了。</p>
</blockquote>
<h2 id="两种阴影判断的方法、工作原理。"><a href="#两种阴影判断的方法、工作原理。" class="headerlink" title="两种阴影判断的方法、工作原理。"></a>两种阴影判断的方法、工作原理。</h2><blockquote>
<p>本影:景物表面上那些没有被光源直接照射的区域(全黑的轮廓分明的区域)。<br>半影:景物表面上那些被某些特定光源直接照射但并非被所有特定光源直接照射的区域(半明半暗区域)<br>工作原理:从光源处向物体的所有可见面投射光线,将这些面投影到场景中得到投影面,再将这些投影面与场景中的其他平面求交得出阴影多边形,保存这些阴影多边形信息,然后再按视点位置对场景进行相应处理得到所要求的视图(利用空间换时间,每次只需依据视点位置进行一次阴影计算即可,省去了一次消隐过程)</p>
</blockquote>
<h2 id="Unity提供了几种光源,分别是什么"><a href="#Unity提供了几种光源,分别是什么" class="headerlink" title="Unity提供了几种光源,分别是什么"></a>Unity提供了几种光源,分别是什么</h2><blockquote>
<p>四种。<br>平行光:Directional Light<br>点光源:Point Light<br>聚光灯:Spot Light<br>区域光源:Area Light</p>
</blockquote>
<h2 id="实时点光源的优缺点是什么"><a href="#实时点光源的优缺点是什么" class="headerlink" title="实时点光源的优缺点是什么"></a>实时点光源的优缺点是什么</h2><blockquote>
<p>可以有cookies – 带有 alpha通道的立方图(Cubemap )纹理。点光源是最耗费资源的。</p>
</blockquote>
<h2 id="GPU的工作原理"><a href="#GPU的工作原理" class="headerlink" title="GPU的工作原理"></a>GPU的工作原理</h2><blockquote>
<p>简而言之,GPU的图形(处理)流水线完成如下的工作:(并不一定是按照如下顺序) 顶点处理:这阶段GPU读取描述3D图形外观的顶点数据并根据顶点数据确定3D图形的形状及位置关系,建立起3D图形的骨架。在支持DX8和DX9规格的GPU中,这些工作由硬件实现的Vertex Shader(定点着色器)完成。 光栅化计算:显示器实际显示的图像是由像素组成的,我们需要将上面生成的图形上的点和线通过一定的算法转换到相应的像素点。把一个矢量图形转换为一系列像素点的过程就称为光栅化。例如,一条数学表示的斜线段,最终被转化成阶梯状的连续像素点。 纹理帖图:顶点单元生成的多边形只构成了3D物体的轮廓,而纹理映射(texture mapping)工作完成对多变形表面的帖图,通俗的说,就是将多边形的表面贴上相应的图片,从而生成“真实”的图形。TMU(Texture mapping unit)即是用来完成此项工作。 像素处理:这阶段(在对每个像素进行光栅化处理期间)GPU完成对像素的计算和处理,从而确定每个像素的最终属性。在支持DX8和DX9规格的GPU中,这些工作由硬件实现的Pixel Shader(像素着色器)完成。 最终输出:由ROP(光栅化引擎)最终完成像素的输出,1帧渲染完毕后,被送到显存帧缓冲区。<br>总结:GPU的工作通俗的来说就是完成3D图形的生成,将图形映射到相应的像素点上,对每个像素进行计算确定最终颜色并完成输出。</p>
</blockquote>
<h1 id="图形学"><a href="#图形学" class="headerlink" title="图形学"></a>图形学</h1><h2 id="光照模型有哪些"><a href="#光照模型有哪些" class="headerlink" title="光照模型有哪些"></a>光照模型有哪些</h2><h2 id="3维模型组成"><a href="#3维模型组成" class="headerlink" title="3维模型组成"></a>3维模型组成</h2><p>Mesh</p>
<h2 id="Mesh下面有哪些字段"><a href="#Mesh下面有哪些字段" class="headerlink" title="Mesh下面有哪些字段"></a>Mesh下面有哪些字段</h2><h2 id="如向将文理贴在模型上"><a href="#如向将文理贴在模型上" class="headerlink" title="如向将文理贴在模型上"></a>如向将文理贴在模型上</h2><h2 id="图片向格式有那些"><a href="#图片向格式有那些" class="headerlink" title="图片向格式有那些"></a>图片向格式有那些</h2>]]></content>
<summary type="html">
<h2 id="什么是渲染管道(?"><a href="#什么是渲染管道(?" class="headerlink" title="什么是渲染管道(?"></a>什么是渲染管道(?</h2><blockquote>
<p>是指在显示器上为了显示出图像而经过的一系列必要操作。 渲染
</summary>
<category term="Unity" scheme="http://www.z16388.top/tags/Unity/"/>
</entry>
<entry>
<title>U3D问题总结(四) 物理相关</title>
<link href="http://www.z16388.top/2019/10/29/unity4/"/>
<id>http://www.z16388.top/2019/10/29/unity4/</id>
<published>2019-10-29T15:00:04.000Z</published>
<updated>2020-10-30T08:41:37.006Z</updated>
<content type="html"><![CDATA[<h2 id="射线检测碰撞物的原理是"><a href="#射线检测碰撞物的原理是" class="headerlink" title="射线检测碰撞物的原理是"></a>射线检测碰撞物的原理是</h2><blockquote>
<p>射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射 。</p>
</blockquote>
<h2 id="Unity3d中的碰撞器和触发器的区别?"><a href="#Unity3d中的碰撞器和触发器的区别?" class="headerlink" title="Unity3d中的碰撞器和触发器的区别?"></a>Unity3d中的碰撞器和触发器的区别?</h2><blockquote>
<p>碰撞器是触发器的载体,触发器是碰撞器的属性<br>Is Trigger=false,碰撞器根据物理引擎引发碰撞,产生碰撞的效果<br>此时调用OnCollisionEnter/Stay/Exit函数<br>Is Trigger=true,碰撞器被物理引擎所忽略,没有碰撞效果<br>此时调用OnTriggerEnter/Stay/Exit函数</p>
</blockquote>
<h2 id="发生碰撞的必要条件"><a href="#发生碰撞的必要条件" class="headerlink" title="发生碰撞的必要条件"></a>发生碰撞的必要条件</h2><blockquote>
<p>两个物体都必须带有碰撞器(Collider)<br>其中至少有一个物体带有刚体(Rigidbody)或者角色控制器(CharacController)<br>必须是运动的物体带有Rigidbody脚本才能检测到碰撞</p>
</blockquote>
<h2 id="物体发生碰撞的过程有几个阶段"><a href="#物体发生碰撞的过程有几个阶段" class="headerlink" title="物体发生碰撞的过程有几个阶段"></a>物体发生碰撞的过程有几个阶段</h2><blockquote>
<p>1.OnCollisionEnter<br>2.OnCollisionStay<br>3.OnCollisionExit</p>
</blockquote>
<h2 id="当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况?如何避免?"><a href="#当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况?如何避免?" class="headerlink" title="当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况?如何避免?"></a>当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况?如何避免?</h2><blockquote>
<p>穿透(碰撞检测失败)<br>1)增大细小物体的碰撞体(不建议这样做)<br>(2)使用射线检测,检测他们之间的距离<br>(3)FixedUpdate频率修改,可以physics time减小(同样不建议)<br>(4)改变物体的速度(废话)<br>(5)将检测方式改为连续检测,rigifdbody.collisionDetectionMode =CollisionDetectionMode.Continuous;<br>或者是动态连续检测(CollisionDetectionMode.ContinuousDynamic)<br>(6)代码限制,加大计算量 提前计算好下一个位置</p>
</blockquote>
<h2 id="Unity3d物理引擎中,有几种施加力的方式(?"><a href="#Unity3d物理引擎中,有几种施加力的方式(?" class="headerlink" title="Unity3d物理引擎中,有几种施加力的方式(?"></a>Unity3d物理引擎中,有几种施加力的方式(?</h2><blockquote>
<p>rigidbody.AddForce/AddForceAtPosition,都在rigidbody系列函数中</p>
</blockquote>
<h2 id="CharacterController和Rigdibody的区别"><a href="#CharacterController和Rigdibody的区别" class="headerlink" title="CharacterController和Rigdibody的区别"></a>CharacterController和Rigdibody的区别</h2><blockquote>
<p>Rigidbody:刚体组件、用于模拟真实的物理效果、可以受到重力和其他力的作用、这个力可以直接施加、也可以来自其他刚体的碰撞<br>CharacterController:角色控制组件,它自带一个胶囊控制器,能够受到重力的影响。移动时使用自身的Move()、SimpleMove()方法</p>
<p>Rigidbody具有完全真实物理的特性,Unity中物理系统最基本的一个组件,包含了常用的物理特性,而CharacterController可以说是受限的的Rigidbody,具有一定的物理效果但不是完全真实的,是Unity为了使开发者能方便的开发第一人称视角的游戏而封装的一个组件</p>
</blockquote>
<h2 id="什么叫做链条关节-?"><a href="#什么叫做链条关节-?" class="headerlink" title="什么叫做链条关节(?"></a>什么叫做链条关节(?</h2><blockquote>
<p>Hinge Joint,可以模拟两个物体间用一根链条连接在一起的情况,能保持两个物体在一个固定距离内部相互移动而不产生作用力,但是达到固定距离后就会产生拉力。</p>
</blockquote>
]]></content>
<summary type="html">
<h2 id="射线检测碰撞物的原理是"><a href="#射线检测碰撞物的原理是" class="headerlink" title="射线检测碰撞物的原理是"></a>射线检测碰撞物的原理是</h2><blockquote>
<p>射线是3D世界中一个点向一个方向发射的一条
</summary>
<category term="Unity" scheme="http://www.z16388.top/tags/Unity/"/>
</entry>
<entry>
<title>U3D问题总结(三) Unity基础</title>
<link href="http://www.z16388.top/2019/10/29/unity3/"/>
<id>http://www.z16388.top/2019/10/29/unity3/</id>
<published>2019-10-29T15:00:03.000Z</published>
<updated>2020-10-30T09:46:16.673Z</updated>
<content type="html"><![CDATA[<h1 id="Unity基础"><a href="#Unity基础" class="headerlink" title="Unity基础"></a>Unity基础</h1><h2 id="Unity和Android与iOS如何交互"><a href="#Unity和Android与iOS如何交互" class="headerlink" title="Unity和Android与iOS如何交互"></a>Unity和Android与iOS如何交互</h2><blockquote>
<p>Unity可以导出安卓和IOS的工程。导出的工程有Unity封装的方法,可以通过发消息的方式跟Unity进行交互。其中,C#不能与OC直接进行交互,需要用C++去写。</p>
</blockquote>
<h2 id="Unity3D支持的作为脚本的语言"><a href="#Unity3D支持的作为脚本的语言" class="headerlink" title="Unity3D支持的作为脚本的语言"></a>Unity3D支持的作为脚本的语言</h2><blockquote>
<p>C#、JS、Boo </p>
</blockquote>
<h2 id="Unity中用过哪些插件?具体功能"><a href="#Unity中用过哪些插件?具体功能" class="headerlink" title="Unity中用过哪些插件?具体功能"></a>Unity中用过哪些插件?具体功能</h2><blockquote>
<p>NGUI,制作2D界面</p>
<p>Helpshift,帮助与提示</p>
<p>KTPlay,游戏论坛</p>
<p>UniClipboard,粘贴板</p>
</blockquote>
<h2 id="Unity中常用的插件(Δ)"><a href="#Unity中常用的插件(Δ)" class="headerlink" title="Unity中常用的插件(Δ)"></a>Unity中常用的插件(Δ)</h2><h2 id="Unity引擎使用的是左手坐标系还是右手坐标系(A)"><a href="#Unity引擎使用的是左手坐标系还是右手坐标系(A)" class="headerlink" title="Unity引擎使用的是左手坐标系还是右手坐标系(A)"></a>Unity引擎使用的是左手坐标系还是右手坐标系(A)</h2><blockquote>
<p>A.左手坐标系 B.右手坐标系<br>C.可以通过ProjectSetting切换右手坐标系 D.可以通过Reference切换左手坐标系</p>
</blockquote>
<h2 id="什么是导航网格(NavMesh)(B)"><a href="#什么是导航网格(NavMesh)(B)" class="headerlink" title="什么是导航网格(NavMesh)(B)"></a>什么是导航网格(NavMesh)(B)</h2><blockquote>
<p>A.一种用于描述相机轨迹的网格 B.一种用于实现自动寻址的网格<br>C.一种被优化过的物体网格 D.一种用于物理碰撞的网格</p>
</blockquote>
<h1 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h1><h2 id="OnEnable、Awake、Start运行时发生的顺序,哪些可以在同一周期中重复发生"><a href="#OnEnable、Awake、Start运行时发生的顺序,哪些可以在同一周期中重复发生" class="headerlink" title="OnEnable、Awake、Start运行时发生的顺序,哪些可以在同一周期中重复发生"></a>OnEnable、Awake、Start运行时发生的顺序,哪些可以在同一周期中重复发生</h2><blockquote>
<p>Awake->OnEnable->Start<br>OnEnable可以在同一周期中重复发生</p>
</blockquote>
<h2 id="生命周期顺序"><a href="#生命周期顺序" class="headerlink" title="生命周期顺序"></a>生命周期顺序</h2><blockquote>
<p>Awake——>OnEnable–>Start——>Update——>FixedUpdate——>LateUpdate——>OnGUI——>OnDisable——>OnDestroy</p>
<p>Awake() 脚本唤醒,系统执行的第一个方法,用于脚本初始化,只执行一次。</p>
<p>Start()在Awake之后、Update之前执行,只执行一次。</p>
<p>Update()用于逻辑正常更新,每帧由系统自动调用一次。</p>
<p>FixedUpdate()固定更新。</p>
<p>LateUpdate()推迟更新,每帧调用,在Update之后调用。</p>
<p>OnGUI() 每帧可能会被绘制多次,每次对应于一个 GUI event</p>
<p>OnDestroy()当前脚本销毁时调用。</p>
</blockquote>
<h2 id="12-以下关于-MonoBehaviour-OnGUI-的描述错误的是(D)"><a href="#12-以下关于-MonoBehaviour-OnGUI-的描述错误的是(D)" class="headerlink" title="12.以下关于 MonoBehaviour.OnGUI()的描述错误的是(D)"></a>12.以下关于 MonoBehaviour.OnGUI()的描述错误的是(D)</h2><blockquote>
<p>A.如果 MonoBehaviour 没有被启用,则OnGUI函数不会被调用<br>B.用于绘制和处理 GUI events<br>C.每帧可能会被绘制多次,每次对应于一个 GUI event<br>D.每帧被调用一次</p>
</blockquote>
<h2 id="Addcomponent后哪个生命周期函数会被调用?"><a href="#Addcomponent后哪个生命周期函数会被调用?" class="headerlink" title="Addcomponent后哪个生命周期函数会被调用?"></a>Addcomponent后哪个生命周期函数会被调用?</h2><blockquote>
<p>对于AddComponent添加的脚本,其Awake,Start,OnEnable是在Add的当前帧被调用的,其中Awake,OnEnable与AddComponent处于同一调用链上,Start会在当前帧稍晚一些的时候被调用。Update则是根据Add调用时机决定何时调用:如果Add是在当前帧的Update前调用,那么新脚本的Update也会在当前帧被调用,否则会被延迟到下一帧调用。<br><a href="https://blog.csdn.net/qq_32821435/article/details/94760815" target="_blank" rel="external">https://blog.csdn.net/qq_32821435/article/details/94760815</a></p>
</blockquote>
<h2 id="物理更新一般放在哪个系统函数里"><a href="#物理更新一般放在哪个系统函数里" class="headerlink" title="物理更新一般放在哪个系统函数里"></a>物理更新一般放在哪个系统函数里</h2><blockquote>
<p>FixedUpdate。update跟当前平台的帧数有关,而FixedUpdate是真实时间</p>
</blockquote>
<h2 id="Update和FixedUpdate的区别?"><a href="#Update和FixedUpdate的区别?" class="headerlink" title="Update和FixedUpdate的区别?"></a>Update和FixedUpdate的区别?</h2><blockquote>
<p>Update是在每次渲染新的一帧的时候会调用,FixedUpdate,是在固定的时间间隔执行,不受游戏帧率的影响。FixedUpdate的时间间隔可以在项目设置中更改,Edit->ProjectSetting->time 找到Fixedtimestep。</p>
</blockquote>
<h2 id="移动相机动作在哪个函数里,为什么在这个函数里"><a href="#移动相机动作在哪个函数里,为什么在这个函数里" class="headerlink" title="移动相机动作在哪个函数里,为什么在这个函数里"></a>移动相机动作在哪个函数里,为什么在这个函数里</h2><blockquote>
<p>LateUpdate,是在所有的update结束后才调用,比较适合用于命令脚本的执行。官网上例子是摄像机的跟随,都是所有的update操作完才进行摄像机的跟进,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。</p>
</blockquote>
<h2 id="关于-MonoBehaviour-LateUpdate-函数描述错误的是:(B)"><a href="#关于-MonoBehaviour-LateUpdate-函数描述错误的是:(B)" class="headerlink" title="关于 MonoBehaviour.LateUpdate 函数描述错误的是:(B)"></a>关于 MonoBehaviour.LateUpdate 函数描述错误的是:(B)</h2><blockquote>
<p>A.当 MonoBehaviour 类被启用后,每帧调用一次<br>B.常被用于处理 Rigidbody 的更新<br>C.在所有 Update 函数执行后才能被调用<br>D.常被用于实现跟随相机效果,且目标物体的位置已经在 Update 函数中被更新</p>
<p>应该放在FixedUpdate</p>
</blockquote>
<h2 id="如何让已经存在的GameObject在LoadLevel后不被卸载掉"><a href="#如何让已经存在的GameObject在LoadLevel后不被卸载掉" class="headerlink" title="如何让已经存在的GameObject在LoadLevel后不被卸载掉"></a>如何让已经存在的GameObject在LoadLevel后不被卸载掉</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">void Awake()</div><div class="line">{</div><div class="line"> DontDestroyOnLoad(transform.gameObject);</div><div class="line">}</div></pre></td></tr></table></figure>
<h1 id="脚本及编辑器"><a href="#脚本及编辑器" class="headerlink" title="脚本及编辑器"></a>脚本及编辑器</h1><h2 id="命名空间"><a href="#命名空间" class="headerlink" title="命名空间"></a>命名空间</h2><blockquote>
<p>unityEngne</p>
</blockquote>
<h2 id="9-在哪个面板中可以修改物体的空间属性,如位置,朝向,大小等(B)"><a href="#9-在哪个面板中可以修改物体的空间属性,如位置,朝向,大小等(B)" class="headerlink" title="9.在哪个面板中可以修改物体的空间属性,如位置,朝向,大小等(B)"></a>9.在哪个面板中可以修改物体的空间属性,如位置,朝向,大小等(B)</h2><blockquote>
<p>A.Project B.Inspector C.Hierarchy D.Toolbar</p>
</blockquote>
<h2 id="如何为一个Asset-资源设定一个Label,从而能够方便准确的搜索到?(D)"><a href="#如何为一个Asset-资源设定一个Label,从而能够方便准确的搜索到?(D)" class="headerlink" title="如何为一个Asset 资源设定一个Label,从而能够方便准确的搜索到?(D)"></a>如何为一个Asset 资源设定一个Label,从而能够方便准确的搜索到?(D)</h2><blockquote>
<p>A.在Project窗口中选中一个Asset,右键->Create->Label<br>B.在Project窗口中选中一个Asset,右键->Add Label<br>C.在Project窗口中选中一个Asset,在Inspector窗口中点击添加Label的图标<br>D.在Project窗口中选中一个Asset,在Inspector窗口中点击按钮“Add Label”</p>
</blockquote>
<h2 id="5-Application-loadLevel命令为(A)"><a href="#5-Application-loadLevel命令为(A)" class="headerlink" title="5.Application.loadLevel命令为(A)"></a>5.Application.loadLevel命令为(A)</h2><blockquote>
<p>A.加载关卡 B.异步加载关卡 C.加载动作 D.加载动画</p>
</blockquote>
<h2 id="将图片的TextureType选项分别选为“Texture”和“Sprite”有什么区别"><a href="#将图片的TextureType选项分别选为“Texture”和“Sprite”有什么区别" class="headerlink" title="将图片的TextureType选项分别选为“Texture”和“Sprite”有什么区别"></a>将图片的TextureType选项分别选为“Texture”和“Sprite”有什么区别</h2><blockquote>
<p>Sprite作为UI精灵使用,Texture作用模型贴图使用。Sprite需要2的整次幂,打包图片省资源</p>
</blockquote>
<h2 id="为什么dynamic-font在unicode环境下优于static-font(?"><a href="#为什么dynamic-font在unicode环境下优于static-font(?" class="headerlink" title="为什么dynamic font在unicode环境下优于static font(?"></a>为什么dynamic font在unicode环境下优于static font(?</h2><blockquote>
<p>Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。<br>使用动态字体时,Unity将不会预先生成一个与所有字体的字符纹理。当需要支持亚洲语言或者较大的字体的时候,若使用正常纹理,则字体的纹理将非常大。</p>
</blockquote>
<h2 id="OnBecameVisible及OnBecameInvisible的发生时机,以及这一对回调函数的意义"><a href="#OnBecameVisible及OnBecameInvisible的发生时机,以及这一对回调函数的意义" class="headerlink" title="OnBecameVisible及OnBecameInvisible的发生时机,以及这一对回调函数的意义"></a>OnBecameVisible及OnBecameInvisible的发生时机,以及这一对回调函数的意义</h2><blockquote>
<p>当物体是否可见切换之时。可以用于只需要在物体可见时才进行的计算。</p>
</blockquote>
<h2 id="采用Input-mousePosition-来获取鼠标在屏幕上的位置,以下表达正确的是(C)"><a href="#采用Input-mousePosition-来获取鼠标在屏幕上的位置,以下表达正确的是(C)" class="headerlink" title="采用Input.mousePosition 来获取鼠标在屏幕上的位置,以下表达正确的是(C)"></a>采用Input.mousePosition 来获取鼠标在屏幕上的位置,以下表达正确的是(C)</h2><blockquote>
<p>A.左上角为原点(0,0),右下角为(Screen.Width, Screen.Height)<br>B.左下角为原点(0,0),右下角为(Screen.Height, Screen.Width)<br>C.左下角为原点(0,0),右上角为(Screen.Width, Screen.Height)<br>D.左上角为原点(0,0),右下角为(Screen.Height, Screen.Width)</p>
</blockquote>
<h2 id="物体自身旋转使用的函数?"><a href="#物体自身旋转使用的函数?" class="headerlink" title="物体自身旋转使用的函数?"></a>物体自身旋转使用的函数?</h2><blockquote>
<p>Transform.Rotate()</p>
</blockquote>
<h2 id="物体绕某点旋转使用函数叫什么?"><a href="#物体绕某点旋转使用函数叫什么?" class="headerlink" title="物体绕某点旋转使用函数叫什么?"></a>物体绕某点旋转使用函数叫什么?</h2><blockquote>
<p>transform.RotateAround()</p>
</blockquote>
<h2 id="以下选项中,将游戏对象绕Z轴逆时针旋转90度(C)"><a href="#以下选项中,将游戏对象绕Z轴逆时针旋转90度(C)" class="headerlink" title="以下选项中,将游戏对象绕Z轴逆时针旋转90度(C)"></a>以下选项中,将游戏对象绕Z轴逆时针旋转90度(C)</h2><blockquote>
<p>A.transform.rotation = Quaternion.Euler(0,0,90)<br>B.transform.rotation = Quaternion.Angle(0,0,90)<br>C.transform.Rotate(new Vector3(0,0,90))<br>D.transform.Rotate(new Vector3(90,0,0))</p>
</blockquote>
<h2 id="游戏对象B是游戏对象A的子物体,游戏对象A经过了旋转,请写出游戏B围绕自身的Y轴进行旋转的脚本语句,以及游戏对象B围绕世界坐标的Y轴旋转的脚本语句"><a href="#游戏对象B是游戏对象A的子物体,游戏对象A经过了旋转,请写出游戏B围绕自身的Y轴进行旋转的脚本语句,以及游戏对象B围绕世界坐标的Y轴旋转的脚本语句" class="headerlink" title="游戏对象B是游戏对象A的子物体,游戏对象A经过了旋转,请写出游戏B围绕自身的Y轴进行旋转的脚本语句,以及游戏对象B围绕世界坐标的Y轴旋转的脚本语句"></a>游戏对象B是游戏对象A的子物体,游戏对象A经过了旋转,请写出游戏B围绕自身的Y轴进行旋转的脚本语句,以及游戏对象B围绕世界坐标的Y轴旋转的脚本语句</h2><blockquote>
<p>绕世界坐标旋转:transform.Rotate (transform.up<em>speed</em>Time.deltatime);<br>绕自身Y轴旋转:transform.Rotate (Vector.up<em>speed</em>Time.deltatime);</p>
</blockquote>
<h2 id="U3D中用于记录节点空间几何信息的组件名称,及其父类名称"><a href="#U3D中用于记录节点空间几何信息的组件名称,及其父类名称" class="headerlink" title="U3D中用于记录节点空间几何信息的组件名称,及其父类名称"></a>U3D中用于记录节点空间几何信息的组件名称,及其父类名称</h2><blockquote>
<p>Transform 父类是 Component</p>
</blockquote>
<h2 id="关于Vector3-的API,以下说法正确的是(BC)"><a href="#关于Vector3-的API,以下说法正确的是(BC)" class="headerlink" title="关于Vector3 的API,以下说法正确的是(BC)"></a>关于Vector3 的API,以下说法正确的是(BC)</h2><blockquote>
<p>A.Vector3.normalize 可以获取一个三维向量的法线向量<br>B.Vector3.magnitude 可以获取一个三维向量的长度<br>C.Vector3.forward 与 Vector3(0,0,1)是一样的意思<br>D.Vector3.Dot(向量A,向量B)是用来计算向量A与向量B的叉乘</p>
</blockquote>
<h2 id="以下哪个函数在游戏进入新场景后会被马上调用(B)"><a href="#以下哪个函数在游戏进入新场景后会被马上调用(B)" class="headerlink" title="以下哪个函数在游戏进入新场景后会被马上调用(B)"></a>以下哪个函数在游戏进入新场景后会被马上调用(B)</h2><blockquote>
<p>A.MonoBehaviour.OnSceneWastLoaded()<br>B.MonoBehaviour.OnSceneEnter()<br>C.MonoBehaviour.OnLevelEnter()<br>D.MonoBehaviour.OnLevelWastLoaded()</p>
</blockquote>
<h2 id="14-在Unity引擎中,Collider所指的是什么(D)"><a href="#14-在Unity引擎中,Collider所指的是什么(D)" class="headerlink" title="14.在Unity引擎中,Collider所指的是什么(D)"></a>14.在Unity引擎中,Collider所指的是什么(D)</h2><blockquote>
<p>A.collider 是Unity引擎中所支持的一种资源,可用作存储网格信息<br>B.Collider 是Unity引擎中内置的一种组件,可用对网格进行渲染<br>C.Collider 是Unity引擎中所支持的一种资源,可用作游戏对象的坐标转换<br>D.Collider 是Unity引擎中内置的一种组件,可用作游戏对象之间的碰撞检测</p>
</blockquote>
<h2 id="下列选项中,关于Transform组件的Scale参数描述正确的是(A)"><a href="#下列选项中,关于Transform组件的Scale参数描述正确的是(A)" class="headerlink" title="下列选项中,关于Transform组件的Scale参数描述正确的是(A)"></a>下列选项中,关于Transform组件的Scale参数描述正确的是(A)</h2><blockquote>
<p>A.Transform组件的Scale参数不会影响ParticleSystem产生粒子的大小<br>B.Transform组件的Scale参数不会影响GUITexture的大小<br>C.添加Collider组件后的GameoObject,其 Collider 组件的尺寸不受Transform组件的Scale参数影响<br>D.添加Rigidbody组件后的物体,大小将不再受Transform组件中 Scale 参数的影响</p>
</blockquote>
<h2 id="如何销毁一个UnityEngine-Object及其子类"><a href="#如何销毁一个UnityEngine-Object及其子类" class="headerlink" title="如何销毁一个UnityEngine.Object及其子类"></a>如何销毁一个UnityEngine.Object及其子类</h2><blockquote>
<p>Destroy()方法</p>
</blockquote>
<h2 id="DestroyImmediate和Destroy的区别"><a href="#DestroyImmediate和Destroy的区别" class="headerlink" title="DestroyImmediate和Destroy的区别"></a>DestroyImmediate和Destroy的区别</h2><blockquote>
<p>DestroyImmeditate 销毁对象的时候,会立即释放资源。Destroy只是从该场景销毁,但是还在内存当中。</p>
</blockquote>
<h2 id="在编辑场景时将GameObject设置为Static有何作用"><a href="#在编辑场景时将GameObject设置为Static有何作用" class="headerlink" title="在编辑场景时将GameObject设置为Static有何作用"></a>在编辑场景时将GameObject设置为Static有何作用</h2><blockquote>
<p>设置游戏对象为Static时,这些部分被静态物体挡住而不可见时,将会剔除(或禁用)网格对象。因此,在你的场景中的所有不会动的物体都应该标记为Static。</p>
</blockquote>
<h2 id="如何通过脚本来删除其自身对应的Gameobject(A)"><a href="#如何通过脚本来删除其自身对应的Gameobject(A)" class="headerlink" title="如何通过脚本来删除其自身对应的Gameobject(A)"></a>如何通过脚本来删除其自身对应的Gameobject(A)</h2><blockquote>
<p>A.Destroy(gameObject) B.this.Destroy()<br>C.Destroy(this) D.其他三项都可以</p>
</blockquote>
<h2 id="某个GameObject有一个名为MyScript的脚本,该脚本中有一个名为DoSomething-的函数,则如何在该Gameobject的另外一个脚本中调用该函数?(A)"><a href="#某个GameObject有一个名为MyScript的脚本,该脚本中有一个名为DoSomething-的函数,则如何在该Gameobject的另外一个脚本中调用该函数?(A)" class="headerlink" title="某个GameObject有一个名为MyScript的脚本,该脚本中有一个名为DoSomething 的函数,则如何在该Gameobject的另外一个脚本中调用该函数?(A)"></a>某个GameObject有一个名为MyScript的脚本,该脚本中有一个名为DoSomething 的函数,则如何在该Gameobject的另外一个脚本中调用该函数?(A)</h2><blockquote>
<p>A.GetComponent().DoSomething()<br>B.GetComponent<br>C.GetComponent().Call(“DoSomething”)<br>D.GetComponent</p>
</blockquote>
<h2 id="CompareTag比直接用gameObject-tag要好"><a href="#CompareTag比直接用gameObject-tag要好" class="headerlink" title="CompareTag比直接用gameObject.tag要好"></a>CompareTag比直接用gameObject.tag要好</h2><h2 id="简述一下对象池"><a href="#简述一下对象池" class="headerlink" title="简述一下对象池"></a>简述一下对象池</h2><blockquote>
<p>对象池就存放需要被反复调用资源的一个空间,当一个对象回大量生成的时候如果每次都销毁创建会很费时间,通过对象池把暂时不用的对象放到一个池中(也就是一个集合),当下次要重新生成这个对象的时候先去池中查找一下是否有可用的对象,如果有的话就直接拿出来使用,不需要再创建,如果池中没有可用的对象,才需要重新创建,利用空间换时间来达到游戏的高速运行效果,在FPS游戏中要常被大量复制的对象包括子弹,敌人,粒子等</p>
</blockquote>
<h2 id="对象池使用什么数据结构构建"><a href="#对象池使用什么数据结构构建" class="headerlink" title="对象池使用什么数据结构构建"></a>对象池使用什么数据结构构建</h2><h2 id="频繁创建GameObject会降低程序性能为什么?怎么解决?"><a href="#频繁创建GameObject会降低程序性能为什么?怎么解决?" class="headerlink" title="频繁创建GameObject会降低程序性能为什么?怎么解决?"></a>频繁创建GameObject会降低程序性能为什么?怎么解决?</h2><blockquote>
<p>频繁创建游戏对象,会增加游戏的Drawcall数,降低帧率,GPU会一直在渲染绘制。可以通过对象池来管理对象:当需要创建一个游戏对象时,先去对象池中查找一下对象池中是否存在没有被正在使用的对象,如果有的话直接使用这个对象,并把它标记为正在使用,没有话就创建一个,并把它添加到池中,然后标记为使用中。一个游戏对象使用完毕的时候,不要销毁掉,把它放在池中,标记为未使用。</p>
</blockquote>
<h2 id="如何在Unity中创建地形系统?-D"><a href="#如何在Unity中创建地形系统?-D" class="headerlink" title="如何在Unity中创建地形系统?(D)"></a>如何在Unity中创建地形系统?(D)</h2><blockquote>
<p>A.Terrain->Create Terrain B.Component->Create Terrain<br>C.Asset->Create Terrain D.Windows->Create Terrain</p>
</blockquote>
<h1 id="资源相关"><a href="#资源相关" class="headerlink" title="资源相关"></a>资源相关</h1><h2 id="当删除Unity工程Assets目录下地meta文件时会导致什么?为什么?"><a href="#当删除Unity工程Assets目录下地meta文件时会导致什么?为什么?" class="headerlink" title="当删除Unity工程Assets目录下地meta文件时会导致什么?为什么?"></a>当删除Unity工程Assets目录下地meta文件时会导致什么?为什么?</h2><blockquote>
<p>会导致在场景中游戏对象看不到,或者报错,材质找不到资源。多人协作的时候会导致资源的重复产生。因为每个资源文件都对应一个.meta文件,这个.meta文件中的guid就是唯一标识这个资源的。材质就是通过这个guid来记录自己使用了那些资源,而且同一个资源的guid会因为不同的电脑而不同,所以当你上传了丢失了.meta文件的资源的时候,到了别人的机器上就会重新产生guid,那个这个资源就相当于垃圾了。</p>
</blockquote>
<h2 id="meta文件的作用"><a href="#meta文件的作用" class="headerlink" title="meta文件的作用"></a>meta文件的作用</h2><h2 id="prefab的作用"><a href="#prefab的作用" class="headerlink" title="prefab的作用"></a>prefab的作用</h2><blockquote>
<ol>
<li>在游戏运行时实例化。Prefab相当于一个模板,对已有的素材、脚本和参数做一个基础的配置,便于以后的修改</li>
<li>Prefab打包的内容简化了导出操作,便于团队协同</li>
</ol>
</blockquote>
<h2 id="下列叙述中有关-Prefab-说法错误的是哪一项(B)"><a href="#下列叙述中有关-Prefab-说法错误的是哪一项(B)" class="headerlink" title="下列叙述中有关 Prefab 说法错误的是哪一项(B)"></a>下列叙述中有关 Prefab 说法错误的是哪一项(B)</h2><blockquote>
<p>A.Prefab 是一种资源类型 B.Prefab 是一种可以反复使用的游戏对象<br>C.Prefab 可以多次在场景进行实例 D.当一个 Prefab 添加到场景中时,也就是创建了它的一个实例</p>
</blockquote>
<h2 id="资源加载方式"><a href="#资源加载方式" class="headerlink" title="资源加载方式"></a>资源加载方式</h2><blockquote>
<p>1.Resources<br>2.AssetBundle<br>3.AssetDatabase</p>
</blockquote>
<h2 id="资源数据库-AssetDatabase"><a href="#资源数据库-AssetDatabase" class="headerlink" title="资源数据库 (AssetDatabase)"></a>资源数据库 (AssetDatabase)</h2><blockquote>
<p>资源数据库 (AssetDatabase) 是允许您访问工程中的资源的 API。此外,其提供方法供您查找和加载资源,还可创建、删除和修改资源。Unity 编辑器 (Editor) 在内部使用资源数据库 (AssetDatabase) 追踪资源文件,并维护资源和引用资源的对象之间的关联。Unity 需要追踪工程文件夹发生的所有变化,如需访问或修改资源数据,您应始终使用资源数据库 (AssetDatabase) API,而非文件系统。 资源数据库 (AssetDatabase) 接口仅适用于编辑器,不可用于内置播放器。和所有其他编辑器类一样,其只适用于置于编辑器 (Editor) 文件夹中的脚本(只在主要的资源 (Assets) 文件夹中创建名为“编辑器”的文件夹(不存在该文件夹的情况下))。</p>
</blockquote>
<h2 id="什么是AssetBundle-谈谈对AssetBundle内存分配情况的理解"><a href="#什么是AssetBundle-谈谈对AssetBundle内存分配情况的理解" class="headerlink" title="什么是AssetBundle?谈谈对AssetBundle内存分配情况的理解"></a>什么是AssetBundle?谈谈对AssetBundle内存分配情况的理解</h2><blockquote>
<p>可以把多个游戏对象或资源二进制文件封装到AssetBundle中,提供封装与解包的方法使用很方便。</p>
<p>加载资源三个步骤:</p>
<ol>
<li>www/LoadFromFile/LoadFromMemory等接口加载AssetBundle本身</li>
<li>AssetBundle.LoadAsset()等接口从AssetBundle中加载资源</li>
<li>对于GameObject类资源,需要通过GameObject.Instantiate()创建Clone</li>
</ol>
<p>黑色区域:www类本身占用内存,还保留了一份对WebStream数据的引用。使用www = null或www.dispose()释放。前者等待GC,后者立即释放。释放后WebStream引用计数会减一。</p>
<p>橙色区域:WebStream数据,数据真正的存储区域。AssetBundle被加载进来后,这部分内存就被分配了。包含三个内容:1、压缩后的AssetBundle本身。2、解压后的资源。3、一个解压缓冲区。www或AssetBundle对象都只是有一个结构指向了WebStream数据,从而对外部提供操作真正资源数据的方法。当WebStream数据引用为0时,系统会自动释放。为了不频繁的开辟和销毁解压Buffer,绿色Decompression解压缓冲区Unity会至少保留一份。</p>
<p>粉色区域:AssetBundle对象,引用WebStream数据部分,提供从WebStream数据中加载资源的接口。AssetBundle.Unload(bool unloadAllLoadedObjects)释放资源。AssetBundle.Unload(false)释放AssetBundle对象本身,可能引起WebStream释放,导致无法通过接口或依赖关系从该AssetBundle加载资源,但已加载资源可以正常使用。AssetBundle(true)不仅释放WebStream部分,所有被加载出来的资源将被释放。</p>
<p>红色部分:通过Instantiate()创建的GameObject所包含的资源。这些资源根据类型与AssetBundle原始资源(WebStream资源部分)有不同关系。如Texture、shader资源,通常只是使用,不会做出改动,所以仅仅是引用关系;每个GameObject是特殊的,所以是完全复制一份;Mesh和Material,则是引用+复制的关系。</p>
</blockquote>
<h2 id="动态加载资源的方式-区别"><a href="#动态加载资源的方式-区别" class="headerlink" title="动态加载资源的方式 区别"></a>动态加载资源的方式 区别</h2><blockquote>
<p>1.Resources.Load();<br>2.AssetBundle</p>
<p>1.通过Resources模块,调用它的load函数:可以直接load并返回某个类型的Object,前提是要把这个资源放在Resource命名的文件夹下,Unity不关有没有场景引用,都会将其全部打入到安装包中。<br>2.通过bundle的形式:即将资源打成 asset bundle 放在服务器或本地磁盘,然后使用WWW模块get 下来,然后从这个bundle中load某个object。</p>
</blockquote>
<h2 id="以下关于WWW-LoadFromCacheOrDownload描述正确的是(C)"><a href="#以下关于WWW-LoadFromCacheOrDownload描述正确的是(C)" class="headerlink" title="以下关于WWW.LoadFromCacheOrDownload描述正确的是(C)"></a>以下关于WWW.LoadFromCacheOrDownload描述正确的是(C)</h2><blockquote>
<p>A.可被用于将 Text Assets 自动缓存到本地磁盘<br>B.可被用于将 Resource 自动缓存到本地磁盘<br>C.可被用于将 Asset Bundles 自动缓存到本地磁盘<br>D.可被用于将任意格式的Unity资源文件自动缓存到本地磁盘</p>
</blockquote>
<h2 id="如何安全地在不同工程间安全地迁移asset数据(?"><a href="#如何安全地在不同工程间安全地迁移asset数据(?" class="headerlink" title="如何安全地在不同工程间安全地迁移asset数据(?"></a>如何安全地在不同工程间安全地迁移asset数据(?</h2><blockquote>
<ol>
<li>将Assets目录和Library目录一起迁移</li>
<li>导出包,export Package</li>
<li>用unity自带的assets Server功能 或者meta功能</li>
</ol>
</blockquote>
<h2 id="AssetBundle包加载流程"><a href="#AssetBundle包加载流程" class="headerlink" title="AssetBundle包加载流程"></a>AssetBundle包加载流程</h2><h2 id="图集打包怎么分类"><a href="#图集打包怎么分类" class="headerlink" title="图集打包怎么分类"></a>图集打包怎么分类</h2><blockquote>
<p>1.按业务功能的预制,寻找依赖,收集所有预制引用的图片,<br>2.如果有多个预制使用了同一张图片,我们就把它扔到common文件夹<br>3.让图集尽量紧凑,没有太多空白,尽量让图集处于2的n次方大小</p>
</blockquote>
<h2 id="为什么Unity3d中会发生在组件上出现数据丢失的情况"><a href="#为什么Unity3d中会发生在组件上出现数据丢失的情况" class="headerlink" title="为什么Unity3d中会发生在组件上出现数据丢失的情况(?"></a>为什么Unity3d中会发生在组件上出现数据丢失的情况(?</h2><blockquote>
<p>组件上绑定的物体对象被删除了</p>
</blockquote>
<h1 id="UI与Camera"><a href="#UI与Camera" class="headerlink" title="UI与Camera"></a>UI与Camera</h1><h2 id="UGUI的Canvas的作用"><a href="#UGUI的Canvas的作用" class="headerlink" title="UGUI的Canvas的作用"></a>UGUI的Canvas的作用</h2><blockquote>
<p>Canvas画布是承载所有UI元素的区域。所有的UI元素都必须是Canvas的子对象。如果场景中没有画布,那么我们创建任何一个UI元素,都会自动创建画布,并且将新元素置于其下。</p>
<p>创建Canvas:GameObject->UI->Canvas</p>
</blockquote>
<h2 id="如何实现UI界面的层级"><a href="#如何实现UI界面的层级" class="headerlink" title="如何实现UI界面的层级"></a>如何实现UI界面的层级</h2><h2 id="Unity3d实现2d游戏,有几种方式"><a href="#Unity3d实现2d游戏,有几种方式" class="headerlink" title="Unity3d实现2d游戏,有几种方式"></a>Unity3d实现2d游戏,有几种方式</h2><blockquote>
<ol>
<li>使用自身的GUI</li>
<li>把摄像机的Projection(投影)值调整为Orthographic(正交投影),不考虑z轴</li>
<li>使用2d的ui插件:2DToolKit、NGUI等</li>
</ol>
</blockquote>
<h2 id="为何大家都在移动设备上寻求U3D原生GUI的替代方案"><a href="#为何大家都在移动设备上寻求U3D原生GUI的替代方案" class="headerlink" title="为何大家都在移动设备上寻求U3D原生GUI的替代方案"></a>为何大家都在移动设备上寻求U3D原生GUI的替代方案</h2><blockquote>
<p>不美观,OnGUI很耗费时间,效率不高,使用不方便</p>
</blockquote>
<h2 id="如何在不同分辨率下保持UI的一致性"><a href="#如何在不同分辨率下保持UI的一致性" class="headerlink" title="如何在不同分辨率下保持UI的一致性(?"></a>如何在不同分辨率下保持UI的一致性(?</h2><blockquote>
<p>NGUI很好的解决了这一点,屏幕分辨率的自适应性,原理就是计算出屏幕的宽高比跟原来的预设的屏幕分辨率求出一个对比值,然后修改摄像机的size。UGUI通过锚点和中心点和分辨率也解决这个问题</p>
</blockquote>
<h2 id="ngui和ugui的区别"><a href="#ngui和ugui的区别" class="headerlink" title="ngui和ugui的区别"></a>ngui和ugui的区别</h2><h2 id="简述NGUI中Grid和Table的作用"><a href="#简述NGUI中Grid和Table的作用" class="headerlink" title="简述NGUI中Grid和Table的作用"></a>简述NGUI中Grid和Table的作用</h2><blockquote>
<p>对Grid和Table下的子物体进行排序和定位</p>
</blockquote>
<h2 id="请简述NGUI中Panel和Anchor的作用"><a href="#请简述NGUI中Panel和Anchor的作用" class="headerlink" title="请简述NGUI中Panel和Anchor的作用"></a>请简述NGUI中Panel和Anchor的作用</h2><blockquote>
<ol>
<li>只要提供一个half-pixel偏移量,它可以让一个控件的位置在Windows系统上精确的显示出来(只有这个Anchor的子控件会受到影响)</li>
<li>如果挂载到一个对象上,那么他可以将这个对象依附到屏幕的角落或者边缘<br>3.UIPanel用来收集和管理它下面所有widget的组件。通过widget的geometry创建实际的draw call。没有panel所有东西都不能够被渲染出来,你可以把UIPanel当做Renderer</li>
</ol>
</blockquote>
<h2 id="UGUI中Image和RawImage的区别"><a href="#UGUI中Image和RawImage的区别" class="headerlink" title="UGUI中Image和RawImage的区别"></a>UGUI中Image和RawImage的区别</h2><blockquote>
<p>Imgae比RawImage更消耗性能<br>Image只能使用Sprite属性的图片,但是RawImage什么样的都可以使用<br>Image适合放一些有操作的图片,裁剪平铺旋转什么的,针对Image Type属性<br>RawImage就放单独展示的图片就可以,性能会比Image好很多</p>
</blockquote>
<h2 id="在场景中放置多个Camera并同时处于活动状态会发生什么-?"><a href="#在场景中放置多个Camera并同时处于活动状态会发生什么-?" class="headerlink" title="在场景中放置多个Camera并同时处于活动状态会发生什么(?"></a>在场景中放置多个Camera并同时处于活动状态会发生什么(?</h2><blockquote>
<p>游戏界面可以看到很多摄像机的混合。可以用depth(深度),Layer(层)+ Culling Mask,enable = false/true来控制</p>
</blockquote>
<h2 id="照相机的Clipping-Planes的作用是什么?调整Near、Fare两个值时,应该注意什么"><a href="#照相机的Clipping-Planes的作用是什么?调整Near、Fare两个值时,应该注意什么" class="headerlink" title="照相机的Clipping Planes的作用是什么?调整Near、Fare两个值时,应该注意什么"></a>照相机的Clipping Planes的作用是什么?调整Near、Fare两个值时,应该注意什么</h2><blockquote>
<p>剪裁平面 。从相机到开始渲染和停止渲染之间的距离。</p>
</blockquote>
<h2 id="将Camera组件的ClearFlags选项选成Depth-only是什么意思?有何用处"><a href="#将Camera组件的ClearFlags选项选成Depth-only是什么意思?有何用处" class="headerlink" title="将Camera组件的ClearFlags选项选成Depth only是什么意思?有何用处"></a>将Camera组件的ClearFlags选项选成Depth only是什么意思?有何用处</h2><blockquote>
<p>如果把摄像机的ClearFlags勾选为Deapth Only,那么摄像机就会只渲染看得见的对象,把背景会完全透明,这种情况一般用在两个摄像机以上的场景中</p>
</blockquote>
<h2 id="在-Unity-中的场景中创建-Camera-时,默认情况下除了带有Transform、Camera、GUILayer、Flare-Layer-组件之外,还带有以下哪种组件(C)"><a href="#在-Unity-中的场景中创建-Camera-时,默认情况下除了带有Transform、Camera、GUILayer、Flare-Layer-组件之外,还带有以下哪种组件(C)" class="headerlink" title="在 Unity 中的场景中创建 Camera 时,默认情况下除了带有Transform、Camera、GUILayer、Flare Layer 组件之外,还带有以下哪种组件(C)"></a>在 Unity 中的场景中创建 Camera 时,默认情况下除了带有Transform、Camera、GUILayer、Flare Layer 组件之外,还带有以下哪种组件(C)</h2><blockquote>
<p>A.Mouse Look B.FPS Input Controller C.Audio Listener D.Character Motor</p>
</blockquote>
<h2 id="以下哪组摄像机中-Normalized-View-Port-Rect-的数值设置可以使摄像机显示的画面位于1280-720分辨率的屏幕画面右上角(D)"><a href="#以下哪组摄像机中-Normalized-View-Port-Rect-的数值设置可以使摄像机显示的画面位于1280-720分辨率的屏幕画面右上角(D)" class="headerlink" title="以下哪组摄像机中 Normalized View Port Rect 的数值设置可以使摄像机显示的画面位于1280*720分辨率的屏幕画面右上角(D)"></a>以下哪组摄像机中 Normalized View Port Rect 的数值设置可以使摄像机显示的画面位于1280*720分辨率的屏幕画面右上角(D)</h2><blockquote>