-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
648 lines (329 loc) · 381 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>綺跡</title>
<subtitle>其冀有希</subtitle>
<link href="https://blog.yukx.io/atom.xml" rel="self"/>
<link href="https://blog.yukx.io/"/>
<updated>2023-12-17T08:19:33.835Z</updated>
<id>https://blog.yukx.io/</id>
<author>
<name>Yuki Xiracle</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>在Windows中读取你的Btrfs分区的硬盘</title>
<link href="https://blog.yukx.io/2023/12/read-your-btrfs-disk-in-windows/"/>
<id>https://blog.yukx.io/2023/12/read-your-btrfs-disk-in-windows/</id>
<published>2023-12-17T03:29:47.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<div class="note info"><p>小心劣质电源!</p></div><h2 id="挂载硬盘"><a class="anchor" href="#挂载硬盘">#</a> 挂载硬盘</h2><p>软件也好、驱动也罢,Linux 就藏在你的 Windows 设备里。</p><figure class="highlight powershell"><figcaption data-lang="PowerShell"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">GET-CimInstance</span> <span class="token operator">-</span>query <span class="token string">"SELECT * from Win32_DiskDrive"</span></pre></td></tr></table></figure><p>使用该命令获取连接硬盘的 DeviceID,并使用下面的命令挂载到 wsl 中。</p><figure class="highlight powershell"><figcaption data-lang="PowerShell"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 命令需要管理员权限</span></pre></td></tr><tr><td data-num="2"></td><td><pre>wsl <span class="token operator">--</span><span class="token function">mount</span> \\<span class="token punctuation">.</span>\PHYSICALDRIVE1 <span class="token operator">--</span>bare</pre></td></tr></table></figure><p>接下来进入子系统。</p><figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td data-command=""></td><td><pre><span class="token comment"># 让系统识别到设备</span></pre></td></tr><tr><td data-num="2"></td><td data-command="$"></td><td><pre><span class="token function">sudo</span> btrfs device scan</pre></td></tr><tr><td data-num="3"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td data-command="$"></td><td><pre><span class="token function">sudo</span> blkid</pre></td></tr><tr><td data-num="5"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/loop0: UUID="2023-01-19-13-06-17-00" LABEL="wsl-cli-bundle" TYPE="iso9660"</span></pre></td></tr><tr><td data-num="6"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/loop1: UUID="2023-01-19-13-05-01-00" LABEL="LinuxKit" TYPE="iso9660"</span></pre></td></tr><tr><td data-num="7"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/sda: TYPE="ext4"</span></pre></td></tr><tr><td data-num="8"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/sdb: UUID="cbe7b857-ce76-4e39-90fb-aeefe1056177" TYPE="swap"</span></pre></td></tr><tr><td data-num="9"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/sdc: UUID="3255683f-53a2-4fdf-91cf-b4c1041e2a62" TYPE="ext4"</span></pre></td></tr><tr><td data-num="10"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/sdd: UUID="bd3640c6-a231-4698-a283-9d23929b7edc" TYPE="ext4"</span></pre></td></tr><tr><td data-num="11"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/sde: UUID="b533f29f-e0f6-470d-b7b6-897a88b22f6f" TYPE="ext4"</span></pre></td></tr><tr><td data-num="12"></td><td data-command=""></td><td><pre><span class="token comment"># /dev/sdf1: LABEL="sto1" UUID="8ec8825c-80d8-4064-85ef-53a77fbd16e2" UUID_SUB="7f9f572d-9603-4d72-9647-0a239dec1b9f" TYPE="btrfs" PARTUUID="950e6328-89f2-4c63-9cc8-3b2ba2687b49"</span></pre></td></tr></table></figure><p>可以看到 <code>blkid</code> 的最后一行输出就是我们的 btrfs 分区的硬盘。</p><figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">sudo</span> <span class="token function">mkdir</span> /mnt/sto1 <span class="token operator">&&</span> <span class="token function">sudo</span> <span class="token function">mount</span> /dev/sdf1 /mnt/sto1</pre></td></tr></table></figure><p>创建挂载目录,将硬盘挂载上去,之后就可以去看看我们的硬盘上的数据是否还安好了。</p><h2 id="收尾"><a class="anchor" href="#收尾">#</a> 收尾</h2><p>注意在解除挂载时不要打开挂载的目录。</p><figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">sudo</span> <span class="token function">umount</span> /dev/sdf1</pre></td></tr></table></figure><figure class="highlight powershell"><figcaption data-lang="PowerShell"></figcaption><table><tr><td data-num="1"></td><td><pre>wsl <span class="token operator">--</span>unmount \\<span class="token punctuation">.</span>\PHYSICALDRIVE1</pre></td></tr></table></figure>]]></content>
<summary type="html"><div class="note info">
<p>小心劣质电源!</p>
</div>
<h2 id="挂载硬盘"><a class="anchor" href="#挂载硬盘">#</a> 挂载硬盘</h2>
<p>软件也好、驱动也罢,Linux 就藏在你的 Windows </summary>
<category term="Windows" scheme="https://blog.yukx.io/tags/Windows/"/>
<category term="Btrfs" scheme="https://blog.yukx.io/tags/Btrfs/"/>
<category term="wsl (Windows subsystem for linux)" scheme="https://blog.yukx.io/tags/wsl-Windows-subsystem-for-linux/"/>
</entry>
<entry>
<title>Deep Dark ECS</title>
<link href="https://blog.yukx.io/2023/11/deep-dark-ecs/"/>
<id>https://blog.yukx.io/2023/11/deep-dark-ecs/</id>
<published>2023-11-29T11:26:31.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>有了<a href="/2023/05/intro-ecs/">上一篇</a>的铺垫,在这一篇里我们将聚焦于复杂一些的逻辑。</p><p>本文将基于 <span class="exturl" data-url="aHR0cHM6Ly9iZXZ5ZW5naW5lLm9yZw==" title="A refreshingly simple data-driven game engine built in Rust.">Bevy</span> 演示代码。</p><p>首先来思考一个 “简单” 的问题:实体的创建。</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">spawn_xxx</span><span class="token punctuation">(</span><span class="token keyword">mut</span> commands<span class="token punctuation">:</span> <span class="token class-name">Command</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="2"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">XXXComponent</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>如上是一个简单创建实体的过程, <code>spawn</code> 方法可以接受一个组件组成的元组,其中的组件将被附加到创建的实体上。<br />很简单地,我们可以把所有用到的组件一股脑写上去。比如:</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token punctuation">(</span><span class="token class-name">Sprite</span><span class="token punctuation">,</span> <span class="token class-name">Name</span><span class="token punctuation">,</span> <span class="token class-name">Life</span><span class="token punctuation">,</span> <span class="token class-name">Movable</span><span class="token punctuation">,</span> <span class="token class-name">Player</span><span class="token punctuation">,</span> <span class="token class-name">Character</span><span class="token punctuation">,</span> <span class="token class-name">Transform</span> <span class="token punctuation">{</span>x<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">,</span> z<span class="token punctuation">:</span> <span class="token number">0.0</span><span class="token punctuation">}</span><span class="token punctuation">)</span></pre></td></tr></table></figure><div class="note info"><p>该示例仅用作展示一些可能的组件的类型,实际初始化的结构体包含更多的字段。</p></div><p>但是这种简单的做法并不十分美好,这个 <code>spawn_xxx</code> 的系统仅能生成一种实体,而且无从定制一些初始化参数:生成位置、不同阵营实体的区分、特定的强化等等。而且在省略的 Sprite 中,很显然我们还需要加载<ruby> Asset<rp>(</rp><rt>资产</rt><rp>)</rp></ruby>,来让角色有面目以示人。<br />我们需要更多参数!</p><p>世界出现了参差,这意味这我们一定把一些<strong>隐藏的东西</strong>给忽略了。</p><p>容易发现,我们的需求实际是两部分:创建实体、实体的初始化。这在平常的范式中通常是实例化一个预制体,于是我们得到了这个实体的引用,在此之上进行我们需要的修改,就是初始化过程了。但在这里我们做不到这一点: <code>spawn_xxx</code> 的运行独立于其他系统,如果我们不想在不同的逻辑里插入一大堆重复的 <code>spawn((...))</code> 的话。</p><p>那么你一定想问了:你不是说系统可以作用到特定的实体的组件上吗,我们设计一个 「Initialize」 组件,只需要创建一个包含必要初始化信息的实体,让这个 <code>spawn_xxx</code> 成为 <code>initialize_xxx</code> 补充缺少的组件不就好了?</p><p>Bravo,这就是我们要做的:</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">spawner</span><span class="token punctuation">(</span><span class="token keyword">mut</span> commands<span class="token punctuation">:</span> <span class="token class-name">Command</span><span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Initialize</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> position<span class="token punctuation">:</span> <span class="token punctuation">...</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token class-name">Team</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">...</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">initializer</span><span class="token punctuation">(</span> <span class="token comment">// Entity 本质为一个自增 id,Initialize 是组件,查询时获取其引用,Character 则是(组件)筛选条件,并不读取其数据</span></pre></td></tr><tr><td data-num="7"></td><td><pre> things_to_initialize<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token class-name">Entity</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Initialize</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">With</span><span class="token operator"><</span><span class="token class-name">Character</span><span class="token operator">>></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">mut</span> meshes<span class="token punctuation">:</span> <span class="token class-name">ResMut</span><span class="token operator"><</span><span class="token class-name">Assets</span><span class="token operator"><</span><span class="token class-name">Mesh</span><span class="token operator">>></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">mut</span> materials<span class="token punctuation">:</span> <span class="token class-name">ResMut</span><span class="token operator"><</span><span class="token class-name">Assets</span><span class="token operator"><</span><span class="token class-name">ColorMaterial</span><span class="token operator">>></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">mut</span> commands<span class="token punctuation">:</span> <span class="token class-name">Command</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td><pre> things_to_initialize<span class="token punctuation">.</span><span class="token function">for_each</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span><span class="token punctuation">(</span>entity<span class="token punctuation">,</span> initialize_infomation<span class="token punctuation">)</span><span class="token closure-punctuation punctuation">|</span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>entity<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token class-name">MaterialMesh2dBundle</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="15"></td><td><pre> mesh<span class="token punctuation">:</span> meshes<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token namespace">shape<span class="token punctuation">::</span></span><span class="token class-name">Circle</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">32</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="16"></td><td><pre> material<span class="token punctuation">:</span> materials<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">ColorMaterial</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">::</span><span class="token constant">ALICE_BLUE</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="17"></td><td><pre> transform<span class="token punctuation">:</span> <span class="token class-name">Transform</span><span class="token punctuation">::</span><span class="token function">from_translation</span><span class="token punctuation">(</span>initialize_infomation<span class="token punctuation">.</span>position<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">..</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">...</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token class-name">Initialize</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>通过查询组件 <code>(Initialize, Character)</code> 的组合,我们得到了需要初始化的实体,以一套通用的逻辑通过 <code>insert</code> 补上我们需要的组件,然后删除 <code>Initialize</code> 就完成了初始化,实体不再符合查询条件。</p><p>而当我们想要以一个通用的逻辑来生成一类不同的实体时,这样做更是必须的:</p><p>比如 「武器」 可以装载不同 「弹药」 ,发射时就需要生成不同的子弹。<br />我们就需要一个 <code>Bullet</code> 组件来承载一些公共参数:速度、散布、伤害等等,每种弹药一个组件作为区分:霰弹(弹头数量)、冲锋枪弹、狙击步枪弹等等。</p><p>当武器开火时,发送一个事件到 <code>spawner</code> ,事件包含弹药等必要信息。</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">spawner</span><span class="token punctuation">(</span><span class="token keyword">mut</span> event<span class="token punctuation">:</span> <span class="token class-name">EventReader</span><span class="token operator"><</span><span class="token class-name">BulletSpawnEvent</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token punctuation">...</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token comment">//... 读取事件</span></pre></td></tr><tr><td data-num="3"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>bullet<span class="token punctuation">,</span> <span class="token class-name">Initialize</span><span class="token punctuation">,</span> event<span class="token punctuation">.</span>bullet_type<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">shotgun_initializer</span><span class="token punctuation">(</span>shotgun_bullets<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token class-name">Entity</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Bullet</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">BulletType</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Initialize</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token punctuation">...</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">...</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token comment">//... 其他子弹初始化</span></pre></td></tr></table></figure><div class="note info"><p>由于 Bevy 目前 ^0.12.0 尚未有足够方便好用的预制体一类的功能,这或许也是目前最 “舒服” 的重复创建过程了。</p></div>]]></content>
<summary type="html"><p>有了<a href="/2023/05/intro-ecs/">上一篇</a>的铺垫,在这一篇里我们将聚焦于复杂一些的逻辑。</p>
<p>本文将基于 <span class="exturl" data-url="aHR0cHM6Ly9iZXZ5ZW5naW5lLm9yZw</summary>
<category term="ECS 与脑部护理" scheme="https://blog.yukx.io/categories/ECS-%E4%B8%8E%E8%84%91%E9%83%A8%E6%8A%A4%E7%90%86/"/>
<category term="ECS" scheme="https://blog.yukx.io/tags/ECS/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/tags/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
</entry>
<entry>
<title>你知道安利吗之 ECS</title>
<link href="https://blog.yukx.io/2023/05/intro-ecs/"/>
<id>https://blog.yukx.io/2023/05/intro-ecs/</id>
<published>2023-05-20T03:00:24.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<div class="note info"><p>本文又名 <a href="/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/">游戏开发日志 (其 3𝒾)</a></p></div><h2 id="敷衍的介绍"><a class="anchor" href="#敷衍的介绍">#</a> 敷衍的介绍</h2><p>ECS 即 Entity-Component-System 的缩写,是一种将世界抽象为:<br />组件 (Component): 持有完成特定功能所需的数据的结构<br />系统 (System): 通过查询、修改<ruby>数据<rp> (</rp><rt>组件</rt><rp>)</rp></ruby> 实现想要的行为的 “函数”<br /> 实体 (Entity): 持有一系列组件的个体的标识</p><p>一个简单的例子:对于一个实体 「Car」,要实现移动、载人这两样功能的话,则需要组件 「Movable」、「Loadable」 其中可以存储 「速度 (Movable)」 或 「乘员数 (Loadable)」 诸如此类的数据,这样就可以通过系统获取所有 「Movable」 和某种 “目标”、“方向” 一类的数据,进而移动实体的 「Transform」 ;载人功能亦如此,你也可以多查询一个 「Movable」 ,配合 「Loadable」 在乘员变化时影响 「速度 (Movable)」 让空车更快。</p><p>显而易见,这样的范式与主流的面向对象的思路大相径庭,将数据与行为隔离开,编写行为来影响不特定范围的数据,数据既是行为的结果又是行为的原因,此为面向数据编程 (Data Oriented Programing - DOP)。</p><p>其显著的特点<s>是设计思路反人类</s><br />是高性能,得益于其数据组织方式,<ruby>系统<rp> (</rp><rt>System</rt><rp>)</rp></ruby> 在运行时访问整块连续的同种数据,欢呼吧,缓存!</p><div class="note default"><p>有这样的一种说法:对现代 CPU 而言,整体运行速度的瓶颈在于存储访问 —— 你的某算法的优化版本很可能不如其对缓存友好的暴力循环版本</p></div><p>而且还有一种潜藏的优化空间 —— 批量重复的数据可以很好的被 GPU 处理,或许你能更轻松的利用到在看戏的 GPU。</p><h2 id="反人类的另一面"><a class="anchor" href="#反人类的另一面">#</a> “反人类” 的另一面</h2><p>确实有相当的声音:ECS 的代码组织方式有悖人类直觉。<br />而这也确实不是空穴来风,不过如果使用 ECS 的优势仅仅只是在性能方面的话,那么也不会有本文出现了。<s>性能,它值几个钱?</s> <span class="spoiler" title="你知道得太多了">也不是很配谈性能的说</span></p><p>回到上面的例子,直觉来想,「Car」 需要能跑能载人,有了 「载具」 这一概念,我实现一个载具,能跑能装人,写完收工,也没什么不好的,轻松又愉快,而仅仅写一个 「Loadable」 可不能实现载人,你很可能需要给人添加一个 「TakeCar」 组件再交给某个系统处理而不是 <code>car.Load(people)</code> ,何异于褪裤而放屁者?</p><p>不过生活未必总是会一帆风顺,问题总是会来的,让我们更进一步。<br />「Car」 是要来开的,在此先假设载具与玩家本人的控制方式一致,这里就需要先解除控制玩家单位转而控制载具,稍有不慎,可能两套控制代码就来了,而将玩家身上的 <code>Controllable</code> 或者叫别的什么移动到载具上是很自然的一件事情 —— 你总需要一个方式在茫茫的 Entities 中找出你要控制的那个。<br />如果有很多载具的话,还是让一部分动起来比较自然,有没有想过要怎么用 <code>car.MoveTo(..)</code> 来组织一个交通网?我有一计,不如放弃思考,看我用一个<ruby>系统<rp> (</rp><rt>System</rt><rp>)</rp></ruby> 查询 <code>AutoRun</code> ,给没有 <code>MoveTo</code> 的实体添加一个新目标 <code>MoveTo</code> ,随后等着掌管 「Movable」 的系统移动到位删除 <code>MoveTo</code> 便好。日后若是想给玩家的载具添加自动驾驶也不必如现实里一样苦苦研发一番。<br />很不巧,刚刚拍脑袋想到我们应该加入地堡:单位进入可以获得庇护。哎呀,这不是没有 「Movable」 的 「Car」 么,这下我们比拼一下下班速度吧 😉。</p><p>到此,不知各位是否已经有些许既视感,ECS-way 真的就与我们的直觉 —— 或者说我们已经熟悉的某种范式想去甚远吗?比较擅长抽象(狭义)多少已经主动或被动的接触到 “组合优于继承”、“Is A 与 Has A 的纠缠” 一类的纷纭。<br />在此暴论:<strong>DOP 就是在完全控制的场面下适合于大量广泛相互作用场景的 OOP 的极限值</strong>。</p><p>当我们想到 「载具」 的概念,再进一步,切至不可分的 「Movable」、「Loadable」 以至于更多需要的部分,这一过程实际上就是输出代码的前置准备工作,即便并未拆分出组件也是如此。<br />得益于数据完全被拆分出去,行为代码可以完全复用,再也不需要纠结涉及到多个组件时到底把功能实现到什么地方,需要改动时通常只需要涉及有限的区域 —— 平铺的线性流程,而不是柳暗花明的嵌套调用,更是可以通过玩弄<ruby>标签<rp> (</rp><rt>组件</rt><rp>)</rp></ruby> 来实现新功能。</p><p>能够如此拆分数据的一个原因是游戏的世界有一个很重要的性质:这里面的一切都是完全封闭的,完全由我们 —— 程序员来控制,而玩家,则仅能通过有限的输入事件来操作,而不是几十个 API,实在只能算作外人<s>要被骗到底裤都不剩的</s>。<br />正是因为封闭,不会有访问到不该访问的数据这种情况,而恰好这里面的数据随时有可能彼此产生联系 —— 灵感来啦!<br />限制访问 —— 在数据堆在一起时不得已而为之的手段,终于得以摆脱,于是给予我们极大的灵活性。</p><div class="note default no-icon"><p>突然有了一个邪恶的想法,通过 C# 的扩展方法也可以实现类似的效果。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">ExtMethods</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token generic-method"><span class="token function">DoSometing</span><span class="token generic class-name"><span class="token punctuation"><</span>T<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">T</span> entity<span class="token punctuation">)</span> <span class="token keyword">where</span> <span class="token class-name">T</span><span class="token punctuation">:</span> Interface1<span class="token punctuation">,</span> Interface2<span class="token punctuation">,</span> <span class="token range operator">..</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>避开了接口不方便带实现的限制,一些工具方法完全可以通过给 <code>T</code> 添加约束来实现,我干,感觉还真有那么些可行性。</p></div><h2 id="纯粹的目的"><a class="anchor" href="#纯粹的目的">#</a> 纯粹的目的</h2><p>所以回到思考方式上来,ECS 或者说 DOP,相比于 “直觉”,只是在抽象上更进了一步 —— 将我们的想法,分解成一个个简单的逻辑,再组合起来。<br />就如前文所举的 「Movable」 ,其实玩家的角色、自动行动的 NPC、乃至联机中其他玩家操控的角色,它们的移动都没有什么不同,其真正的区别在于 「行动意图」 的来源:</p><ul><li>玩家的角色的移动由玩家的输入驱动</li><li>自动行动的 NPC 的移动由 AI 的决策驱动</li><li>联机中其他玩家操控的角色的移动由网络读取的数据驱动</li></ul><p>于是我们真正要做的就是区分这些类型的单位,分别为它们实现产生 「MoveTo」 的系统。并且借助这个控制 Movable 的系统,在之后的开发中我们都不必再考虑一个实体要如何移动的问题,即使是子弹,即使是进行优美曲线运动的弹幕,只有如何产生 「MoveTo」 ,以及它如何变化的问题。</p>]]></content>
<summary type="html"><div class="note info">
<p>本文又名 <a href="/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-s</summary>
<category term="ECS 与脑部护理" scheme="https://blog.yukx.io/categories/ECS-%E4%B8%8E%E8%84%91%E9%83%A8%E6%8A%A4%E7%90%86/"/>
<category term="ECS" scheme="https://blog.yukx.io/tags/ECS/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/tags/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/tags/conquest-of-star/"/>
</entry>
<entry>
<title>游戏开发日志 (其2𝒾):摄像机神秘抖动事件</title>
<link href="https://blog.yukx.io/2023/04/game-dev-journal-2i-camera-mystery-trembling/"/>
<id>https://blog.yukx.io/2023/04/game-dev-journal-2i-camera-mystery-trembling/</id>
<published>2023-04-28T02:13:22.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>突然发现还没有关于最开始就完成的 「切屏」 部分的内容,也是突然发现这东西还有必要拉出来说一嘴的价值。</p><h2 id="一切的起因"><a class="anchor" href="#一切的起因">#</a> 一切的起因</h2><p>虽然在 RTS 类游戏里大部分人的浏览信息的方式都是鼠标移到屏幕边缘 「拖拽」 过去,不过这更像是表达一种 “我要操作那边的单位,给我过去” 的想法,而这样也挺麻烦的,有时候我们只是想稍微往那边看看。<br />在我游戏的过程中发现了一种更为舒适的移动屏幕的方式 「中键拖屏」 (什么键都可以啦),按下那个键,屏幕 (或者说地图,或者说摄像机) 就会跟随鼠标开始移动。</p><h3 id="随意的实现-精确的计算"><a class="anchor" href="#随意的实现-精确的计算">#</a> 随意的实现 精确的计算</h3><p>在最初的版本中,通过记录按下 「那个键」 时的鼠标位置和摄像机位置,在鼠标移动时通过系数放大 <code>Input.mousePosition</code> 的变化量将其施加给摄像机。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre>Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> camPos <span class="token operator">-</span> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>orthographicSize <span class="token operator">/</span> <span class="token number">20</span> <span class="token operator">*</span> CameraSpeed <span class="token operator">*</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span>mousePosition <span class="token operator">-</span> initialPos<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>通过精心调整 CameraSpeed 和配合 orthographicSize 的除数,甚至在支持摄像机缩放的情况下拖动可以完美跟手,可喜可贺!</p><p>不过这显然存在一个问题, <code>Input.mousePosition</code> 到世界坐标是显示相关的,一般来讲用鼠标操作游戏物体时都是要转换的。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td data-command="代码里甚至留着这样一个注释"></td><td><pre><span class="token comment">//var mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);</span></pre></td></tr></table></figure><h3 id="能出问题的地方就一定会出问题"><a class="anchor" href="#能出问题的地方就一定会出问题">#</a> 能出问题的地方就一定会出问题</h3><p>因为我有两块不同分辨率的屏幕,把 Unity 窗口拖过来就发现 「拖动」 不跟手了。</p><h2 id="简单的修复"><a class="anchor" href="#简单的修复">#</a> 简单的修复</h2><p>不得不说这就是先人的智慧,你看注释都留好了,只需要小小的修改……</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name"><span class="token keyword">var</span></span> mousePosition <span class="token operator">=</span> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">ScreenToWorldPoint</span><span class="token punctuation">(</span>Input<span class="token punctuation">.</span>mousePosition<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre>Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> camPos <span class="token operator">-</span> <span class="token punctuation">(</span>mousePosition <span class="token operator">-</span> initialPos<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>于是就炸了,拖动距离一远摄像机就开始狂抖。</p><p>而据 Log 显示 <code>Camera.main.transform.position</code> 并不像在 Inspector 里一样不停来回变化。</p><p>把设置摄像机位置的代码移到 LateUpdate 中有效果吗,并没有。</p><h3 id="真先人的智慧"><a class="anchor" href="#真先人的智慧">#</a> 真・先人的智慧</h3><p>所幸,在我无数个早夭的项目里发现了这样一段代码:</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">Vector3</span> m <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetAxisRaw</span><span class="token punctuation">(</span><span class="token string">"Mouse X"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> Input<span class="token punctuation">.</span><span class="token function">GetAxisRaw</span><span class="token punctuation">(</span><span class="token string">"Mouse Y"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre>Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">-=</span> m <span class="token operator">*</span> mainPlay<span class="token punctuation">.</span>MouseSensitivity<span class="token punctuation">;</span></pre></td></tr></table></figure><p>虽然没能避免用系数接近真实的移动,不过把从 「The Key」 按下到抬起过程的大 Delta 分散到了每一帧,这或许有帮助。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">Vector3</span> mousePos <span class="token operator">=</span> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">ScreenToWorldPoint</span><span class="token punctuation">(</span>Input<span class="token punctuation">.</span>mousePosition<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKey</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse2<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name">Vector3</span> mouseDelta <span class="token operator">=</span> mousePos <span class="token operator">-</span> lastMousePos<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> </pre></td></tr><tr><td data-num="6"></td><td><pre> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">-=</span> mouseDelta<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="8"></td><td><pre>lastMousePos <span class="token operator">=</span> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">ScreenToWorldPoint</span><span class="token punctuation">(</span>Input<span class="token punctuation">.</span>mousePosition<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>完美,任何分辨率,任何缩放都完美。</p><h2 id="直到最后仍然未解的烂片"><a class="anchor" href="#直到最后仍然未解的烂片">#</a> 直到最后<s>仍然未解</s>的烂片</h2><p>其实这个代码并不太符合我的风格,在同一个 Update 里出现了两个理应是相同的变量进行了两次一样的转换</p><p>—— 我本来是想这么说的,我想了一天一夜,在一个没有午休的中午过后,写到了这里</p><p>—— 于是突然我意识到这两个看似相同的东西实则不同</p><p>—— 摄像机移动了,于是转换的坐标也改变了</p><p>而 lastMousePos 不变则是应该的,我们要的正是 「地图跟随鼠标」 。</p><p>所以一切的抖动大抵都出自摄像机移动后,lastMousePos 发生漂移,而此前的思路根本上就有问题 —— 跟手的拖动,initialPos 与 lastPos 是相同的,所以每一次 Update 中计算出的差值并非鼠标全过程的<ruby>位移<rp> (</rp><rt>delta</rt><rp>)</rp></ruby>,而是殊途同归的小小增量。</p>]]></content>
<summary type="html"><p>突然发现还没有关于最开始就完成的 「切屏」 部分的内容,也是突然发现这东西还有必要拉出来说一嘴的价值。</p>
<h2 id="一切的起因"><a class="anchor" href="#一切的起因">#</a> 一切的起因</h2>
<p>虽然在 RTS 类游戏里大部</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Unity" scheme="https://blog.yukx.io/tags/Unity/"/>
<category term="摄像机移动" scheme="https://blog.yukx.io/tags/%E6%91%84%E5%83%8F%E6%9C%BA%E7%A7%BB%E5%8A%A8/"/>
<category term="摄像机抖动" scheme="https://blog.yukx.io/tags/%E6%91%84%E5%83%8F%E6%9C%BA%E6%8A%96%E5%8A%A8/"/>
</entry>
<entry>
<title>游戏开发日志 (其六):武器、投射物</title>
<link href="https://blog.yukx.io/2023/04/game-dev-journal-6-weapons-projectiles/"/>
<id>https://blog.yukx.io/2023/04/game-dev-journal-6-weapons-projectiles/</id>
<published>2023-04-18T06:09:16.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>好了,我们已经有了一个系统来把输入指令传递给我们的舰队了,那么,我们的舰队又将如何执行命令呢?<br />更具体一点,进行攻击?<br /><s>是以豪迈的气魄向敌人发起冲锋,胆怯的人将迎来粉身碎骨的命运!</s><br />既然我们都已经登上太空了,当然要避免这种原始低效的杀戮方式。真理部的工程师们给我们带来了更好的选择。</p><h2 id="万物皆可发射的终极火炮"><a class="anchor" href="#万物皆可发射的终极火炮">#</a> 万物皆可发射的终极 “火炮”</h2><h3 id="枪"><a class="anchor" href="#枪">#</a> 枪</h3><p>先考虑一些基本参数</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">Weapon</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">string</span></span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">float</span></span> BaseDamage <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">float</span></span> BaseRange <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token comment">// 攻击间隔,防止过热,需要冷却才能进行下次攻击</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">float</span></span> BaseCooldown <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token comment">// “热身” 过程,而当我们停止攻击,又逐渐变得需要重新进行预热</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">float</span></span> BasePrepareTime <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p><s>改改参数就可以说自己推出了一款新武器</s></p><p>为了保护武器延长使用寿命,为其加上限制</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">Weapon</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">float</span></span> <span class="token function">IsCoolingDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> cooldown<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">float</span></span> <span class="token function">Cooldown</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">return</span> cooldown <span class="token operator">=</span> Mathf<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>cooldown <span class="token operator">-</span> Time<span class="token punctuation">.</span>dltaTime<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> BaseCooldown<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> cooldown <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">Prepared</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td><pre> prepared <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> prepareTime <span class="token operator">=</span> Mathf<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>prepareTime <span class="token operator">+</span> Time<span class="token punctuation">.</span>deltaTime<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> BasePrepareTime<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">return</span> prepareTime <span class="token operator">>=</span> BasePrepareTime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token class-name"><span class="token keyword">bool</span></span> prepared <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> prepareTime <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token function">Cooldown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">LateUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>prepared<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="26"></td><td><pre> prepared <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token keyword">else</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">IsCoolingDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="29"></td><td><pre> prepareTime <span class="token operator">=</span> Mathf<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>prepareTime <span class="token operator">-</span> Time<span class="token punctuation">.</span>deltaTime<span class="token operator">*</span><span class="token number">0.3f</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> BasePrepareTime<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="31"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>我们在 “开火!” 时检测 Prepare 和 Cooldown (顺便进行了 Prepare),当可以发射后就发射并设置 Cooldown。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Fire</span><span class="token punctuation">(</span><span class="token class-name">Fleet</span> self<span class="token punctuation">,</span> <span class="token class-name">Fleet</span> target<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">Prepared</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">IsCoolingDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">return</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token function">LaunchProjectile</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> target<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> cooldown <span class="token operator">=</span> BaseCooldown<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">LaunchProjectile</span><span class="token punctuation">(</span><span class="token class-name">Fleet</span> self<span class="token punctuation">,</span> <span class="token class-name">Fleet</span> target<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="弹"><a class="anchor" href="#弹">#</a> 弹</h3><p>枪已经准备好了,只需要子弹了,那这就简单了,我们实际上只需要两个要素:</p><ol><li>移动路径</li><li>命中判定</li></ol><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LaserProjectile</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Projectile</span></span> <span class="token comment">// 继承自 MonoBehaviour</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">Vector2</span> from<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name">Vector2</span> to<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token class-name">Action<span class="token punctuation"><</span>Fleet<span class="token punctuation">></span></span> OnHit<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token comment">// Update is called once per frame</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">LateUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> collider <span class="token operator">=</span> <span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Collider2D<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> hitList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Collider2D</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>collider<span class="token punctuation">.</span><span class="token function">OverlapCollider</span><span class="token punctuation">(</span><span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> layerMask <span class="token operator">=</span> LayerMask<span class="token punctuation">.</span><span class="token function">GetMask</span><span class="token punctuation">(</span><span class="token string">"PlayerControls"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> hitList<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>hitList<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>gameObject<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Fleet<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">is</span> <span class="token class-name">Fleet</span> fleet <span class="token operator">&&</span> fleet <span class="token operator">!=</span> self <span class="token operator">&&</span> fleet<span class="token punctuation">.</span>Team <span class="token operator">!=</span> self<span class="token punctuation">.</span>Team<span class="token comment">/*friendly fire*/</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="15"></td><td><pre> OnHit<span class="token punctuation">?.</span><span class="token function">Invoke</span><span class="token punctuation">(</span>fleet<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token function">Destroy</span><span class="token punctuation">(</span>gameObject<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="23"></td><td><pre> transform<span class="token punctuation">.</span>position <span class="token operator">=</span> Vector2<span class="token punctuation">.</span><span class="token function">MoveTowards</span><span class="token punctuation">(</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">,</span> to<span class="token punctuation">,</span> speed <span class="token operator">*</span> Time<span class="token punctuation">.</span>deltaTime<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="25"></td><td><pre></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name">LaserProjectile</span> <span class="token function">Create</span><span class="token punctuation">(</span><span class="token class-name">Fleet</span> self<span class="token punctuation">,</span> <span class="token class-name">Fleet</span> target<span class="token punctuation">,</span> <span class="token class-name">Action<span class="token punctuation"><</span>Fleet<span class="token punctuation">></span></span> onHit<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> r <span class="token operator">=</span> Quaternion<span class="token punctuation">.</span><span class="token function">LookRotation</span><span class="token punctuation">(</span>Vector3<span class="token punctuation">.</span>forward<span class="token punctuation">,</span> target<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">-</span> self<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="29"></td><td><pre></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> projectile <span class="token operator">=</span> <span class="token function">Instantiate</span><span class="token punctuation">(</span>LaserProjectilePrefab<span class="token punctuation">,</span> self<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>LaserProjectile<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="31"></td><td><pre></pre></td></tr><tr><td data-num="32"></td><td><pre> projectile<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> self<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="33"></td><td><pre> projectile<span class="token punctuation">.</span>self <span class="token operator">=</span> self<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="34"></td><td><pre></pre></td></tr><tr><td data-num="35"></td><td><pre> projectile<span class="token punctuation">.</span>from <span class="token operator">=</span> self<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="36"></td><td><pre> projectile<span class="token punctuation">.</span>to <span class="token operator">=</span> target<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="37"></td><td><pre> projectile<span class="token punctuation">.</span>OnHit <span class="token operator">=</span> onHit<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token keyword">return</span> projectile<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="40"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>这里简单制作了一枚弹药:直线运动,不能追踪目标<br />在 Update 中进行移动,在 LateUpdate 中进行命中判定,在创建时设置目标等一系列参数。<br />命中时触发命中事件进行诸如造成伤害之类的行为。</p><h4 id="外题"><a class="anchor" href="#外题">#</a> 外题</h4><p>近来有对 Shader 进行一定了解,将投射物整体运动也交给 Shader 不知道是否可行?<br />使用一张覆盖整个地图的材质,在上面绘制弹道,对大量的,规则运动的 「弹幕」 应该是个很好的优化办法。</p><p>—— 由此延申,战争迷雾也可以直接在 Shader 中计算范围,而非是基于网格的循环遍历,不过遮挡的处理或许略有复杂。<br />这大概能挽回我丢失的 200 多帧吧,是的,之前的实现要消耗掉 200 多帧,甚至略有卡顿。</p>]]></content>
<summary type="html"><p>好了,我们已经有了一个系统来把输入指令传递给我们的舰队了,那么,我们的舰队又将如何执行命令呢?<br />
更具体一点,进行攻击?<br />
<s>是以豪迈的气魄向敌人发起冲锋,胆怯的人将迎来粉身碎骨的命运!</s><br />
既然我们都已经登上太空了,当然要避免这种原</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Weapon" scheme="https://blog.yukx.io/tags/Weapon/"/>
<category term="Projectile" scheme="https://blog.yukx.io/tags/Projectile/"/>
</entry>
<entry>
<title>游戏开发日志 (其ℂ(5,2)):输入、选中</title>
<link href="https://blog.yukx.io/2023/04/game-dev-journal-5-2i-input-selection/"/>
<id>https://blog.yukx.io/2023/04/game-dev-journal-5-2i-input-selection/</id>
<published>2023-04-07T02:53:41.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<div class="note default no-icon"><p>一遇到鼠标,事情就会变的复杂起来</p></div><p>在曾经的<a href="/2022/06/game-dev-journal-2-unit-selection-and-minimap-more/">文章</a>里已经做了一个选择功能的雏形,到了现在,可以发现,这也只能算是一个原型。<s>什么,这么长时间过去了还没弃坑!</s></p><p>确实是走了一段很难说是不是歧途的弯路。</p><p>简单的说,作为一个 RTS 类型为源头的游戏,鼠标的重要性不必再说(什么你是触摸屏?),指指点点、框框 A 上去;而不巧,我们要做的东西有几套不同的逻辑都要用这一套交互,还要在彼此间切换。形象点说,类似建筑规划与单位操作之间的关系。</p><h2 id="状态机"><a class="anchor" href="#状态机">#</a> 状态机</h2><p>聪明如你未必想不到这个办法,来分割不同的逻辑。<br />想不到也没关系,<a href="https://gpp.tkchu.me/state.html">快来学</a>。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">internal</span> <span class="token class-name">InputState</span> inputState <span class="token operator">=</span> InputState<span class="token punctuation">.</span>DefaultInputState<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> next <span class="token operator">=</span> inputState<span class="token punctuation">.</span><span class="token function">GetNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">??</span> inputState<span class="token punctuation">.</span><span class="token function">Handle</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>next <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="8"></td><td><pre> inputState<span class="token punctuation">.</span><span class="token function">OnLeave</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> next<span class="token punctuation">.</span><span class="token function">OnEnter</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> inputState <span class="token operator">=</span> next<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>这下眼不见心不烦了!我们还可以像那些牛逼哄哄的项目一样,<ruby>一个 State 就写一个 文件<rp> (</rp><rt>一个 文件 就写一个 State</rt><rp>)</rp></ruby> 了!<ruby>可喜可贺<rp> (</rp><rt>おめでと</rt><rp>)</rp></ruby>,<ruby>可喜可贺<rp> (</rp><rt>おめでと</rt><rp>)</rp></ruby>!<br />同时我们还能轻易支持状态打断 <code>.SetNext()</code> 、 <code>.GetNext()</code> 和优雅的状态进入、离开的处理。</p><p>这样就把一个隐藏的问题摆到了我们的面前:是否有必要每个状态都自己实现一遍对输入的处理?</p><h2 id="输入系统-选择"><a class="anchor" href="#输入系统-选择">#</a> 输入系统 - 选择</h2><p>理想情况下,我们会想要一个专门的系统来处理一切用户的输入和输入带来的结果,而只需要给指定事件提供其对应的功能。<br />在能够改键的游戏里应该很常见,不如说作为游戏引擎应该是会有这样的插件的吧?</p><p>但是很不幸,本作 —— 如果完成发布的话,有很多不同的框选 / 选择操作;姑且透露下,如果有过 RTS 游戏经验的人,很容易就能想到 “选择单位 -> 下达命令” 这个流程,而我偏要加入一个 “下达命令 -> 选择单位执行” 流程。<br />而即便不提同样的行为不同的功能,如果有一个编队面板,我想让这个面板也支持 “选择单位执行”,那么给面板写一个逻辑再手动打断 “选择单位” 的状态显然不是一个好主意。<br />我们面对的东西要更迫切一些。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">InputSystem</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name">GameObject<span class="token punctuation">[</span><span class="token punctuation">]</span></span> SelectedGameObjects <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">Event</span> OnSelectionChanged<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">SetSelection</span><span class="token punctuation">(</span><span class="token class-name">GameObject<span class="token punctuation">[</span><span class="token punctuation">]</span></span> selections<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> </pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token comment">//... HandleSelction()</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>这样的一个东西大概就能满足我们的需要了,根据需要可能要加入 Predication 来清除不需要的选择,或者是干脆一点用 LayerMask 筛选;以及 ——<br /><em> 关闭这套功能的开关</em><br />总有些时候会考虑不周<s>来酒吧里点炒饭</s>嘛是不是。</p><h2 id="输入系统-命令"><a class="anchor" href="#输入系统-命令">#</a> 输入系统 - 命令</h2><p>如上所说,这样一个 InputSystem 如果只是处理下鼠标选择,那么也稍显贫弱了。<br />那么便来考虑下 “常规” 的命令、改键相关的东西,不过直接做一个命令表键位映射什么的跟我们的项目不是很搭 —— 不同的输入状态分割了不同的输入命令。</p><p>由此暂且构想这样一个东西</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre>InputSystem<span class="token punctuation">.</span>Instance<span class="token punctuation">.</span><span class="token function">AddCommand</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">commandName</span><span class="token punctuation">:</span> <span class="token string">"attack-intent"</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">defaultKey</span><span class="token punctuation">:</span> KeyCode<span class="token punctuation">.</span>A<span class="token punctuation">,</span> handler<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>而显然是允许一个 commandName 具有多个 handler 随状态进行切换的,那么考虑多处的重复 commandName,也许可以用其首字母作为默认键。<span class="spoiler" title="你知道得太多了">War3 的先进经验</span><br />随后就在运行时把不存在的 「命令 - 键位 映射」 输出保存到什么文件,此后可高枕而无忧也!</p>]]></content>
<summary type="html"><div class="note default no-icon">
<p>一遇到鼠标,事情就会变的复杂起来</p>
</div>
<p>在曾经的<a href="/2022/06/game-dev-journal-2-unit-selection-and-minimap-mor</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="鼠标框选单位" scheme="https://blog.yukx.io/tags/%E9%BC%A0%E6%A0%87%E6%A1%86%E9%80%89%E5%8D%95%E4%BD%8D/"/>
<category term="Selection" scheme="https://blog.yukx.io/tags/Selection/"/>
<category term="Input System" scheme="https://blog.yukx.io/tags/Input-System/"/>
</entry>
<entry>
<title>C# 的一些问题操作 Ⅱ</title>
<link href="https://blog.yukx.io/2023/02/csharp-questionable-techs/"/>
<id>https://blog.yukx.io/2023/02/csharp-questionable-techs/</id>
<published>2023-02-12T13:41:53.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>省流:在 C# 中静态成员是相同类型共有的,即,派生类型与基类型公用同一个静态成员。</p><p>例如</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">Base</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">static</span> <span class="token class-name"><span class="token keyword">int</span></span> data <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Base</span></span><span class="token punctuation">{</span><span class="token punctuation">}</span></pre></td></tr></table></figure><p>修改 <code>Base.data</code> 后,访问 <code>A.data</code> 也会获得修改后的值。<br />很 trivial 对不对?</p><h2 id="the-non-trivials"><a class="anchor" href="#the-non-trivials">#</a> The Non-trivials</h2><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td data-command=""></td><td><pre><span class="token keyword">class</span> <span class="token class-name">Base<span class="token punctuation"><</span>K<span class="token punctuation">,</span> V<span class="token punctuation">></span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td data-command=""></td><td><pre> <span class="token keyword">static</span> <span class="token class-name">Dictionary<span class="token punctuation"><</span>K<span class="token punctuation">,</span> V<span class="token punctuation">></span></span> data<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td data-command=""></td><td><pre> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td data-command=""></td><td><pre> <span class="token comment">// ... save data to somewhere</span></pre></td></tr><tr><td data-num="6"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="7"></td><td data-command=""></td><td><pre> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Load</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="8"></td><td data-command=""></td><td><pre> <span class="token comment">// ... load data from somewhere</span></pre></td></tr><tr><td data-num="9"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="10"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="11"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td data-command=""></td><td><pre><span class="token keyword">class</span> <span class="token class-name">SomeDataType</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Base<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">,</span> SomeDataType<span class="token punctuation">></span></span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td data-command=""></td><td><pre> <span class="token keyword">static</span> <span class="token class-name">Dictionary<span class="token punctuation"><</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">></span></span> otherNewData<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="15"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="16"></td><td data-command=""></td><td><pre> Base<span class="token operator"><</span><span class="token keyword">int</span><span class="token punctuation">,</span> SomeDataType<span class="token operator">></span><span class="token punctuation">.</span><span class="token function">Save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="18"></td><td data-command=""></td><td><pre> <span class="token comment">// ... save new data to somewhere</span></pre></td></tr><tr><td data-num="19"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="20"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Load</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="21"></td><td data-command=""></td><td><pre> Base<span class="token operator"><</span><span class="token keyword">int</span><span class="token punctuation">,</span> SomeDataType<span class="token operator">></span><span class="token punctuation">.</span><span class="token function">Load</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="23"></td><td data-command=""></td><td><pre> <span class="token comment">// ... load new data from somewhere</span></pre></td></tr><tr><td data-num="24"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="25"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>上述代码得以正常运作。<br />虽然细想一下就可以明白,不过初次遇见还是有些被迷惑住。</p>]]></content>
<summary type="html"><p>省流:在 C# 中静态成员是相同类型共有的,即,派生类型与基类型公用同一个静态成员。</p>
<p>例如</p>
<figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table></summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="言尽于行" scheme="https://blog.yukx.io/tags/%E8%A8%80%E5%B0%BD%E4%BA%8E%E8%A1%8C/"/>
<category term="C#" scheme="https://blog.yukx.io/tags/C/"/>
<category term="Static method hiding" scheme="https://blog.yukx.io/tags/Static-method-hiding/"/>
<category term="Inheritance" scheme="https://blog.yukx.io/tags/Inheritance/"/>
</entry>
<entry>
<title>Bevy、贪吃蛇,与一些记录</title>
<link href="https://blog.yukx.io/2023/02/bevy-the-snake-and-notes/"/>
<id>https://blog.yukx.io/2023/02/bevy-the-snake-and-notes/</id>
<published>2023-02-06T09:02:25.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>本文基于 <a href="https://mbuffett.com/posts/bevy-snake-tutorial/">Creating a Snake Clone in Rust, with Bevy</a></p><p>仓库地址 <a href="https://github.com/hxYuki/a_snake">a_snake</a></p><iframe src="/nested/bevy-snake" title="sample" height="500" width="500"></iframe><div class="note default"><p>代码现已更新到 0.10</p><p>Window 现已成为 Entity,不在存在曾经的<a href="#%E5%B0%9A%E5%AD%98%E5%9C%A8%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E9%97%AE%E9%A2%98">问题</a></p></div><h2 id="与源文中的一些区别"><a class="anchor" href="#与源文中的一些区别">#</a> 与源文中的一些区别</h2><p>除了使用更高版本的 Bevy 以外<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>,主要改动在于没有使用 Resource 保存 <code>SnakeSegments</code> 、 <code>LastTailPosition</code> ,而是保存在了 <code>SnakeHead</code> 中。<br />个人认为这两个数据不是很适合作为 Resource,蛇身的实体 ID 与之前的尾部位置都是与蛇关联着的数据, <s>如果有多条蛇存在的话</s> 故存储到蛇头的组件中。</p><h2 id="对于源文的作业"><a class="anchor" href="#对于源文的作业">#</a> 对于源文的 “作业”</h2><ol><li>蛇的 180° 转向<br />思路有二,其一是使用 Events, <code>snake_movement_input</code> 中不再直接修改 <code>head.direction</code> 而改为发送事件,发送前清空未处理的事件,在 <code>snake_movement</code> 中接收事件修改 <code>direction</code> ;其二也雷同,不使用 Events,另外存储 <code>next_direction</code> 即可。</li><li>食物可以生成在蛇身上<br />遍历所有 <code>SnakeSegment</code> (其实也应该包含 <code>Food</code> )的位置,重复则重新生成随机位置(或者直接 return)。<br />不过食物最好应当在上一个被吃掉后再生成,屏幕填满不知道是否会卡住呢?<br />其实更好的方法似乎有两个,碰撞检测,不过在当前版本的 Bevy 中尚不支持 Physics;或是存储网格矩阵,检测 <code>grid[i][j]</code> 中是否有物体,如果不用引擎实现游戏的话,该方法是很自然的选择。</li></ol><h2 id="尚存在的一些小问题"><a class="anchor" href="#尚存在的一些小问题">#</a> 尚存在的一些小问题</h2><p>关闭窗口时会由于使用了 <code>Res<Windows></code> -> <code>get_primary().unwrap()</code> unwrap 先抛出导致整个窗口卡住。(偶尔可以正常退出)</p><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>WindowDescripter 不再直接可用于 Resource <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
<summary type="html"><p>本文基于 <a href="https://mbuffett.com/posts/bevy-snake-tutorial/">Creating a Snake Clone in Rust, with Bevy</a></p>
<p>仓库地址 <a href="https:/</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="Bevy" scheme="https://blog.yukx.io/tags/Bevy/"/>
<category term="Rust" scheme="https://blog.yukx.io/tags/Rust/"/>
</entry>
<entry>
<title>ObservableCollection 之批次更新</title>
<link href="https://blog.yukx.io/2022/12/bulk-update-ObservableCollection/"/>
<id>https://blog.yukx.io/2022/12/bulk-update-ObservableCollection/</id>
<published>2022-12-12T14:13:14.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<h2 id="使用示例"><a class="anchor" href="#使用示例">#</a> 使用示例</h2><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">using</span> <span class="token punctuation">(</span>collection<span class="token punctuation">.</span><span class="token function">BatchUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> collection<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token range operator">..</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token range operator">..</span><span class="token punctuation">.</span> <span class="token comment">// Some Addition</span></pre></td></tr><tr><td data-num="5"></td><td><pre> collection<span class="token punctuation">.</span><span class="token function">Remove</span><span class="token punctuation">(</span><span class="token range operator">..</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token range operator">..</span><span class="token punctuation">.</span> <span class="token comment">// Some Removal</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token comment">// And then only one time OnCollectionChanged trigged.</span></pre></td></tr></table></figure><h2 id="实现代码"><a class="anchor" href="#实现代码">#</a> 实现代码</h2><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">BulkObservableCollection<span class="token punctuation"><</span>T<span class="token punctuation">></span></span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ObservableCollection<span class="token punctuation"><</span>T<span class="token punctuation">></span></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">protected</span> <span class="token class-name"><span class="token keyword">bool</span></span> _suppressNotification <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnCollectionChanged</span><span class="token punctuation">(</span><span class="token class-name">NotifyCollectionChangedEventArgs</span> e<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_suppressNotification<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnCollectionChanged</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name">IDisposable</span> <span class="token function">BatchUpdate</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td><pre> _suppressNotification <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">UpdateToken</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">class</span> <span class="token class-name">UpdateToken</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IDisposable</span></span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">BulkObservableCollection<span class="token punctuation"><</span>T<span class="token punctuation">></span></span> oc<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">public</span> <span class="token function">UpdateToken</span><span class="token punctuation">(</span><span class="token class-name">BulkObservableCollection<span class="token punctuation"><</span>T<span class="token punctuation">></span></span> cl<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="22"></td><td><pre> oc <span class="token operator">=</span> cl <span class="token operator">??</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ArgumentNullException</span><span class="token punctuation">(</span><span class="token keyword">nameof</span><span class="token punctuation">(</span>cl<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="26"></td><td><pre> oc<span class="token punctuation">.</span>_suppressNotification <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> oc<span class="token punctuation">.</span><span class="token function">OnCollectionChanged</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">NotifyCollectionChangedEventArgs</span><span class="token punctuation">(</span>NotifyCollectionChangedAction<span class="token punctuation">.</span>Reset<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="30"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="使用示例"><a class="anchor" href="#使用示例">#</a> 使用示例</h2>
<figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="C#" scheme="https://blog.yukx.io/tags/C/"/>
<category term="ObservableCollection" scheme="https://blog.yukx.io/tags/ObservableCollection/"/>
</entry>
<entry>
<title>魔法上网碎碎念</title>
<link href="https://blog.yukx.io/2022/11/noise-about-magic-surfing/"/>
<id>https://blog.yukx.io/2022/11/noise-about-magic-surfing/</id>
<published>2022-11-17T20:17:16.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<div class="note warning"><p>LONG may the empire.</p></div><p>VMessTCPTLS 跑了好久了,最近终于在 IPv4 上挂了,虽然也不确定。<br />毕竟本地的运营商思路非常广,骚操作也非常多,DNS 发脾气不解析外部域名是常有的事,固定宽带尚且如此,基站的玩法更是花样频出,给你分配一些申必地址<br /><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20221118123415.png" alt="?" title="***" /><br /> 真是让人受宠若惊。<br />由于最近的网络环境已经不再垂青于我,终于被迫趁着星光尚能亮起的时候迁移到了新家。</p><p>IPv4 的地址已经暴露,网页尚能浏览,而传统魔法结构已经不能维持了。</p><ul><li>CDN 大法好!</li><li>仅有 WebSocket 可以通过 CDN</li></ul><p>经过一些试错,如果构筑法术时保留了 TLS 的话,CDN 也要至少将等级提升到’Full’。<span class="spoiler blur" title="你知道得太多了">不会有人不用 Cloudflare 吧</span></p><p>网页可以访问的话,不如做戏做个全套,为流量设置一个 Fallback。</p><ul><li>Fallback 仅支持 TCP 方式</li></ul><p>Fallback 后面都是本机了,所以 TLS 的保障也可以到此为止了,不过需要注意的是另一点’alpn’。<br />HTTP/2 的流量 Fallback 下去也会是 HTTP/2,确保底层可以接住 h2 流量以免网页无法访问。或者干脆不要在前面添加 h2 的 alpn。</p><h2 id="注意"><a class="anchor" href="#注意">#</a> 注意</h2><p>本文主要还是发发牢骚,一通暴学终于感觉掌握了魔法的配置原理,记录一些不才落下的点,可能不适合作为参考。</p><h2 id="参考"><a class="anchor" href="#参考">#</a> 参考</h2><ol><li><p><a href="https://itlanyan.com/vless-fallback-object/#bnp_i_3">VLESS 协议的 fallback 参数介绍</a></p></li><li><p><a href="https://v2xtls.org/v2ray%E4%BD%BF%E7%94%A8cloudflare%E4%B8%AD%E8%BD%AC%E6%B5%81%E9%87%8F%EF%BC%8C%E6%8B%AF%E6%95%91%E8%A2%AB%E5%A2%99ip/">使用 cloudflare 中转流量,拯救被墙 ip</a></p></li></ol>]]></content>
<summary type="html"><div class="note warning">
<p>LONG may the empire.</p>
</div>
<p>VMessTCPTLS 跑了好久了,最近终于在 IPv4 上挂了,虽然也不确定。<br />
毕竟本地的运营商思路非常广,骚操作也非常多,DNS 发脾</summary>
<category term="生命在于折腾" scheme="https://blog.yukx.io/categories/%E7%94%9F%E5%91%BD%E5%9C%A8%E4%BA%8E%E6%8A%98%E8%85%BE/"/>
<category term="魔法上网" scheme="https://blog.yukx.io/tags/%E9%AD%94%E6%B3%95%E4%B8%8A%E7%BD%91/"/>
<category term="WS、TLS、CDN" scheme="https://blog.yukx.io/tags/WS%E3%80%81TLS%E3%80%81CDN/"/>
</entry>
<entry>
<title>类型系统漫巡</title>
<link href="https://blog.yukx.io/2022/10/type-system-explorition/"/>
<id>https://blog.yukx.io/2022/10/type-system-explorition/</id>
<published>2022-10-08T21:15:24.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<div class="note default no-icon"><p>气温骤降,天冷的似乎要把脑子都冻僵,不禁感叹当初为什么选了一个网面的椅子。</p></div><h2 id="类型类型"><a class="anchor" href="#类型类型">#</a> 类型,类型</h2><p>在动态语言中扑腾久了,作为一个短时记忆倾向的人类,就会不由得怀念起确定的类型给人带来的温暖的安心感,从这个角度来说,动态的类型,其强也好弱也好,都很难说是’有一个类型’—— 既不能在按下<span class="kbd">.</span> 时提供可用的成员,也不能在运行前确定这个’东西’到底会是什么样子。</p><p>在静态语言里扑腾久了,就有点烦,屁大点事也要重新声明一个类型。</p><p>普通的来说,也很难说现有类型系统的极限普遍迫切的需要突破,大部分的需求都可以被 <code><T, U, ...></code> 这样的类型参数解决,甚至说这些参数可以有提供的实参自动推导出来不需要再显式填写。<br />但是当你有了一些稀奇古怪的抽象,你想写最少的代码,你想把写过的东西随意组合一下形成新的东西,你就会发现这玩意既不直观也不方便,很快就直线撞上了边界 —— 当然你总有办法绕过去,但那就是另外的东西了。</p><h2 id="快给我变"><a class="anchor" href="#快给我变">#</a> 快给我变</h2><p>最近是有些想法,比如抽象出一个允许施加 / 撤销修改的数值类型,<br />通过依次计算修改来得出最终的值</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifiable</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token class-name"><span class="token keyword">object</span></span> Value<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">Modifiers<span class="token punctuation">[</span><span class="token punctuation">]</span></span> Modifiers<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifier</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">object</span></span> <span class="token function">Calculate</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">object</span></span> val<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>但在强类型语言里直接塞一个 object 进去显然不是什么好想法。<br />很容易想到的,给 Value 加一个类型</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifiable<span class="token punctuation"><</span>T<span class="token punctuation">></span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token class-name">T</span> Value<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">Modifier<span class="token punctuation"><</span>T<span class="token punctuation">></span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> Modifiers<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifier<span class="token punctuation"><</span>T<span class="token punctuation">></span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token return-type class-name">T</span> <span class="token function">Calculate</span><span class="token punctuation">(</span><span class="token class-name">T</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>但是还不太够的感觉,Modifier 显然是针对特定 Modifiable,即便是 value 的类型相同,也未必会想要 <code>ValueA: Modifiable<int></code> 能够使用对 <code>ValueB: Modifiable<int></code> 编写的 <code>Modifier<int></code> 。</p><p>基于此,我理解了 <code>T: SomeInterface<T></code> 的意义。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">ValueA</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Modifiable<span class="token punctuation"><</span>ValueA<span class="token punctuation">></span></span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token class-name">ValueA</span> Value<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">Modifier<span class="token punctuation"><</span>ValueA<span class="token punctuation">></span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> Modifiers<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">class</span> <span class="token class-name">AMod</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Modifier<span class="token punctuation"><</span>ValueA<span class="token punctuation">></span></span></span><span class="token punctuation">{</span> <span class="token range operator">..</span><span class="token punctuation">.</span> <span class="token punctuation">}</span></pre></td></tr></table></figure><p>但是这样仍然排除不了之前的用法,所以在接口上添加如是约束</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifiable<span class="token punctuation"><</span>T<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">where</span> <span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Modifiable<span class="token punctuation"><</span>T<span class="token punctuation">></span></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name">T</span> Value<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token class-name">Modifier<span class="token punctuation"><</span>T<span class="token punctuation">></span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> Modifiers<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifier<span class="token punctuation"><</span>T<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">where</span> <span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Modifiable<span class="token punctuation"><</span>T<span class="token punctuation">></span></span></span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token return-type class-name">T</span> <span class="token function">Calculate</span><span class="token punctuation">(</span><span class="token class-name">T</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><div class="note default"><p>后期修订:<br />现在回过头来想想这个 Value 其实就没有任何意义了,而要添加一个类型泛型又很麻烦地需要每次多标注一个类型,还是得靠基础设施。</p></div><p>若是有心继续深挖还可以进一步细化约束内部数据的类型</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifiable<span class="token punctuation"><</span>TSelf<span class="token punctuation">,</span> TData<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">where</span> <span class="token class-name">TSelf</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Modifiable<span class="token punctuation"><</span>TSelf<span class="token punctuation">,</span> TData<span class="token punctuation">></span></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name">TData</span> Value<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token class-name">Modifier<span class="token punctuation"><</span>TSelf<span class="token punctuation">,</span> TData<span class="token punctuation">></span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> Mods<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifier<span class="token punctuation"><</span>TModifiable<span class="token punctuation">,</span> TData<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">where</span> <span class="token class-name">TModifiable</span><span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Modifiable<span class="token punctuation"><</span>TModifiable<span class="token punctuation">,</span>TData<span class="token punctuation">></span></span></span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token return-type class-name">TData</span> <span class="token function">Calculate</span><span class="token punctuation">(</span><span class="token class-name">TData</span> lastCalculated<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>理想情况下,对于 Modifier 的具体实现,应当从 TModifiable 中获取 TData,而现有工具已经覆盖不到这种需求了,况且在本例来讲,分出这个 TData 的意义不大。</p><h2 id="幻想时间"><a class="anchor" href="#幻想时间">#</a> 幻想时间</h2><p>比如这种混乱的写法</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">interface</span> <span class="token class-name">Modifier<span class="token punctuation"><</span>TModifiable<span class="token punctuation"><</span>TModifiable<span class="token punctuation">,</span> TData<span class="token punctuation">></span><span class="token punctuation">></span></span></pre></td></tr></table></figure><p>似乎是叫高阶类型来着,不过通常举出的例子通常关心 <code><T<_>></code> 高阶的类型本身,不过理应顺带可以提取出内层的类型。</p><p>也罢,我这半吊子函数式爱好者还是要学习一个。</p>]]></content>
<summary type="html"><div class="note default no-icon">
<p>气温骤降,天冷的似乎要把脑子都冻僵,不禁感叹当初为什么选了一个网面的椅子。</p>
</div>
<h2 id="类型类型"><a class="anchor" href="#类型类型">#</a> 类型</summary>
<category term="俗世以外的消遣" scheme="https://blog.yukx.io/categories/%E4%BF%97%E4%B8%96%E4%BB%A5%E5%A4%96%E7%9A%84%E6%B6%88%E9%81%A3/"/>
<category term="言尽于行" scheme="https://blog.yukx.io/tags/%E8%A8%80%E5%B0%BD%E4%BA%8E%E8%A1%8C/"/>
<category term="类型系统" scheme="https://blog.yukx.io/tags/%E7%B1%BB%E5%9E%8B%E7%B3%BB%E7%BB%9F/"/>
</entry>
<entry>
<title>MiniValine 使用 Cloudflare Workers 反代LeanCloud API</title>
<link href="https://blog.yukx.io/2022/07/reverse-proxy-on-cloudflare-workers-access-leancloud-api/"/>
<id>https://blog.yukx.io/2022/07/reverse-proxy-on-cloudflare-workers-access-leancloud-api/</id>
<published>2022-07-27T00:02:39.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<div class="note info"><p>通过严谨的阅读公告,更深刻的理解了下内容,仅仅是不提供共享域名,你可以通过绑定自己的域名来继续使用服务。</p><p>不过本文的努力也没有全部白费,使用 Workers 可以隐藏自己的 Key,防止被奇奇怪怪的使用,甚至可以自己加点佐料,就这么安慰下自己吧。</p></div><p>首先,<a href="https://leancloudblog.com/2022-07-19-international-service-restrictions/">8 月 1 日起,国际版共享域名不再向中国大陆提供服务</a></p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220727160750.png" alt="官网公告" title="官网公告" /></p><p>虽然链接 404,但是公告可没有移除。</p><p>为了继续快乐白嫖,折腾了一整天,终于找到了<a href="https://github.com/MHuiG/MiniValine/tree/5/CF-LC">解决方案</a><span class="spoiler" title="你知道得太多了">并解决了解决方案里的问题成功上线</span></p><p>原本的代码写的一言难尽之余,跨域的访问一旦出错就是 CORS error,也真是天才般的设计。别人的问题在于给不支持跨域的 API 包装跨域,也许本方案不需要处理跨域也说不定…</p><p>需要格外注意的是修改访问人数是 <code>PUT</code> 请求,复制 request 的时候要对 body 特殊处理。</p><p>同时由于 Cloudflare Workers 自带域名 <code>*.workers.dev</code> 也是在我朝不可用的状态,需要配置自定义域名。Cloudflare Workers 的设置中已经提供了功能。<br />经尝试似乎要添加 <code>redirect: "follow"</code> 才能正常访问。</p><div class="note info"><p>自定义域名需要域名托管于 Cloudflare DNS 下,并且确认你的 SSL 设置不为 <code>Off</code> 以提供 HTTPS 访问,避免 <code>mixed content</code> 。</p></div><p>随后修改 <code>serverURLs</code> 为你的 Workers,按你的心情决定是否隐藏 AppKey。</p><p><span class="spoiler blur" title="你知道得太多了">各种错误轮番出现已经人晕了,每次改一点儿再撤销都回不到一个地方</span><br /><span class="spoiler blur" title="你知道得太多了">既然现在能用了我也懒得再改什么了,有人能提供优化的话也欢迎留言</span><br /><span class="spoiler blur" title="你知道得太多了">最开始还想在 MiniValine 基础上加个后端,结果 clone 下来一看</span><br /><span class="spoiler blur" title="你知道得太多了">代码像个麻花扭在一起,注入调用乱飞,告辞,我跟动态语言水火不容</span></p><figure class="highlight javascript"><figcaption data-lang="javascript"></figcaption><table><tr><td data-num="1"></td><td data-command=""></td><td><pre><span class="token comment">// src/index.js</span></pre></td></tr><tr><td data-num="2"></td><td data-command=""></td><td><pre><span class="token keyword">var</span> <span class="token maybe-class-name">AppId</span> <span class="token operator">=</span> <span class="token string">"--------------"</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td data-command=""></td><td><pre><span class="token keyword">var</span> <span class="token maybe-class-name">AppKey</span> <span class="token operator">=</span> <span class="token string">"--------------"</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td data-command=""></td><td><pre><span class="token keyword">var</span> <span class="token constant">ORIGINS</span> <span class="token operator">=</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td data-command=""></td><td><pre> <span class="token string-property property">"---------------"</span><span class="token operator">:</span> <span class="token string">"----------------"</span></pre></td></tr><tr><td data-num="6"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td data-command=""></td><td><pre><span class="token keyword">var</span> corsHeaders <span class="token operator">=</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="8"></td><td data-command=""></td><td><pre> <span class="token string-property property">"Access-Control-Allow-Origin"</span><span class="token operator">:</span> <span class="token string">"*"</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="9"></td><td data-command=""></td><td><pre> <span class="token string-property property">"Access-Control-Allow-Methods"</span><span class="token operator">:</span> <span class="token string">"GET,PUT,DELETE,HEAD,POST,OPTIONS"</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="10"></td><td data-command=""></td><td><pre> <span class="token string-property property">"Access-Control-Max-Age"</span><span class="token operator">:</span> <span class="token string">"86400"</span></pre></td></tr><tr><td data-num="11"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td data-command=""></td><td><pre><span class="token keyword">var</span> src_default <span class="token operator">=</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td data-command=""></td><td><pre> <span class="token keyword">async</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token parameter">request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="14"></td><td data-command="自定义域名"></td><td><pre> <span class="token keyword">let</span> rq <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Request</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">redirect</span><span class="token operator">:</span> <span class="token string">"follow"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">return</span> <span class="token function">handleRequest</span><span class="token punctuation">(</span>rq<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="17"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td data-command=""></td><td><pre><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">handleRequest</span><span class="token punctuation">(</span><span class="token parameter">request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token property-access">method</span> <span class="token operator">===</span> <span class="token string">"OPTIONS"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="20"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">return</span> <span class="token function">handleOptions</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="22"></td><td data-command=""></td><td><pre> <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token property-access">url</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">'Origin'</span><span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token constant">ORIGINS</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="24"></td><td data-command=""></td><td><pre> <span class="token comment">// const target = ORIGINS[url.hostname];</span></pre></td></tr><tr><td data-num="25"></td><td data-command=""></td><td><pre> url<span class="token punctuation">.</span><span class="token property-access">hostname</span> <span class="token operator">=</span> <span class="token string">"---------------"</span><span class="token operator">:</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> reqHEDNew <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Headers</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>reqHEDNew<span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"X-LC-Id"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="28"></td><td data-command=""></td><td><pre> reqHEDNew<span class="token punctuation">.</span><span class="token method function property-access">set</span><span class="token punctuation">(</span><span class="token string">"X-LC-Id"</span><span class="token punctuation">,</span> <span class="token maybe-class-name">AppId</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="29"></td><td data-command=""></td><td><pre> reqHEDNew<span class="token punctuation">.</span><span class="token method function property-access">set</span><span class="token punctuation">(</span><span class="token string">"X-LC-Key"</span><span class="token punctuation">,</span> <span class="token maybe-class-name">AppKey</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="30"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="31"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>reqHEDNew<span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"x-lc-sign"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="32"></td><td data-command=""></td><td><pre> reqHEDNew<span class="token punctuation">.</span><span class="token method function property-access">delete</span><span class="token punctuation">(</span><span class="token string">"x-lc-sign"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="33"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="34"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> reqNew<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="35"></td><td data-command="PUT请求"></td><td><pre> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token property-access">method</span> <span class="token operator">===</span> <span class="token string">"PUT"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="36"></td><td data-command=""></td><td><pre> reqNew <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"PUT"</span><span class="token punctuation">,</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> reqHEDNew<span class="token punctuation">,</span> <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token keyword control-flow">await</span> request<span class="token punctuation">.</span><span class="token method function property-access">arrayBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="37"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">else</span></pre></td></tr><tr><td data-num="38"></td><td data-command=""></td><td><pre> reqNew <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Request</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> reqHEDNew <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="39"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> responsefetch <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">.</span><span class="token method function property-access">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> reqNew<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="40"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> resHEDNew <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Headers</span><span class="token punctuation">(</span>responsefetch<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="41"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span>responsefetch<span class="token punctuation">.</span><span class="token property-access">body</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> resHEDNew <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="42"></td><td data-command=""></td><td><pre> response<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">.</span><span class="token method function property-access">set</span><span class="token punctuation">(</span><span class="token string">"Access-Control-Allow-Origin"</span><span class="token punctuation">,</span> <span class="token string">"*"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="43"></td><td data-command=""></td><td><pre> response<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">.</span><span class="token method function property-access">set</span><span class="token punctuation">(</span><span class="token string">"Access-Control-Allow-Methods"</span><span class="token punctuation">,</span> <span class="token string">"GET, POST, PUT, DELETE, OPTIONS"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="44"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">return</span> response<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="45"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="46"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">"nothing here"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="47"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="48"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="49"></td><td data-command=""></td><td><pre><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">handleOptions</span><span class="token punctuation">(</span><span class="token parameter">request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="50"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> headers <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="51"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>headers<span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"Origin"</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token keyword null nil">null</span> <span class="token operator">&&</span> headers<span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"Access-Control-Request-Method"</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token keyword null nil">null</span> <span class="token operator">&&</span> headers<span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"Access-Control-Request-Headers"</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token keyword null nil">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="52"></td><td data-command=""></td><td><pre> <span class="token keyword">let</span> respHeaders <span class="token operator">=</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="53"></td><td data-command=""></td><td><pre> <span class="token spread operator">...</span>corsHeaders<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="54"></td><td data-command=""></td><td><pre> <span class="token string-property property">"Access-Control-Allow-Headers"</span><span class="token operator">:</span> request<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"Access-Control-Request-Headers"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="55"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="56"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token keyword null nil">null</span><span class="token punctuation">,</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="57"></td><td data-command=""></td><td><pre> <span class="token literal-property property">headers</span><span class="token operator">:</span> respHeaders</pre></td></tr><tr><td data-num="58"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="59"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword control-flow">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="60"></td><td data-command=""></td><td><pre> <span class="token keyword control-flow">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token keyword null nil">null</span><span class="token punctuation">,</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="61"></td><td data-command=""></td><td><pre> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="62"></td><td data-command=""></td><td><pre> <span class="token literal-property property">Allow</span><span class="token operator">:</span> <span class="token string">"GET, HEAD, PUT,DELETE, POST, OPTIONS"</span></pre></td></tr><tr><td data-num="63"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="64"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="65"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="66"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="67"></td><td data-command=""></td><td><pre><span class="token keyword module">export</span> <span class="token exports"><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="68"></td><td data-command=""></td><td><pre> src_default <span class="token keyword module">as</span> <span class="token keyword module">default</span></pre></td></tr><tr><td data-num="69"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="70"></td><td data-command=""></td><td><pre><span class="token comment">//# sourceMappingURL=index.js.map</span></pre></td></tr></table></figure>]]></content>
<summary type="html"><div class="note info">
<p>通过严谨的阅读公告,更深刻的理解了下内容,仅仅是不提供共享域名,你可以通过绑定自己的域名来继续使用服务。</p>
<p>不过本文的努力也没有全部白费,使用 Workers 可以隐藏自己的 Key,防止被奇奇怪怪的使用,甚至可以</summary>
<category term="生命在于折腾" scheme="https://blog.yukx.io/categories/%E7%94%9F%E5%91%BD%E5%9C%A8%E4%BA%8E%E6%8A%98%E8%85%BE/"/>
<category term="MyBlog" scheme="https://blog.yukx.io/categories/%E7%94%9F%E5%91%BD%E5%9C%A8%E4%BA%8E%E6%8A%98%E8%85%BE/MyBlog/"/>
<category term="MiniValine" scheme="https://blog.yukx.io/tags/MiniValine/"/>
<category term="Cloudflare Workers" scheme="https://blog.yukx.io/tags/Cloudflare-Workers/"/>
<category term="LeanCloud国际版" scheme="https://blog.yukx.io/tags/LeanCloud%E5%9B%BD%E9%99%85%E7%89%88/"/>
</entry>
<entry>
<title>游戏开发日志 (其𝒾):ECS中的Buff系统实现思路</title>
<link href="https://blog.yukx.io/2022/07/game-dev-journal-i-ideas-of-a-buff-system-in-ECS/"/>
<id>https://blog.yukx.io/2022/07/game-dev-journal-i-ideas-of-a-buff-system-in-ECS/</id>
<published>2022-07-24T18:58:52.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>最近一直在磕 ECS,其将数据拆分为组件的想法深得我心,毕竟有些东西你总是要做了才知道合不合适,但是做完好不好改,可就不一定了。<br />学习了很多 ECS 的利弊,毕竟软件开发没有银弹,真实的世界处处充满了妥协。<br />而看到了有人说 Buff/Debuff 在 ECS 中很难高效实现,那今时不同往日,我自然是要试试,已经涌现了不少想法,必可活用于下一次。</p><h2 id="期望"><a class="anchor" href="#期望">#</a> 期望</h2><p>一个 Buff/Debuff,最为普遍的效果便是对数值的增减,对一个或数个数值,一个或数个 Buff 产生效果,作用到一个或数个目标。我们自然是希望这个系统可以比较好的描述这些行为。</p><h2 id="思路"><a class="anchor" href="#思路">#</a> 思路</h2><p>我们将一个 Buff 视为一个 Entity,Buff 的效果暂且仅关注各种数值的 <code>Modifier</code> ,因为很显然不作数值影响的各类 Buff 是必定要进行实现的,不能简单的复用。</p><p>这样一个 Buff 与被作用者的关系我们可以这样描述。</p><figure class="highlight mermaid"><figcaption data-lang="mermaid"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">flowchart</span> TB</pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">subgraph</span> BuffEntity<span class="token text string">["Buff (Entity)"]</span></pre></td></tr><tr><td data-num="3"></td><td><pre> b1<span class="token text string">["Buff (component)"]</span></pre></td></tr><tr><td data-num="4"></td><td><pre> b2<span class="token text string">["xxx Effect"]</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">end</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">subgraph</span> AffectedEntity<span class="token text string">["Affected Entity"]</span></pre></td></tr><tr><td data-num="7"></td><td><pre> a1<span class="token text string">["xxx Modifiable"]</span></pre></td></tr><tr><td data-num="8"></td><td><pre> a2<span class="token text string">["xxx Modification"]</span></pre></td></tr><tr><td data-num="9"></td><td><pre></pre></td></tr><tr><td data-num="10"></td><td><pre> a1 <span class="token arrow operator">--></span> a2</pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">end</span></pre></td></tr><tr><td data-num="12"></td><td><pre></pre></td></tr><tr><td data-num="13"></td><td><pre> a2 <span class="token arrow operator">--></span> b2</pre></td></tr><tr><td data-num="14"></td><td><pre> a2 <span class="token arrow operator">-.-></span> BuffEntity</pre></td></tr></table></figure><div class="note info"><p>此处仅表示逻辑上的关系。</p></div><p>通过实体上的 <code>Buff</code> 组件,我们可以以此来追踪 Buff 的作用时间,ECS 范式下普遍支持组件的移除检测,这样我们在 Buff 结束后仅将组件移除,而在 Buff 的实际实现中监测组件移除,就可以正确的移除 Buff 生效时添加的效果。</p><p><code>xxx Effect</code> 即为我们实现的 Buff 的标记在系统中查询区分。</p><p><code>xxx Modifiable</code> 是我们获取数值时查询的组件。而 <code>xxx Modification</code> 用于存储所有影响该组件的 Buff( <code>Modifier</code> s, <code>Buff</code> )。<br />则其实本系统与 <code>Modifiable</code> s 几乎是无关的,在对应 <code>Modification</code> 中 <code>Modifier</code> 与 <code>Buff</code> 实体对应存储,用于 Buff 效果的解除。只需要每次更新中按照<ruby>一定顺序<rp> (</rp><rt>大 坑</rt><rp>)</rp></ruby> 计算 <code>Modifier</code> 求值更新数值到 <code>Modifiable</code> 。</p><h3 id="关于计算顺序"><a class="anchor" href="#关于计算顺序">#</a> 关于计算顺序</h3><p>目前也有一点想法,可以使用优先队列,通过优先级排序确定计算顺序,但是需要注意的是,同优先级不能有两种不同的计算方法。</p><h2 id="bonus"><a class="anchor" href="#bonus">#</a> Bonus</h2><p>在此附上实验用到的代码,使用了 Bevy 实现,不过思路应该可以通用。</p><p>:::warn<br /> 声明:代码仅保证了没有<em>编译错误</em><sub> (笑)</sub>,未实际运行检验,也并不与上文所述思路完全一致。<span class="spoiler" title="你知道得太多了">这一切完全都是在实践中一点点发现不可行性后修补的结果的说…</span><br />:::</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token attribute attr-name">#[derive(Component)]</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Vision</span><span class="token punctuation">(</span><span class="token keyword">f32</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token attribute attr-name">#[derive(Component)]</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">Buff</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="6"></td><td><pre> target<span class="token punctuation">:</span> <span class="token class-name">Entity</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="7"></td><td><pre> from<span class="token punctuation">:</span> <span class="token class-name">Entity</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="8"></td><td><pre> duration<span class="token punctuation">:</span> <span class="token keyword">f32</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token attribute attr-name">#[derive(Component)]</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">VisionModification</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td><pre> ord1<span class="token punctuation">:</span> <span class="token class-name">Vec</span><span class="token operator"><</span><span class="token class-name">ModifierEffect</span><span class="token operator">></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="13"></td><td><pre> ord2<span class="token punctuation">:</span> <span class="token namespace">collections<span class="token punctuation">::</span></span><span class="token class-name">BTreeSet</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token keyword">i32</span><span class="token punctuation">,</span> <span class="token class-name">ModifierEffect</span><span class="token punctuation">,</span> <span class="token class-name">Entity</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token attribute attr-name">#[derive(Component)]</span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token keyword">pub</span> <span class="token keyword">enum</span> <span class="token type-definition class-name">ModifierEffect</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token class-name">ByValue</span><span class="token punctuation">(</span><span class="token keyword">f32</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token class-name">ByPercentage</span><span class="token punctuation">(</span><span class="token keyword">f32</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="19"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token attribute attr-name">#[derive(Component)]</span></pre></td></tr><tr><td data-num="21"></td><td><pre><span class="token keyword">pub</span> <span class="token keyword">struct</span> <span class="token type-definition class-name">VisionModifierEffect</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">buff_vision_modify_system</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token keyword">mut</span> commands<span class="token punctuation">:</span> <span class="token class-name">Commands</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">mut</span> vision_effects<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token class-name">Buff</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">ModifierEffect</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">With</span><span class="token operator"><</span><span class="token class-name">VisionModifierEffect</span><span class="token operator">>></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token keyword">mut</span> visions<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token class-name">Entity</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Vision</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">VisionModification</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token keyword">mut</span> visions_removed<span class="token punctuation">:</span> <span class="token class-name">RemovedComponents</span><span class="token operator"><</span><span class="token class-name">Buff</span><span class="token operator">></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="28"></td><td><pre><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span>buff<span class="token punctuation">,</span> vision_effect<span class="token punctuation">)</span> <span class="token keyword">in</span> vision_effects<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token keyword">let</span> vision <span class="token operator">=</span> visions<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>buff<span class="token punctuation">.</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token keyword">match</span> vision_effect <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token class-name">ModifierEffect</span><span class="token punctuation">::</span><span class="token class-name">ByValue</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="33"></td><td><pre> commands</pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>buff<span class="token punctuation">.</span>target<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Vision</span><span class="token punctuation">(</span>vision<span class="token number">.1</span> <span class="token punctuation">.</span><span class="token number">0</span> <span class="token operator">+</span> value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token class-name">ModifierEffect</span><span class="token punctuation">::</span><span class="token class-name">ByPercentage</span><span class="token punctuation">(</span>factor<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="38"></td><td><pre> commands</pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>buff<span class="token punctuation">.</span>target<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Vision</span><span class="token punctuation">(</span>vision<span class="token number">.1</span> <span class="token punctuation">.</span><span class="token number">0</span> <span class="token operator">*</span> factor<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="44"></td><td><pre></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token keyword">for</span> e <span class="token keyword">in</span> visions_removed<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token keyword">if</span> <span class="token keyword">let</span> <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token punctuation">(</span>buff<span class="token punctuation">,</span> effect<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">=</span> vision_effects<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token keyword">let</span> vision <span class="token operator">=</span> visions<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>buff<span class="token punctuation">.</span>target<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token keyword">match</span> effect <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token class-name">ModifierEffect</span><span class="token punctuation">::</span><span class="token class-name">ByValue</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="50"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Vision</span><span class="token punctuation">(</span>vision<span class="token number">.1</span> <span class="token punctuation">.</span><span class="token number">0</span> <span class="token operator">-</span> value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="51"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="52"></td><td><pre> <span class="token class-name">ModifierEffect</span><span class="token punctuation">::</span><span class="token class-name">ByPercentage</span><span class="token punctuation">(</span>factor<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="53"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Vision</span><span class="token punctuation">(</span>vision<span class="token number">.1</span> <span class="token punctuation">.</span><span class="token number">0</span> <span class="token operator">/</span> factor<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="54"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="55"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="56"></td><td><pre></pre></td></tr><tr><td data-num="57"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">despawn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="59"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="60"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="61"></td><td><pre></pre></td></tr><tr><td data-num="62"></td><td><pre><span class="token keyword">fn</span> <span class="token function-definition function">buff_duration_system</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="63"></td><td><pre> <span class="token keyword">mut</span> commands<span class="token punctuation">:</span> <span class="token class-name">Commands</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="64"></td><td><pre> <span class="token keyword">mut</span> buffs<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token class-name">Entity</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Buff</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="65"></td><td><pre> time<span class="token punctuation">:</span> <span class="token class-name">Res</span><span class="token operator"><</span><span class="token class-name">Time</span><span class="token operator">></span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="66"></td><td><pre><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="67"></td><td><pre> <span class="token keyword">for</span> mutable <span class="token keyword">in</span> buffs<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="68"></td><td><pre> mutable<span class="token number">.1</span><span class="token punctuation">.</span>duration <span class="token operator">-=</span> time<span class="token punctuation">.</span><span class="token function">delta</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">as_secs_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="69"></td><td><pre> <span class="token keyword">if</span> mutable<span class="token number">.1</span><span class="token punctuation">.</span>duration <span class="token operator"><=</span> <span class="token number">0.0</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="70"></td><td><pre> commands<span class="token punctuation">.</span><span class="token function">entity</span><span class="token punctuation">(</span>mutable<span class="token number">.0</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token class-name">Buff</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="71"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="72"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="73"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h2 id="bonus-plus"><a class="anchor" href="#bonus-plus">#</a> Bonus Plus</h2><p>最初的构想其实是使用接口抽象,每个 Buff 都实现此接口,作为组件挂在被作用对象的实体上,在 System 中通过接口来获取所有 Buff 组件进行处理。<br />但这样做问题很多,</p><blockquote><p>Unity ECS 支持查询接口,代价是无法使用高性能的 Burst 编译器,最重要的是多个影响某个数值的 Buff 无法结算 —— 其他同类型的组件不可见;且想要用泛型接口来统一时就会发现组件内不允许出现非值类型,即使最后实现接口的均是 <code>struct</code> 。</p><p>而在 Rust 中类似的方法时使用 traits 作为类型参数,而 trait objects 无法在编译时时确定大小需要装箱,那就要给 <code>Box<trait></code> 实现 <code>Component</code> ,也太怪了。</p></blockquote><p>最后一定要吐槽的是,Unity 的 ECS 文档目前写的真是屎一样,这样是最后尝试都在 Bevy 中做的原因。<br />虽然可能有还在 experimental 的缘故?看了一大堆不明所以的概念,最后试了一下确认了 System 创建后直接可以生效。也不得不说其实现也用着有点别扭(相对于 Bevy)。可能是我先入为主吗?或者说是基础设施对人潜意识的引导?总觉得现在 Unity 的 ECS<sup>0.51</sup> 有点不伦不类;写到这里我突然意识到没看到有创建 Entity 相关的内容,赶紧去找了下,嗯…<br />…<br /> 牌子、车、岔路.jpg</p>]]></content>
<summary type="html"><p>最近一直在磕 ECS,其将数据拆分为组件的想法深得我心,毕竟有些东西你总是要做了才知道合不合适,但是做完好不好改,可就不一定了。<br />
学习了很多 ECS 的利弊,毕竟软件开发没有银弹,真实的世界处处充满了妥协。<br />
而看到了有人说 Buff/Debuff 在</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="思路" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%80%9D%E8%B7%AF/"/>
<category term="ECS" scheme="https://blog.yukx.io/tags/ECS/"/>
<category term="Buff/Debuff System" scheme="https://blog.yukx.io/tags/Buff-Debuff-System/"/>
<category term="Modifiers" scheme="https://blog.yukx.io/tags/Modifiers/"/>
</entry>
<entry>
<title>游戏开发日志 (其π):Rust、Bevy & ECS</title>
<link href="https://blog.yukx.io/2022/07/game-dev-journal-pi-Rust-Bevy-and-ECS/"/>
<id>https://blog.yukx.io/2022/07/game-dev-journal-pi-Rust-Bevy-and-ECS/</id>
<published>2022-07-22T06:18:09.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<p>本来嘛,想着重构要趁早,现在也阶段性完成一部分内容,试着把项目用 Rust 重写,刚好最近了解了 <a href="https://bevyengine.org/">Bevy</a> 这个 Rust 写的使用 ECS 范式的游戏引擎,一举多得岂不美哉?</p><h2 id="初见"><a class="anchor" href="#初见">#</a> 初见</h2><p>看看这目录结构,好不整齐<br /><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220722222441.png" alt="directory" title="真好啊" /></p><p>数据使用组件完全打散,在系统中通过查询来获取组件或实体,可以说是彻底解决了我不知道要怎么组织代码才算好的问题,功能也都完全隔离开,可以说是没有耦合的机会了。</p><p>最先实现的则是地图网格生成,感觉上既不算是过于复杂,又足够可以踩坑了。</p><h2 id="试探"><a class="anchor" href="#试探">#</a> 试探</h2><p>于是果不其然,当前版本的 Bevy <sup>0.7.0</sup> 并没有物理系统,于是递归查找物理引擎的插件。<br />倒还真有 <a href="https://rapier.rs/docs/">Rapier</a> 这个 Rust 写的物理引擎,他们给 Bevy 写了一个物理引擎插件提供了物理系统。<br />但我们的主角却并非其人,而也正是这个插件,使我的心态发生了一点变化。</p><p><a href="https://github.com/jcornaz/heron">Heron</a>,基于 Rapier 提供了一套 API,看上去也挺对味<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>,使我选择了它。</p><p>由于没有诸如 <code>OverlapBox</code> 之类的助手函数,我只好按块在地图上生成<ruby>碰撞检测体<rp> (</rp><rt>Sensor</rt><rp>)</rp></ruby>,在下一帧中查询物体是否发生重叠。</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">..</span>grid<span class="token punctuation">.</span>width <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">for</span> j <span class="token keyword">in</span> <span class="token number">0</span><span class="token punctuation">..</span>grid<span class="token punctuation">.</span>height <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> world</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">.</span><span class="token function">spawn</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert_bundle</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token class-name">TransformBundle</span><span class="token operator">></span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token class-name">Transform</span><span class="token punctuation">::</span><span class="token function">from_translation</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="7"></td><td><pre> grid<span class="token punctuation">.</span><span class="token function">get_world_coordinate</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> j<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">.</span><span class="token function">with_scale</span><span class="token punctuation">(</span><span class="token class-name">MapGrid</span><span class="token punctuation">::</span><span class="token function">vec_size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">RigidBody</span><span class="token punctuation">::</span><span class="token class-name">Sensor</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">CollisionShape</span><span class="token punctuation">::</span><span class="token class-name">Cuboid</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="14"></td><td><pre> half_extends<span class="token punctuation">:</span> <span class="token class-name">MapGrid</span><span class="token punctuation">::</span><span class="token function">vec_size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token number">0.0</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="15"></td><td><pre> border_radius<span class="token punctuation">:</span> <span class="token class-name">None</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Collisions</span><span class="token punctuation">::</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">Tile</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td><pre> grid<span class="token punctuation">:</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> j<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="23"></td><td><pre>world<span class="token punctuation">.</span><span class="token function">insert_resource</span><span class="token punctuation">(</span><span class="token class-name">Tiled</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><div class="note info"><p>这里展示了创建实体的方法,在最后生成完砖块后在世界里添加 <code>Tiled</code> 资源,以在下一次调用时作为判断依据。</p></div><p>查询 Tile (存储着砖块的索引),和 Collision(存储着碰撞的信息),生成网格数据,<br />把 Entity 存起来后面清理用。<br />这样网格数据作为游戏内有唯一性的数据就作为 Resource 存储好了,随后切换<ruby>状态<rp> (</rp><rt>State</rt><rp>)</rp></ruby> 表示游戏可以开始了<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td data-command=""></td><td><pre><span class="token keyword">let</span> <span class="token keyword">mut</span> map_grid <span class="token operator">=</span> <span class="token class-name">MapGrid</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td data-command=""></td><td><pre> width<span class="token punctuation">:</span> map<span class="token punctuation">.</span>size<span class="token punctuation">.</span>x <span class="token keyword">as</span> <span class="token keyword">i32</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="3"></td><td data-command=""></td><td><pre> height<span class="token punctuation">:</span> map<span class="token punctuation">.</span>size<span class="token punctuation">.</span>y <span class="token keyword">as</span> <span class="token keyword">i32</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="4"></td><td data-command=""></td><td><pre> status<span class="token punctuation">:</span> <span class="token macro property">vec!</span><span class="token punctuation">[</span><span class="token class-name">MapStatus</span><span class="token punctuation">::</span><span class="token class-name">Empty</span><span class="token punctuation">;</span> <span class="token punctuation">(</span>map<span class="token punctuation">.</span>size<span class="token punctuation">.</span>x <span class="token operator">*</span> map<span class="token punctuation">.</span>size<span class="token punctuation">.</span>y<span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token keyword">usize</span><span class="token punctuation">]</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="5"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td data-command=""></td><td><pre><span class="token comment">// map is tiled, check tiles</span></pre></td></tr><tr><td data-num="7"></td><td data-command=""></td><td><pre><span class="token keyword">let</span> <span class="token keyword">mut</span> query <span class="token operator">=</span> world<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token punctuation">(</span><span class="token class-name">Entity</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Tile</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token class-name">Collisions</span><span class="token punctuation">)</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td data-command="我与编译器搏斗的证明"></td><td><pre><span class="token keyword">let</span> <span class="token keyword">mut</span> tile_entities <span class="token operator">=</span> <span class="token class-name">Vec</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td data-command="我与编译器搏斗的证明"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="10"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token keyword">let</span> <span class="token keyword">mut</span> tiles <span class="token operator">=</span> query<span class="token punctuation">.</span><span class="token function">iter</span><span class="token punctuation">(</span><span class="token operator">&</span>world<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span>e<span class="token punctuation">,</span> <span class="token class-name">Tile</span> <span class="token punctuation">{</span> grid<span class="token punctuation">:</span> pos <span class="token punctuation">}</span><span class="token punctuation">,</span> collision<span class="token punctuation">)</span> <span class="token keyword">in</span> tiles<span class="token punctuation">.</span><span class="token function">by_ref</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> map_grid<span class="token punctuation">[</span><span class="token punctuation">[</span>pos<span class="token punctuation">.</span>x <span class="token keyword">as</span> <span class="token keyword">usize</span><span class="token punctuation">,</span> pos<span class="token punctuation">.</span>y <span class="token keyword">as</span> <span class="token keyword">usize</span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">if</span> collision<span class="token punctuation">.</span><span class="token function">is_empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token class-name">MapStatus</span><span class="token punctuation">::</span><span class="token class-name">Empty</span></pre></td></tr><tr><td data-num="14"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="15"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token class-name">MapStatus</span><span class="token punctuation">::</span><span class="token class-name">Obstacle</span></pre></td></tr><tr><td data-num="16"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> tile_entities<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td data-command="我与编译器搏斗的证明"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="19"></td><td data-command="我与编译器搏斗的证明"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="20"></td><td data-command="我与编译器搏斗的证明"></td><td><pre></pre></td></tr><tr><td data-num="21"></td><td data-command=""></td><td><pre><span class="token keyword">for</span> t <span class="token keyword">in</span> tile_entities <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="22"></td><td data-command=""></td><td><pre> world<span class="token punctuation">.</span><span class="token function">despawn</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="24"></td><td data-command=""></td><td><pre>world<span class="token punctuation">.</span><span class="token function">remove_resource</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token class-name">Tiled</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="26"></td><td data-command=""></td><td><pre>world<span class="token punctuation">.</span><span class="token function">insert_resource</span><span class="token punctuation">(</span>map_grid<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td data-command=""></td><td><pre>world</pre></td></tr><tr><td data-num="28"></td><td data-command=""></td><td><pre> <span class="token punctuation">.</span><span class="token function">get_resource_mut</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token class-name">State</span><span class="token operator"><</span><span class="token class-name">GameState</span><span class="token operator">>></span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="29"></td><td data-command=""></td><td><pre> <span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="30"></td><td data-command=""></td><td><pre> <span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">GameState</span><span class="token punctuation">::</span><span class="token class-name">Game</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="31"></td><td data-command=""></td><td><pre> <span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><div class="note info"><p>中间突兀的大括号方法块是为了让其中的 world 不可变引用早日如土为安,不要妨碍后面的可变引用调用。<br />这里展示了查询组件和实体,进行操作的方法</p></div><h2 id="递进"><a class="anchor" href="#递进">#</a> 递进</h2><p>这里可以透露一下地图文件的设计,使用 json 存储,地图上的对象设计成内置、外置素材,方便进一步自定义。</p><p>这里值得一提的是 Rust 可以将 <code>Result<T, E></code> 的迭代器(不做处理的最终结果将是 <code>Vec<Result<T, E>></code> )收集为 <code>Result<Vec<T>, E></code> ,这样极大方便了对数组映射时的错误处理,真是百闻不如一见,令人耳目一新。<br />这样我就可以放心的返回一个 <code>Err</code> ,而它最终也会冒泡到闭包外部成为返回值。</p><figure class="highlight rust"><figcaption data-lang="rust"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">// pub fn load_map(path: &str) -> Result<Map, Box<dyn Error>></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">let</span> objects <span class="token operator">=</span> map<span class="token punctuation">[</span><span class="token string">"objects"</span><span class="token punctuation">]</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">.</span><span class="token function">into_iter</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>obj<span class="token closure-punctuation punctuation">|</span></span> <span class="token keyword">match</span> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"type"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token namespace">map_object_meta<span class="token punctuation">::</span></span><span class="token class-name">SpawnPoint</span><span class="token punctuation">::</span><span class="token constant">TYPENAME</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">let</span> position<span class="token punctuation">:</span> <span class="token class-name">Vec2</span> <span class="token operator">=</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="8"></td><td><pre> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"position"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="9"></td><td><pre> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"position"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">let</span> player <span class="token operator">=</span> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"player"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_i32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token class-name">MapObject</span><span class="token punctuation">::</span><span class="token class-name">SpawnPoint</span><span class="token punctuation">(</span><span class="token namespace">map_object_meta<span class="token punctuation">::</span></span><span class="token class-name">SpawnPoint</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="15"></td><td><pre> position<span class="token punctuation">,</span> player<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token namespace">map_object_meta<span class="token punctuation">::</span></span><span class="token class-name">Struct</span><span class="token punctuation">::</span><span class="token constant">TYPENAME</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token keyword">let</span> position<span class="token punctuation">:</span> <span class="token class-name">Vec2</span> <span class="token operator">=</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="20"></td><td><pre> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"position"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="21"></td><td><pre> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"position"</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_f32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token keyword">let</span> player <span class="token operator">=</span> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"player"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_i32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">let</span> group <span class="token operator">=</span> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"group"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_i32</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token keyword">let</span> source <span class="token operator">=</span> obj<span class="token number">.1</span><span class="token punctuation">[</span><span class="token string">"source"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">as_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok_or</span><span class="token punctuation">(</span><span class="token string">"map parsing err"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token class-name">Ok</span><span class="token punctuation">(</span><span class="token class-name">MapObject</span><span class="token punctuation">::</span><span class="token class-name">Struct</span><span class="token punctuation">(</span><span class="token namespace">map_object_meta<span class="token punctuation">::</span></span><span class="token class-name">Struct</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="29"></td><td><pre> position<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="30"></td><td><pre> player<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="31"></td><td><pre> group<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="32"></td><td><pre> source<span class="token punctuation">.</span><span class="token function">to_string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="35"></td><td><pre> _ <span class="token operator">=></span> <span class="token class-name">Err</span><span class="token punctuation">(</span><span class="token string">"unknown map object type"</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// Iter<Result<MapObject, &str>></span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">::</span><span class="token operator"><</span><span class="token class-name">Result</span><span class="token operator"><</span><span class="token class-name">Vec</span><span class="token operator"><</span>_<span class="token operator">></span><span class="token punctuation">,</span> _<span class="token operator">>></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>到这为止都还显得十分宁静祥和。</p><h2 id="终章"><a class="anchor" href="#终章">#</a> 𝆑𝆑𝆑 终章</h2><p>那么很自然的,我要生成地图了,我要生成地图边界了,我发现没有这样一个碰撞体。</p><p>Heron 声明提供底层 Rapier 的功能,我找到这样的碰撞体了,我找到所在的模块了,我发现这个 <code>struct</code> 没有 <code>#[derive(Component)]</code> 。</p><p>ℱ𝒾𝓃.</p><hr /><p>不过此处折腾也不能说是一无所获,本文也没有任何抱怨的意思,Rust、Bevy 可以说未来可期了。不过一无所有的我还是要以完成项目为优先事项,暂别。</p><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>相比 Rapier,使用内置的 Vector 类型,API 也更加简单 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>其实不应该写在这里,而应该单独写一个系统用于检查资源是否准备完成切换状态,不过现在姑且还算简单就先这么写了。 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
<summary type="html"><p>本来嘛,想着重构要趁早,现在也阶段性完成一部分内容,试着把项目用 Rust 重写,刚好最近了解了 <a href="https://bevyengine.org/">Bevy</a> 这个 Rust 写的使用 ECS 范式的游戏引擎,一举多得岂不美哉?</p>
<h2 id</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Bevy" scheme="https://blog.yukx.io/tags/Bevy/"/>
<category term="Rust" scheme="https://blog.yukx.io/tags/Rust/"/>
<category term="ECS" scheme="https://blog.yukx.io/tags/ECS/"/>
</entry>
<entry>
<title>游戏开发日志 (其四·一):迷雾大小与物体实际大小不一致的原因</title>
<link href="https://blog.yukx.io/2022/07/game-dev-journal-4-1-mismatching-fog-size-with-obstacle-size/"/>
<id>https://blog.yukx.io/2022/07/game-dev-journal-4-1-mismatching-fog-size-with-obstacle-size/</id>
<published>2022-07-18T05:28:50.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>在上一篇的最后,可以看到小尺寸的障碍物有着与之不匹配的巨大遮挡面积。</p><p>—— 这里不得不补充下:尚未书面记录的,本项目使用了 「地图」 这一概念,目前的运行场景中包含编辑器中添加的物体和读取地图文件后运行时添加的物体。在地图生成完成后调用初始化网格。</p><p>所以合理怀疑到了地图生成阶段。</p><p><a href="#%E7%AD%94%E6%A1%88%E5%91%BC%E4%B9%8B%E6%AC%B2%E5%87%BA">太长不看</a></p><h3 id="gizmos"><a class="anchor" href="#gizmos">#</a> Gizmos</h3><p>为了 Debug,学习了下原项目中绘制地图网格的操作,在 Hierarchy 中选中对象,可以将生成的网格显示到屏幕上。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">private</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnDrawGizmosSelected</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> </pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>mapGrid <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="6"></td><td><pre> Gizmos<span class="token punctuation">.</span>color <span class="token operator">=</span> Color<span class="token punctuation">.</span>blue<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> Gizmos<span class="token punctuation">.</span><span class="token function">DrawWireCube</span><span class="token punctuation">(</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">*</span> mapGrid<span class="token punctuation">.</span>GridSize<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre> Gizmos<span class="token punctuation">.</span>color <span class="token operator">=</span> mapGrid<span class="token punctuation">[</span>i<span class="token punctuation">,</span> j<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">HasFlag</span><span class="token punctuation">(</span>MapGrid<span class="token punctuation">.</span>MapStatus<span class="token punctuation">.</span>Obstacle<span class="token punctuation">)</span> <span class="token punctuation">?</span> Color<span class="token punctuation">.</span>red <span class="token punctuation">:</span> Color<span class="token punctuation">.</span>white<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> Gizmos<span class="token punctuation">.</span><span class="token function">DrawWireCube</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span><span class="token function">GetRealPosition</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span>j<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>GridSize<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>GridSize<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>地图可视化后,发现右侧小障碍物在网格中的大小似乎与左下侧大障碍物(编辑器中的 Prefab 原型)相近,而该小障碍物是在运行后创建的对象,其大小是从地图文件中读取缩放值后设定的。</p><figure class="highlight json"><figcaption data-lang="JSON"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token property">"scale"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">Vector3</span> scale <span class="token operator">=</span> st<span class="token punctuation">.</span>scale<span class="token punctuation">;</span> scale<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre>st_in<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>localScale <span class="token operator">=</span> scale<span class="token punctuation">;</span></pre></td></tr></table></figure><p>而尝试将其变得更大后,发现遮挡面积并未改变,</p><h3 id="答案呼之欲出"><a class="anchor" href="#答案呼之欲出">#</a> 答案呼之欲出</h3><p>—— localScale 并非立即生效,所以生成阶段设置 scale,生效延后到了生成阶段完成网格初始化之后,可能是在下一帧中生效?</p><p>使用 <code>Invoke</code> 延迟网格初始化后问题也成功解决。</p><div class="note default"><p>这个异常的迷雾没有碰撞体积,走在里面会丢失周围一切的视野,只能看到周围一圈,外面自然也无法看到里面<br />其实还挺酷的,「黑域」,后续可以专门搞一个。</p></div><h3 id="另外的小收获"><a class="anchor" href="#另外的小收获">#</a> 另外的小收获</h3><p>在上一篇的缓动函数 <code>Lerp</code> 中<br />将</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre>Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>nextTexture<span class="token punctuation">,</span> currnetTexture<span class="token punctuation">,</span> blurMaterial<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>中的 <code>pass</code> 传入参数 <code>1</code> 改为 <code>0</code> ,可以避免迷雾的透明度的提升导致可以透过未探索迷雾看到地形。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220718220522.png" alt="新效果" /></p>]]></content>
<summary type="html"><p>在上一篇的最后,可以看到小尺寸的障碍物有着与之不匹配的巨大遮挡面积。</p>
<p>—— 这里不得不补充下:尚未书面记录的,本项目使用了 「地图」 这一概念,目前的运行场景中包含编辑器中添加的物体和读取地图文件后运行时添加的物体。在地图生成完成后调用初始化网格。</p>
<</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Unity" scheme="https://blog.yukx.io/tags/Unity/"/>
<category term="战争迷雾" scheme="https://blog.yukx.io/tags/%E6%88%98%E4%BA%89%E8%BF%B7%E9%9B%BE/"/>
<category term="localScale" scheme="https://blog.yukx.io/tags/localScale/"/>
</entry>
<entry>
<title>游戏开发日志 (其四):战争迷雾</title>
<link href="https://blog.yukx.io/2022/07/game-dev-journal-4-fog-of-war/"/>
<id>https://blog.yukx.io/2022/07/game-dev-journal-4-fog-of-war/</id>
<published>2022-07-17T17:15:11.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<div class="note info"><p>本文基于<a href="https://www.bilibili.com/video/BV1tt411j7Zr?share_source=copy_web">【基于视野的战争迷雾实现】Unity 战争迷雾实现</a> <a href="https://space.bilibili.com/3981300">@琴桌</a> 实现。<br /><a href="https://github.com/QinZhuo/FogOfWar_ForUnity">Github</a></p></div><div class="note default"><p>一个月的磕磕绊绊终于是完成了效果,总感觉既然当初察觉了掌握 ECS 的契机不如直接上手,现在纠结这些对象、类功能的划分实属难受。<br />旁人的打断,自己的摆烂,想到这里,不禁潸然。</p></div><h2 id="概述"><a class="anchor" href="#概述">#</a> 概述</h2><p>总体上的思路为将地图按方块划分,将地图上的障碍物标记出来,对每个有视野的单位进行射线检测判断视野是否被遮挡,将方块化的视野转换为 RenderTexture 作为迷雾对象的材质渲染到地图的上方。</p><h2 id="地图块"><a class="anchor" href="#地图块">#</a> 地图块</h2><h3 id="地图块定义"><a class="anchor" href="#地图块定义">#</a> 地图块定义</h3><p>使用一个枚举代表一个地图块的状态</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">MapStatus</span><span class="token punctuation">:</span><span class="token type-list"><span class="token keyword">byte</span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> Empty<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre> Obstacle<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="5"></td><td><pre> AllyUnit<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="6"></td><td><pre> EnemeyUnit<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="7"></td><td><pre> SelfUnit</pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token comment">// 整个地图的地图块</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token class-name">MapStatus<span class="token punctuation">[</span><span class="token punctuation">,</span><span class="token punctuation">]</span></span> innerMap<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token comment">// 地图宽高</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> Width <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token operator">=></span> innerMap<span class="token punctuation">.</span><span class="token function">GetLength</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> Height <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token operator">=></span> innerMap<span class="token punctuation">.</span><span class="token function">GetLength</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token comment">// 地图块的边长</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">float</span></span> GridSize <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="地图块索引"><a class="anchor" href="#地图块索引">#</a> 地图块索引</h3><p>对地图的索引到真实位置的转换则有</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name">Vector2</span> <span class="token function">GetRealPosition</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> x<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">int</span></span> y<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector2</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">(</span>x <span class="token operator">-</span> Width <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">0.5f</span><span class="token punctuation">)</span> <span class="token operator">*</span> GridSize<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">(</span>y <span class="token operator">-</span> Height <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">0.5f</span><span class="token punctuation">)</span> <span class="token operator">*</span> GridSize</pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name">Vector2Int</span> <span class="token function">GetGridPosition</span><span class="token punctuation">(</span><span class="token class-name">Vector2</span> position<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector2Int</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">(</span>position<span class="token punctuation">.</span>x <span class="token operator">/</span> GridSize <span class="token operator">+</span> Width <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">0.5f</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">(</span>position<span class="token punctuation">.</span>y <span class="token operator">/</span> GridSize <span class="token operator">+</span> Height <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">0.5f</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">IsInMap</span><span class="token punctuation">(</span><span class="token class-name">Vector2Int</span> pos<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">return</span> <span class="token punctuation">(</span>pos<span class="token punctuation">.</span>x <span class="token operator">>=</span> <span class="token number">0</span> <span class="token operator">&&</span> pos<span class="token punctuation">.</span>x <span class="token operator"><=</span> Width<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>pos<span class="token punctuation">.</span>y <span class="token operator">>=</span> <span class="token number">0</span> <span class="token operator">&&</span> pos<span class="token punctuation">.</span>y <span class="token operator"><=</span> Height<span class="token punctuation">)</span><span class="token punctuation">;</span> </pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="地图块生成"><a class="anchor" href="#地图块生成">#</a> 地图块生成</h3><p>对于地图,可以使用 <code>Physics2D.OverlapBox()</code> <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> 来判断地图块状态,使用了 <code>Solid Unit</code> 作为障碍物的 Layer,排除其他单位碰撞体。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> Width<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> Height<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> box <span class="token operator">=</span> Physics2D<span class="token punctuation">.</span><span class="token function">OverlapBox</span><span class="token punctuation">(</span><span class="token function">GetRealPosition</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> j<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector2</span><span class="token punctuation">(</span>GridSize<span class="token punctuation">,</span> GridSize<span class="token punctuation">)</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> LayerMask<span class="token punctuation">.</span><span class="token function">GetMask</span><span class="token punctuation">(</span><span class="token string">"Solid Unit"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>box <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> innerMap<span class="token punctuation">[</span>i<span class="token punctuation">,</span> j<span class="token punctuation">]</span> <span class="token operator">=</span> MapStatus<span class="token punctuation">.</span>Obstacle<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">else</span> innerMap<span class="token punctuation">[</span>i<span class="token punctuation">,</span> j<span class="token punctuation">]</span> <span class="token operator">=</span> MapStatus<span class="token punctuation">.</span>Empty<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr></table></figure><h2 id="单位视野"><a class="anchor" href="#单位视野">#</a> 单位视野</h2><p>使用一个 Behavior 存储单位视野相关的数据</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UnitVision</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">SerializeField</span></span><span class="token punctuation">]</span> <span class="token comment">// 这个 Attribute 可以让变量显示在 Inspector 窗口中</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> sightRange <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">float</span></span> <span class="token function">GetSight</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">return</span> sightRange<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h2 id="迷雾生成"><a class="anchor" href="#迷雾生成">#</a> 迷雾生成</h2><p>首先归纳下现有代码,将<a href="#%E5%9C%B0%E5%9B%BE%E5%9D%97">地图块</a>内代码均包装为 <code>MapGrid</code> 类</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MapGrid</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="基本设施"><a class="anchor" href="#基本设施">#</a> 基本设施</h3><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FogMaker</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token comment">// 地图网格</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">MapGrid</span> mapGrid<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token comment">// 观察者</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token class-name">List<span class="token punctuation"><</span>UnitVision<span class="token punctuation">></span></span> viewers <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token comment">// 迷雾颜色信息</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token class-name">Color32<span class="token punctuation">[</span><span class="token punctuation">]</span></span> colorBuffer<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token comment">// 网格索引转换为颜色索引</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">int</span></span> <span class="token function">ColorIndex</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> x<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">int</span></span> y<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre> x <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> y <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>y<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token keyword">return</span> x <span class="token operator">+</span> y <span class="token operator">*</span> mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Init</span><span class="token punctuation">(</span><span class="token class-name">MapGrid</span> map<span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token comment">// 初始化迷雾为不透明黑色</span></pre></td></tr><tr><td data-num="18"></td><td><pre> colorBuffer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Color32</span><span class="token punctuation">[</span>mapGrid<span class="token punctuation">.</span>Length<span class="token punctuation">]</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> Array<span class="token punctuation">.</span><span class="token function">Fill</span><span class="token punctuation">(</span>colorBuffer<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Color32</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token comment">// ... </span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="迷雾的计算"><a class="anchor" href="#迷雾的计算">#</a> 迷雾的计算</h3><p>对每个观察者,获取视野范围内的方块</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> v <span class="token keyword">in</span> viewers<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> pos <span class="token operator">=</span> mapGrid<span class="token punctuation">.</span><span class="token function">GetGridPosition</span><span class="token punctuation">(</span>v<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> sight_radius <span class="token operator">=</span> v<span class="token punctuation">.</span><span class="token function">GetSight</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> mapGrid<span class="token punctuation">.</span>GridSize<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> sight_square <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>sight_radius <span class="token operator">*</span> sight_radius<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token class-name">List<span class="token punctuation"><</span>Vector2Int<span class="token punctuation">></span></span> curVisionPos <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> i <span class="token operator">=</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>sight_radius<span class="token punctuation">;</span> i <span class="token operator"><=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>sight_radius<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> j <span class="token operator">=</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>sight_radius<span class="token punctuation">;</span> j <span class="token operator"><=</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>sight_radius<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">*</span> i <span class="token operator">+</span> j <span class="token operator">*</span> j <span class="token operator"><=</span> sight_square<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token comment">// 该坐标处于可视范围内 且处于地图内</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> p <span class="token operator">=</span> pos <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector2Int</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> j<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span><span class="token function">IsInMap</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="16"></td><td><pre> curVisionPos<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="19"></td><td><pre> </pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="21"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>对获取到的方块,将其与观察者连线,判断中间是否有障碍物遮挡,若有则从视野中移除。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">// 由远到近排序</span></pre></td></tr><tr><td data-num="2"></td><td><pre>curVisionPos<span class="token punctuation">.</span><span class="token function">Sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">DistanceSquared</span><span class="token punctuation">(</span>pos<span class="token punctuation">,</span> b<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token function">DistanceSquared</span><span class="token punctuation">(</span>pos<span class="token punctuation">,</span> a<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token class-name">HashSet<span class="token punctuation"><</span>Vector2Int<span class="token punctuation">></span></span> visited <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> novision <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> p <span class="token keyword">in</span> curVisionPos<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>visited<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">var</span> <span class="token punctuation">(</span>blocked<span class="token punctuation">,</span> unblocked<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token function">GetBlockedAndUnblocked</span><span class="token punctuation">(</span>pos<span class="token punctuation">,</span>p<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre> novision<span class="token punctuation">.</span><span class="token function">UnionWith</span><span class="token punctuation">(</span>blocked<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> visited<span class="token punctuation">.</span><span class="token function">UnionWith</span><span class="token punctuation">(</span>blocked<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> visited<span class="token punctuation">.</span><span class="token function">UnionWith</span><span class="token punctuation">(</span>unblocked<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token comment">// 移除无视野</span></pre></td></tr><tr><td data-num="17"></td><td><pre>curVisionPos<span class="token punctuation">.</span><span class="token function">RemoveAll</span><span class="token punctuation">(</span>p <span class="token operator">=></span> novision<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token comment">// 将视野区域设置为透明</span></pre></td></tr><tr><td data-num="19"></td><td><pre><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> p <span class="token keyword">in</span> curVisionPos<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="21"></td><td><pre> colorBuffer<span class="token punctuation">[</span><span class="token function">ColorIndex</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>这里首先按照由远到近的距离将方块排序,提高后续计算效率,因为在计算遮挡时会将所有被遮挡和不被遮挡的方块返回,可以尽可能多的排除 visited 方块。</p><h4 id="射线检测函数"><a class="anchor" href="#射线检测函数">#</a> 射线检测函数</h4><p>由起点向终点逐方块检测是否有障碍物,若遇到障碍物则后续方块均为无视野的遮挡区域。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token punctuation">(</span>List<span class="token punctuation"><</span>Vector2Int<span class="token punctuation">></span><span class="token punctuation">,</span> List<span class="token punctuation"><</span>Vector2Int<span class="token punctuation">></span><span class="token punctuation">)</span></span> <span class="token function">GetBlockedAndUnblocked</span><span class="token punctuation">(</span><span class="token class-name">Vector2Int</span> source<span class="token punctuation">,</span> <span class="token class-name">Vector2Int</span> target<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> blocked <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span>Vector2Int<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> unblocked <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span>Vector2Int<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> delta <span class="token operator">=</span> target <span class="token operator">-</span> source<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token comment">// 起始位置相同</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>delta<span class="token punctuation">.</span>sqrMagnitude <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>mapGrid<span class="token punctuation">[</span>source<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> source<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">HasFlag</span><span class="token punctuation">(</span>MapGrid<span class="token punctuation">.</span>MapStatus<span class="token punctuation">.</span>Obstacle<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="11"></td><td><pre> blocked<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">else</span> unblocked<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">return</span> <span class="token punctuation">(</span>blocked<span class="token punctuation">,</span> unblocked<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre> unblocked<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token class-name"><span class="token keyword">bool</span></span> blockMet <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token comment">// 判断 X 或 Y 作为基础步长方向</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">Abs</span><span class="token punctuation">(</span>delta<span class="token punctuation">.</span>x<span class="token punctuation">)</span> <span class="token operator">></span> Math<span class="token punctuation">.</span><span class="token function">Abs</span><span class="token punctuation">(</span>delta<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">{</span><span class="token comment">// X 轴为方向</span></pre></td></tr><tr><td data-num="22"></td><td><pre> </pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token comment">// 符号</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token class-name"><span class="token keyword">int</span></span> x_sign <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">Sign</span><span class="token punctuation">(</span>delta<span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token comment">// 增量</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> y_inc <span class="token operator">=</span> <span class="token punctuation">(</span>delta<span class="token punctuation">.</span>y <span class="token operator">/</span> <span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">)</span> Math<span class="token punctuation">.</span><span class="token function">Abs</span><span class="token punctuation">(</span>delta<span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> step_y <span class="token operator">=</span> y_inc<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> step_x <span class="token operator">=</span> x_sign<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="29"></td><td><pre> x_sign <span class="token operator">*</span> step_x <span class="token operator"><=</span> x_sign <span class="token operator">*</span> delta<span class="token punctuation">.</span>x<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="30"></td><td><pre> step_x<span class="token operator">+=</span>x_sign<span class="token punctuation">,</span> step_y<span class="token operator">+=</span>y_inc<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> s <span class="token operator">=</span> source <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector2Int</span><span class="token punctuation">(</span>step_x<span class="token punctuation">,</span> Mathf<span class="token punctuation">.</span><span class="token function">RoundToInt</span><span class="token punctuation">(</span>step_y<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="33"></td><td><pre></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>blockMet<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="36"></td><td><pre> unblocked<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="37"></td><td><pre> blockMet <span class="token operator">=</span> mapGrid<span class="token punctuation">[</span>s<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">HasFlag</span><span class="token punctuation">(</span>MapGrid<span class="token punctuation">.</span>MapStatus<span class="token punctuation">.</span>Obstacle<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token keyword">else</span></pre></td></tr><tr><td data-num="40"></td><td><pre> blocked<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token keyword">else</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token comment">// 方向为 Y 轴的情况与 X 轴基本相同,只需调换 x、y 的角色即可</span></pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token comment">// ...</span></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="48"></td><td><pre></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token keyword">return</span> <span class="token punctuation">(</span>blocked<span class="token punctuation">,</span> unblocked<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="50"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="迷雾刷新"><a class="anchor" href="#迷雾刷新">#</a> 迷雾刷新</h3><p>在区域丢失视野时重新覆盖一层半透明的已探索迷雾</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">RefreshFog</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">int</span></span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> colorBuffer<span class="token punctuation">.</span>Length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>colorBuffer<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>a <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> colorBuffer<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token number">180</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>配合使用可以实现战争迷雾 -(未) 探索区域的效果。</p><h3 id="迷雾贴图"><a class="anchor" href="#迷雾贴图">#</a> 迷雾贴图</h3><div class="note info"><p>Shader、材质、纹理,属实头大住了,并没有完全理解此部分的流程,不过姑且实现了效果</p></div><p>初始化资源</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">Material</span> blurMaterial<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token class-name">Texture2D</span> textureBuffer<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token class-name">RenderTexture</span> renderTexture<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token class-name">RenderTexture</span> renderTexture2<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token class-name">RenderTexture</span> nextTexture<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token class-name">RenderTexture</span> currnetTexture<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Init</span><span class="token punctuation">(</span><span class="token class-name">MapGrid</span> map<span class="token punctuation">)</span><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token comment">// ... </span></pre></td></tr><tr><td data-num="10"></td><td><pre> blurMaterial <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Material</span><span class="token punctuation">(</span>Shader<span class="token punctuation">.</span><span class="token function">Find</span><span class="token punctuation">(</span><span class="token string">"ImageEffect/AverageBlur"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> textureBuffer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Texture2D</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">,</span> TextureFormat<span class="token punctuation">.</span>ARGB32<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> renderTexture <span class="token operator">=</span> RenderTexture<span class="token punctuation">.</span><span class="token function">GetTemporary</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> renderTexture2 <span class="token operator">=</span> RenderTexture<span class="token punctuation">.</span><span class="token function">GetTemporary</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre></pre></td></tr><tr><td data-num="15"></td><td><pre> nextTexture <span class="token operator">=</span> RenderTexture<span class="token punctuation">.</span><span class="token function">GetTemporary</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre> currnetTexture <span class="token operator">=</span> RenderTexture<span class="token punctuation">.</span><span class="token function">GetTemporary</span><span class="token punctuation">(</span>mapGrid<span class="token punctuation">.</span>Width<span class="token punctuation">,</span> mapGrid<span class="token punctuation">.</span>Height<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token comment">// 在销毁时释放资源</span></pre></td></tr><tr><td data-num="19"></td><td><pre><span class="token keyword">private</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnDestroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token function">Release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Release</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="24"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="25"></td><td><pre> RenderTexture<span class="token punctuation">.</span><span class="token function">ReleaseTemporary</span><span class="token punctuation">(</span>renderTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> RenderTexture<span class="token punctuation">.</span><span class="token function">ReleaseTemporary</span><span class="token punctuation">(</span>renderTexture2<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> RenderTexture<span class="token punctuation">.</span><span class="token function">ReleaseTemporary</span><span class="token punctuation">(</span>currnetTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> RenderTexture<span class="token punctuation">.</span><span class="token function">ReleaseTemporary</span><span class="token punctuation">(</span>nextTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="29"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>使用颜色信息生成 Texture,并进行几次模糊</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">MakeTextureAndBlur</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> textureBuffer<span class="token punctuation">.</span><span class="token function">SetPixels32</span><span class="token punctuation">(</span>colorBuffer<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> textureBuffer<span class="token punctuation">.</span><span class="token function">Apply</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre> Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>textureBuffer<span class="token punctuation">,</span> renderTexture<span class="token punctuation">,</span> blurMaterial<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> </pre></td></tr><tr><td data-num="8"></td><td><pre> Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>renderTexture<span class="token punctuation">,</span> renderTexture2<span class="token punctuation">,</span> blurMaterial<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>renderTexture2<span class="token punctuation">,</span> renderTexture<span class="token punctuation">,</span> blurMaterial<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre> Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>renderTexture<span class="token punctuation">,</span> nextTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>缓动,在两帧迷雾间过渡</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Lerp</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>currnetTexture<span class="token punctuation">,</span> renderTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> blurMaterial<span class="token punctuation">.</span><span class="token function">SetTexture</span><span class="token punctuation">(</span><span class="token string">"_LastTex"</span><span class="token punctuation">,</span> renderTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> Graphics<span class="token punctuation">.</span><span class="token function">Blit</span><span class="token punctuation">(</span>nextTexture<span class="token punctuation">,</span> currnetTexture<span class="token punctuation">,</span> blurMaterial<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>在每次更新时更新迷雾</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">private</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token function">RefreshFog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token function">ComputeFog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token function">MakeTextureAndBlur</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token function">Lerp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>对外提供 Texture 获取</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name">RenderTexture</span> FogTexture <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token operator">=></span> currnetTexture<span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr></table></figure><h2 id="迷雾渲染"><a class="anchor" href="#迷雾渲染">#</a> 迷雾渲染</h2><p>获取渲染迷雾的对象的材质,每次更新时将生成的 FogTexture 赋予到材质即可。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td data-command=""></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FogRenderer</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span></pre></td></tr><tr><td data-num="2"></td><td data-command=""></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td data-command=""></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">GameObject</span> fogRenderer<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td data-command=""></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">FogMaker</span> fogMaker<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td data-command=""></td><td><pre> </pre></td></tr><tr><td data-num="6"></td><td data-command=""></td><td><pre> <span class="token class-name">Material</span> fogMaterial<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td data-command=""></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td data-command=""></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td data-command=""></td><td><pre> fogMaterial <span class="token operator">=</span> fogRenderer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Renderer<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>material<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="11"></td><td data-command=""></td><td><pre> <span class="token comment">// Update is called once per frame</span></pre></td></tr><tr><td data-num="12"></td><td data-command=""></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="13"></td><td data-command=""></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="14"></td><td data-command=""></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>fogMaker<span class="token punctuation">.</span>FogTexture <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="15"></td><td data-command=""></td><td><pre> fogMaterial<span class="token punctuation">.</span><span class="token function">SetTexture</span><span class="token punctuation">(</span><span class="token string">"_MainTex"</span><span class="token punctuation">,</span> fogMaker<span class="token punctuation">.</span>FogTexture<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="17"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>为 fogRenderer 添加如下组件</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220718140108.png" alt="示例" /></p><div class="note info"><p>在 2D 项目中使用 Plane 需要进行旋转,确保方向符合你的要求。</p><p>MeshRenderer 的材质是使用 Shader 创建的,见<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL1FpblpodW8vRm9nT2ZXYXJfRm9yVW5pdHkvdHJlZS9tYXN0ZXIvQXNzZXRzL0ZvZ09mV2FyL1NoYWRlcnM=" title="Shaders">此</span></p></div><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220718140207.png" alt="效果展示" /></p><div class="note default"><p>意外的实现了一个草丛呢… 真是世事难料。<br />在本章节中的 MapGrid 可以基于此上进一步来实现寻路系统,敬请期待。</p></div><hr class="footnotes-sep" /><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>对于 3D 项目,使用 <code>Physics.CheckBox()</code> <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
<summary type="html"><div class="note info">
<p>本文基于<a href="https://www.bilibili.com/video/BV1tt411j7Zr?share_source=copy_web">【基于视野的战争迷雾实现】Unity 战争迷雾实现</a> <a </summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Unity" scheme="https://blog.yukx.io/tags/Unity/"/>
<category term="战争迷雾" scheme="https://blog.yukx.io/tags/%E6%88%98%E4%BA%89%E8%BF%B7%E9%9B%BE/"/>
<category term="地图网格" scheme="https://blog.yukx.io/tags/%E5%9C%B0%E5%9B%BE%E7%BD%91%E6%A0%BC/"/>
</entry>
<entry>
<title>游戏开发日志 (其三):单位移动</title>
<link href="https://blog.yukx.io/2022/06/game-dev-journal-3-unit-move/"/>
<id>https://blog.yukx.io/2022/06/game-dev-journal-3-unit-move/</id>
<published>2022-06-15T18:20:49.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p><span class="spoiler blur" title="你知道得太多了">我还真时跟对象没有缘分,这几天的闷头搞事竟然还算摸到了一点 ECS 的边。选语言也是放着一众 OOP 不管一头扎进了函数式的坑,偏偏玩的还很菜。</span></p><h2 id="移动"><a class="anchor" href="#移动">#</a> 移动</h2><div class="note default no-icon"><p>本来以为近期可能不太有什么可以说道的事了,还是低估了游戏开发的奥妙,从头搭建一个世界真的是塔诺西呐。</p></div><p>移动这个过程首先是转向,面向要前往的方向,开始前进是一个很自然,很符合直觉的过程,所以这里我也加上了需要转过身来才能移动的限制。</p><div class="note info"><p>这里直接使用了我觉得很妙的组织方法,如果说可能有潜在的性能问题,应该也能方便的转写成 ECS 的模式(大概)</p></div><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">// Unity 会自动为我们添加依赖的 Rigidbody 组件</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">[</span><span class="token function">RequireComponent</span><span class="token punctuation">(</span><span class="token keyword">typeof</span><span class="token punctuation">(</span><span class="token type-expression class-name">Rigidbody2D</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Movable</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">MonoBehaviour</span></span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token class-name">Rigidbody2D</span> rigid<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token comment">// 可移动单位的属性</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> moveSpeed <span class="token operator">=</span> <span class="token number">300</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> rotateSpeed <span class="token operator">=</span> <span class="token number">800</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token comment">// 移动过程的参数</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token class-name">Vector2</span> destination<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token return-type class-name">Vector2</span> direction <span class="token operator">=></span> destination <span class="token operator">-</span> rigid<span class="token punctuation">.</span>position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token class-name"><span class="token keyword">bool</span></span> isMoving <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token comment">// 一些温暖人心的状态判断</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> IsIdling <span class="token operator">=></span> <span class="token operator">!</span>isMoving<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">IsMoveFinished</span><span class="token punctuation">(</span><span class="token class-name">Vector2</span> destination<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator">!</span>isMoving <span class="token operator">&&</span> rigid<span class="token punctuation">.</span>position <span class="token operator">==</span> destination<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token comment">// 对外放出的功能</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">MoveTo</span><span class="token punctuation">(</span><span class="token class-name">Vector2</span> destination<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>destination <span class="token operator">=</span> destination<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> isMoving <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Interupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="23"></td><td><pre> isMoving <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="27"></td><td><pre> isMoving <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="29"></td><td><pre></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token comment">// Use this for initialization</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="33"></td><td><pre> rigid <span class="token operator">=</span> <span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Rigidbody2D<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="35"></td><td><pre></pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token comment">// Update is called once per frame</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>isMoving<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token comment">// 首先旋转</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> lookRotation <span class="token operator">=</span> Quaternion<span class="token punctuation">.</span><span class="token function">LookRotation</span><span class="token punctuation">(</span>Vector3<span class="token punctuation">.</span>forward<span class="token punctuation">,</span> direction<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token comment">// 计算当前帧应该进行的转动</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> rotation <span class="token operator">=</span> Quaternion<span class="token punctuation">.</span><span class="token function">RotateTowards</span><span class="token punctuation">(</span>transform<span class="token punctuation">.</span>rotation<span class="token punctuation">,</span> lookRotation<span class="token punctuation">,</span> Time<span class="token punctuation">.</span>deltaTime <span class="token operator">*</span> rotateSpeed<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token comment">// 当前方向与目标的夹角</span></pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token class-name"><span class="token keyword">float</span></span> angle <span class="token operator">=</span> Quaternion<span class="token punctuation">.</span><span class="token function">Angle</span><span class="token punctuation">(</span>lookRotation<span class="token punctuation">,</span> transform<span class="token punctuation">.</span>rotation<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token comment">// 转身,同时碰撞带来的避免不必要的乱转</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>angle <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="50"></td><td><pre> rigid<span class="token punctuation">.</span>freezeRotation <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="51"></td><td><pre> transform<span class="token punctuation">.</span>rotation <span class="token operator">=</span> rotation<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="52"></td><td><pre> <span class="token punctuation">}</span><span class="token keyword">else</span> rigid<span class="token punctuation">.</span>freezeRotation <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="53"></td><td><pre> <span class="token comment">// 当角度小于 15 度时可以移动</span></pre></td></tr><tr><td data-num="54"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>angle <span class="token operator"><=</span> <span class="token number">15</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="55"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="56"></td><td><pre> <span class="token class-name">Vector2</span> move <span class="token operator">=</span> Vector2<span class="token punctuation">.</span><span class="token function">MoveTowards</span><span class="token punctuation">(</span>rigid<span class="token punctuation">.</span>position<span class="token punctuation">,</span> destination<span class="token punctuation">,</span> Time<span class="token punctuation">.</span>deltaTime <span class="token operator">*</span> moveSpeed<span class="token operator">*</span><span class="token number">0.02f</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="57"></td><td><pre> rigid<span class="token punctuation">.</span>position <span class="token operator">=</span> move<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token comment">// 到达目的地</span></pre></td></tr><tr><td data-num="59"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>destination <span class="token operator">==</span> rigid<span class="token punctuation">.</span>position<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="60"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="61"></td><td><pre> isMoving <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="62"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="63"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="64"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="65"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="66"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>这样一个独立的移动组件就完成了,当后面需要进行寻路等一大堆让人头大的操作时就可以方便的重写了!<br />同样得益于独立性,可以自由的想让谁移动就让谁移动了。</p><hr /><p>然而事情似乎也并没有如此简单,指令 —— 移动、攻击、巡逻,是要有一个队列的。而后两种指令,也都是在移动的基础上添加的变化。</p><h2 id="指令队列"><a class="anchor" href="#指令队列">#</a> 指令队列</h2><h3 id="指令"><a class="anchor" href="#指令">#</a> 指令</h3><p>首先考虑一个抽象的指令,仅需要它的目的地,和判断是否生成一个后继指令就够了。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">InstructionIntent</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token return-type class-name">Vector2</span> Destination <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">Derive</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name">InstructionIntent</span> derived<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>这样移动和巡逻指令很简单:</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">struct</span> <span class="token class-name">MoveIntent</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">InstructionIntent</span></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">Vector2</span> position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name">Vector2</span> Destination <span class="token operator">=></span> position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">public</span> <span class="token function">MoveIntent</span><span class="token punctuation">(</span><span class="token class-name">Vector2</span> position<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>position <span class="token operator">=</span> position<span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="6"></td><td><pre></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">Derive</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name">InstructionIntent</span> derived<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> derived <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">struct</span> <span class="token class-name">PatrolIntent</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">InstructionIntent</span></span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token class-name">Vector2</span> from<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token class-name">Vector2</span> to<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name">Vector2</span> Destination <span class="token operator">=></span> to<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token keyword">public</span> <span class="token function">PatrolIntent</span><span class="token punctuation">(</span><span class="token class-name">Vector2</span> from<span class="token punctuation">,</span> <span class="token class-name">Vector2</span> to<span class="token punctuation">)</span> <span class="token punctuation">{</span> </pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>from <span class="token operator">=</span> from<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>to <span class="token operator">=</span> to<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">Derive</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name">InstructionIntent</span> derived<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="24"></td><td><pre> derived <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">PatrolIntent</span><span class="token punctuation">(</span>to<span class="token punctuation">,</span> from<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="27"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>由于巡逻到目标点后,显然根据现实经验我们需要返回原点,所以指令完成后需要产生出新的指示返回的指令。</p><div class="note info"><p>攻击指令涉及到另外的攻击组件,恐怕不能如此简化,不过暂且先放在这里。</p></div><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">struct</span> <span class="token class-name">AttackIntent</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">InstructionIntent</span></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token class-name">GameObject</span> target<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name">Vector2</span> Destination<span class="token operator">=></span>target<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Transform<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">public</span> <span class="token function">AttackIntent</span><span class="token punctuation">(</span><span class="token class-name">GameObject</span> target<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>target <span class="token operator">=</span> target<span class="token punctuation">;</span> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="6"></td><td><pre></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> <span class="token function">Derive</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name">InstructionIntent</span> derived<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> derived <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="队列"><a class="anchor" href="#队列">#</a> 队列</h3><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token class-name">Queue<span class="token punctuation"><</span>InstructionIntent<span class="token punctuation">></span></span> instructions <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">public</span> <span class="token class-name">Stack<span class="token punctuation"><</span>InstructionIntent<span class="token punctuation">></span></span> patrolSencondaryInstructions <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>为了应对一连串的巡逻指令,实现逐点往返,很明显能想到这是一个栈,在当前指令队列全部完成后,将栈倒进队列,就实现了往复循环。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">// 如果指令队列里存在指令,处理指令</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">if</span><span class="token punctuation">(</span>instructions<span class="token punctuation">.</span><span class="token function">TryPeek</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">var</span></span> current<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> </pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">if</span><span class="token punctuation">(</span>movableUnit<span class="token punctuation">.</span><span class="token function">IsMoveFinished</span><span class="token punctuation">(</span>current<span class="token punctuation">.</span>Destination<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">{</span><span class="token comment">// 如果已到达目的地</span></pre></td></tr><tr><td data-num="7"></td><td><pre> </pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token comment">// 是否有派生移动</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>current<span class="token punctuation">.</span><span class="token function">Derive</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">var</span></span> next<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="11"></td><td><pre> patrolSencondaryInstructions<span class="token punctuation">.</span><span class="token function">Push</span><span class="token punctuation">(</span>next<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="13"></td><td><pre> instructions<span class="token punctuation">.</span><span class="token function">Dequeue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token comment">// 如果完成移动后队列为空,查看派生移动栈</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>instructions<span class="token punctuation">.</span>Count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">while</span> <span class="token punctuation">(</span>patrolSencondaryInstructions<span class="token punctuation">.</span><span class="token function">TryPop</span><span class="token punctuation">(</span><span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">var</span></span> i<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td><pre> instructions<span class="token punctuation">.</span><span class="token function">Enqueue</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>movableUnit<span class="token punctuation">.</span>IsIdling<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token punctuation">{</span><span class="token comment">// 移动</span></pre></td></tr><tr><td data-num="25"></td><td><pre> movableUnit<span class="token punctuation">.</span><span class="token function">MoveTo</span><span class="token punctuation">(</span>current<span class="token punctuation">.</span>Destination<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="27"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>随后检测地图上的鼠标右键事件,队列清空,停止移动,随后放入新指令。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">// move or attack</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKeyDown</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse1<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>EventSystem<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">IsPointerOverGameObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">return</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> mainPlay<span class="token punctuation">.</span>selectedShips<span class="token punctuation">.</span><span class="token function">ForEach</span><span class="token punctuation">(</span>o <span class="token operator">=></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="8"></td><td><pre> o<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Warship<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>instructions<span class="token punctuation">.</span><span class="token function">Clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> o<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Warship<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> o<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Warship<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>instructions<span class="token punctuation">.</span><span class="token function">Enqueue</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">MoveIntent</span><span class="token punctuation">(</span>position<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><div class="note default"><p>此处并未判断队列输入,不过并不复杂。</p></div><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220616121214.png" alt="分散队形" /></p>]]></content>
<summary type="html"><p><span class="spoiler blur" title="你知道得太多了">我还真时跟对象没有缘分,这几天的闷头搞事竟然还算摸到了一点 ECS 的边。选语言也是放着一众 OOP 不管一头扎进了函数式的坑,偏偏玩的还很菜。</span></p>
<h2 id="移动</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Unity" scheme="https://blog.yukx.io/tags/Unity/"/>
<category term="单位移动" scheme="https://blog.yukx.io/tags/%E5%8D%95%E4%BD%8D%E7%A7%BB%E5%8A%A8/"/>
</entry>
<entry>
<title>游戏开发日志 (其二):单位选择、小地图:续</title>
<link href="https://blog.yukx.io/2022/06/game-dev-journal-2-unit-selection-and-minimap-more/"/>
<id>https://blog.yukx.io/2022/06/game-dev-journal-2-unit-selection-and-minimap-more/</id>
<published>2022-06-12T06:32:14.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<p>如果有人看了上一篇,可能已经稍微有点感觉,我们要做的是不是 RTS 游戏呢?—— 很难说不是。</p><h2 id="参演物体"><a class="anchor" href="#参演物体">#</a> 参演物体</h2><p>依照惯例,首先创建一个<ruby>竞技场<rp> (</rp><rt>Arena</rt><rp>)</rp></ruby> 作为整场游戏的地图。<br />Boundary 作为地图边界限制物体移动。<br /><ruby>战舰<rp> (</rp><rt>Warship</rt><rp>)</rp></ruby> 作为 Prefab 自然就是单位啦。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613110559.png" alt="objects" /></p><div class="note default no-icon"><p>此处也能看到在上一篇中未展示的<ruby>小地图指示器<rp> (</rp><rt>Map Indicator</rt><rp>)</rp></ruby></p></div><h2 id="框选单位"><a class="anchor" href="#框选单位">#</a> 框选单位</h2><h3 id="单位选择的思路"><a class="anchor" href="#单位选择的思路">#</a> 单位选择的思路</h3><p>选中单位的视觉标识</p><blockquote><p>单位具有被选中属性</p></blockquote><p>鼠标框选</p><blockquote><p>框体素材、跟随鼠标</p></blockquote><p>鼠标左键点击与拖动框选的统一</p><blockquote><p>被框选、点击物体的判断</p></blockquote><h3 id="单位-warship"><a class="anchor" href="#单位-warship">#</a> 单位 - Warship</h3><p>给绑定到单位的脚本中添加如下内容</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> IsSelected <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td><pre> selectionIndicator<span class="token punctuation">.</span><span class="token function">SetActive</span><span class="token punctuation">(</span>IsSelected<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h3 id="选择框"><a class="anchor" href="#选择框">#</a> 选择框</h3><h4 id="外观"><a class="anchor" href="#外观">#</a> 外观</h4><p>选择框的外观经过权衡选择使用 LineRenderer 实现,将它的 Size 设置为 5 以容纳一个四边闭合的矩形线框,具体的点我们在脚本里计算。<br />给它一个白色的材质,随意设置一个你喜欢的颜色,并调整宽度到合适。<br />要注意的是将 <ins class="dot">Use World Space 取消选中</ins>,这样绘制出来的框体就会跟随物体的位置。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613125446.png" alt="selection box" /></p><p>现在我们来处理鼠标。</p><p>首先是左键按下,确定了一个点,随后在拖动中更新另一个点绘制线框,在鼠标抬起后确定了另一个点。</p><p>记录鼠标起点,通过判断 nullable 来确定鼠标是否已经按下。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">Vector3<span class="token punctuation">?</span></span> selection_start_mouse_position<span class="token punctuation">;</span></pre></td></tr></table></figure><p>总是会用到的鼠标当前位置</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name">Vector3</span> position <span class="token operator">=</span> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">ScreenToWorldPoint</span><span class="token punctuation">(</span>Input<span class="token punctuation">.</span>mousePosition<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>鼠标按下,激活选择框对象,记录位置,这里面的判断是为了避开上层的 UI 元素,你也不想点小地图就取消了当前单位的选择对吧。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKeyDown</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse0<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>EventSystem<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">IsPointerOverGameObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">return</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> selection_start_mouse_position <span class="token operator">=</span> position<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token function">SetActive</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>鼠标拖动时,调整 LineRenderer 不必说,随后需要调整整个物体的中心位置,确保起始点不变。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKey</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse0<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> position<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>selection_start_mouse_position <span class="token keyword">is</span> <span class="token class-name">Vector3</span> sp<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token class-name">Vector3</span> size <span class="token operator">=</span> position <span class="token operator">-</span> sp<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> size<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> half_size <span class="token operator">=</span> size <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>LineRenderer<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SetPositions</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3<span class="token punctuation">[</span><span class="token punctuation">]</span></span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span>half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> selectionBox<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> position <span class="token operator">-</span> half_size<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="21"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>在抬起鼠标时,重置大小并隐藏。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKeyUp</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse0<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>selection_start_mouse_position <span class="token keyword">is</span> <span class="token class-name">Vector3</span> sp<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token function">SetActive</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>LineRenderer<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SetPositions</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3<span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> selection_start_mouse_position <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h4 id="功能"><a class="anchor" href="#功能">#</a> 功能</h4><p>一个很自然的想法是使用起始两点确定的矩形,判断单位是否在矩形内部,不过这样有个小问题,使用中心点判断时需要确保中心点在矩形的内部,不能轻易的实现符合视觉预期的效果,所以我选择了碰撞体。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613140415.png" alt="碰撞体" /></p><p>在鼠标拖动时添加如下代码调整碰撞体大小,需要注意的是碰撞体的 size 参数需要保证顶点距离不能过小或为负。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td data-command=""></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKey</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse0<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td data-command=""></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td data-command=""></td><td><pre> position<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td data-command=""></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>selection_start_mouse_position <span class="token keyword">is</span> <span class="token class-name">Vector3</span> sp<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td data-command=""></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td data-command=""></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td data-command=""></td><td><pre> <span class="token class-name">Vector3</span> size <span class="token operator">=</span> position <span class="token operator">-</span> sp<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td data-command=""></td><td><pre> size<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td data-command=""></td><td><pre> <span class="token class-name"><span class="token keyword">var</span></span> half_size <span class="token operator">=</span> size <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td data-command=""></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>LineRenderer<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SetPositions</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3<span class="token punctuation">[</span><span class="token punctuation">]</span></span></pre></td></tr><tr><td data-num="12"></td><td data-command=""></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="14"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="15"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="16"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span>half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="17"></td><td data-command=""></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td data-command="*"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>BoxCollider2D<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>size <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token function">Max</span><span class="token punctuation">(</span><span class="token function">Abs</span><span class="token punctuation">(</span>size<span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.01f</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Max</span><span class="token punctuation">(</span><span class="token function">Abs</span><span class="token punctuation">(</span>size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.01f</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td data-command=""></td><td><pre> selectionBox<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> position <span class="token operator">-</span> half_size<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td data-command=""></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="22"></td><td data-command=""></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>在鼠标抬起时,首先取消之前的选中,然后通过 <code>OverlapCollider</code> 取得重叠的碰撞体,并选中这些碰撞体对应的单位。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">(</span>Input<span class="token punctuation">.</span><span class="token function">GetKeyUp</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse0<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>selection_start_mouse_position <span class="token keyword">is</span> <span class="token class-name">Vector3</span> sp<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> ship <span class="token keyword">in</span> mainPlay<span class="token punctuation">.</span>selectedShips<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> ship<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Warship<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>IsSelected <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="9"></td><td><pre> mainPlay<span class="token punctuation">.</span>selectedShips<span class="token punctuation">.</span><span class="token function">Clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token class-name">List<span class="token punctuation"><</span>Collider2D<span class="token punctuation">></span></span> shipColliders <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre></pre></td></tr><tr><td data-num="13"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>BoxCollider2D<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">OverlapCollider</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">ContactFilter2D</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="15"></td><td><pre> useLayerMask <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="16"></td><td><pre> layerMask <span class="token operator">=</span> LayerMask<span class="token punctuation">.</span><span class="token function">GetMask</span><span class="token punctuation">(</span><span class="token string">"Unit"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">,</span> shipColliders<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> mainPlay<span class="token punctuation">.</span>selectedShips <span class="token operator">=</span> shipColliders<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>c <span class="token operator">=></span> c<span class="token punctuation">.</span>gameObject<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> ship <span class="token keyword">in</span> mainPlay<span class="token punctuation">.</span>selectedShips<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="22"></td><td><pre> ship<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>Warship<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>IsSelected <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="24"></td><td><pre></pre></td></tr><tr><td data-num="25"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token function">SetActive</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> selectionBox<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>LineRenderer<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SetPositions</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3<span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> selection_start_mouse_position <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="29"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><div class="note info"><p>此处使用了 ContactFilter 来排除其他层中的物体。<br />目前并未进行单位阵营归属的判断。</p></div><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613180430.png" alt="示例" /></p><p>至此,框选功能完成。</p><h2 id="小地图续更多的交互"><a class="anchor" href="#小地图续更多的交互">#</a> 小地图:续,更多的交互</h2><p>在上一篇中只是实现了小地图的显示功能,下面开始完善。</p><h3 id="显示当前镜头范围"><a class="anchor" href="#显示当前镜头范围">#</a> 显示当前镜头范围</h3><p>也就是小地图上的白框,我们可以延续之前显示单位缩略图的思路,给 Main Camera 添加一个 minimap 层的子物体。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613142422.png" alt="子物体" /></p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613142502.png" alt="子物体" /></p><p>同样使用 LineRenderer 来绘制。<br />只需要在游戏初始化的时候设置一下。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token comment">// 获取主摄像头范围</span></pre></td></tr><tr><td data-num="4"></td><td><pre> half_cam_size <span class="token operator">=</span> <span class="token punctuation">(</span>Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">ScreenToWorldPoint</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3</span><span class="token punctuation">(</span>Screen<span class="token punctuation">.</span>width<span class="token punctuation">,</span> Screen<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">-</span> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">ScreenToWorldPoint</span><span class="token punctuation">(</span>Vector3<span class="token punctuation">.</span>zero<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre> GameObject<span class="token punctuation">.</span><span class="token function">Find</span><span class="token punctuation">(</span><span class="token string">"Camera Range"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetComponent</span><span class="token generic class-name"><span class="token punctuation"><</span>LineRenderer<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">SetPositions</span><span class="token punctuation">(</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">Vector3<span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> </pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_cam_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_cam_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> </pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_cam_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_cam_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> </pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span>half_cam_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token operator">-</span>half_cam_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> </pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_cam_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token operator">-</span>half_cam_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> </pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token operator">-</span>half_cam_size<span class="token punctuation">.</span>x<span class="token punctuation">,</span> half_cam_size<span class="token punctuation">.</span>y<span class="token punctuation">)</span> </pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220613180548.png" alt="示例" /></p><h3 id="点击小地图移动镜头"><a class="anchor" href="#点击小地图移动镜头">#</a> 点击小地图移动镜头</h3><p>由于 <code>Input.GetXX</code> 会作用于全局,为了避免不必要的判断,作为 UI 组件可以使用 <code>IPointerDownHandler</code> 系列接口获取点击事件。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnPointerDown</span><span class="token punctuation">(</span><span class="token class-name">PointerEventData</span> eventData<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name">Vector2</span> ratio <span class="token operator">=</span> <span class="token punctuation">(</span>eventData<span class="token punctuation">.</span>position <span class="token operator">-</span> Vector2<span class="token punctuation">.</span>one <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">200</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span>ratio<span class="token punctuation">.</span>x <span class="token operator">*</span> mainPlay<span class="token punctuation">.</span>MapSize<span class="token punctuation">.</span>x<span class="token punctuation">,</span> ratio<span class="token punctuation">.</span>y <span class="token operator">*</span> mainPlay<span class="token punctuation">.</span>MapSize<span class="token punctuation">.</span>y<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><p>小地图的大小目前设置为 200,故鼠标事件的位置需要减去一半大小后再除以 200 得到点击位置相对于全图的比例。<br />注意不要改动摄像机高度。</p><p>更进一步。</p><figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name"><span class="token keyword">bool</span></span> map_operation <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token comment">// Update is called once per frame</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Update</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>map_operation <span class="token operator">&&</span> Input<span class="token punctuation">.</span><span class="token function">GetKey</span><span class="token punctuation">(</span>KeyCode<span class="token punctuation">.</span>Mouse0<span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token class-name">Vector3</span> p <span class="token operator">=</span> Input<span class="token punctuation">.</span>mousePosition<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> </pre></td></tr><tr><td data-num="9"></td><td><pre> p<span class="token punctuation">.</span>x <span class="token operator">=</span> Mathf<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>p<span class="token punctuation">.</span>x<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> p<span class="token punctuation">.</span>y <span class="token operator">=</span> Mathf<span class="token punctuation">.</span><span class="token function">Clamp</span><span class="token punctuation">(</span>p<span class="token punctuation">.</span>y<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token class-name">Vector2</span> ratio <span class="token operator">=</span> <span class="token punctuation">(</span>p <span class="token operator">-</span> Vector3<span class="token punctuation">.</span>one <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">200</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> Camera<span class="token punctuation">.</span>main<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>position <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">(</span>ratio<span class="token punctuation">.</span>x <span class="token operator">*</span> mainPlay<span class="token punctuation">.</span>MapSize<span class="token punctuation">.</span>x<span class="token punctuation">,</span> ratio<span class="token punctuation">.</span>y <span class="token operator">*</span> mainPlay<span class="token punctuation">.</span>MapSize<span class="token punctuation">.</span>y<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnPointerDown</span><span class="token punctuation">(</span><span class="token class-name">PointerEventData</span> eventData<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td><pre> map_operation <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="21"></td><td><pre></pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token keyword">public</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">OnPointerUp</span><span class="token punctuation">(</span><span class="token class-name">PointerEventData</span> eventData<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token punctuation">{</span></pre></td></tr><tr><td data-num="24"></td><td><pre> map_operation<span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>如果有人看了上一篇,可能已经稍微有点感觉,我们要做的是不是 RTS 游戏呢?—— 很难说不是。</p>
<h2 id="参演物体"><a class="anchor" href="#参演物体">#</a> 参演物体</h2>
<p>依照惯例,首先创建一个<ruby>竞技场<</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Unity" scheme="https://blog.yukx.io/tags/Unity/"/>
<category term="鼠标框选单位" scheme="https://blog.yukx.io/tags/%E9%BC%A0%E6%A0%87%E6%A1%86%E9%80%89%E5%8D%95%E4%BD%8D/"/>
<category term="小地图交互" scheme="https://blog.yukx.io/tags/%E5%B0%8F%E5%9C%B0%E5%9B%BE%E4%BA%A4%E4%BA%92/"/>
</entry>
<entry>
<title>游戏开发日志 (其一):HUD、小地图</title>
<link href="https://blog.yukx.io/2022/06/game-dev-journal-1-hud-minimap/"/>
<id>https://blog.yukx.io/2022/06/game-dev-journal-1-hud-minimap/</id>
<published>2022-06-11T18:38:51.000Z</published>
<updated>2023-12-17T08:19:33.831Z</updated>
<content type="html"><![CDATA[<div class="note default no-icon"><p>某人日常不务正业务现已开拓至游戏开发挥年复一年的沉积极放光吧!</p></div><div class="note default"><p>游戏具体情况暂且不提,后续也将在 github 上开源。</p></div><h2 id="hud"><a class="anchor" href="#hud">#</a> HUD</h2><p>首先我们秉持优良传统,创建一个根 GameObject,<br />在其内部添加 Canvas,在 Canvas 内添加我们需要的 UI 物体即可。<br /><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/object-hierachy.png" alt="对象层级示例" /></p><h2 id="小地图"><a class="anchor" href="#小地图">#</a> 小地图</h2><p>小地图有很多种实现方法,这里暂且采用最简单的,添加第二个 Camera 的方法。</p><h3 id="custom-render-texture"><a class="anchor" href="#custom-render-texture">#</a> Custom Render Texture</h3><p>首先新建一个 Custom Render Texture, 用于接收摄像机的内容并显示在指定位置。</p><h3 id="map-camera"><a class="anchor" href="#map-camera">#</a> Map Camera</h3><p>新建一个 Camera,并创建一个 layer: minimap,用于显示单位的缩略图。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220612140021.png" alt="Camera 属性" /></p><p>设置 Clear Flag 为 Solid Color ,<ruby> <rt></rt>投影<rp> (</rp><rt>Projection</rt><rp>)</rp> <rt></rt></ruby>为<ruby> <rt></rt>正交<rp> (</rp><rt>Orthographic</rt><rp>)</rp> <rt></rt></ruby>,以排除透视的影响。<br />设置 <strong>Culling Mask</strong> 取消选中其他 layer 仅保留刚刚新建的 minimap,这样小地图中不会显示多余的内容。(在其他 Camera 中也需要保持不要选中 minimap)</p><p>设置 Target Texture 为刚刚创建的 Custom Render Texture。</p><h3 id="minimap"><a class="anchor" href="#minimap">#</a> Minimap</h3><p>在你喜欢的地方添加一个 <code>UI > Raw Image</code> ,将其 Texture 设置为刚刚创建的 Custom Render Texture。<br />至此小地图的基本显示功能完成,后续需要在想要显示在地图中的物体内完成。</p><h3 id="其他单位"><a class="anchor" href="#其他单位">#</a> 其他单位</h3><p>在想要显示的物体内添加一个 Sprite,指定其 Layer 为 minimap。</p><p><img data-src="https://fastly.jsdelivr.net/gh/hxYuki/im-base@master/20220612143055.png" alt="示例效果" /></p><p>大功告成!</p><div class="note info"><p>Camera size 与 Worldspace 内的坐标尺度一致,可按需要调整地图大小。</p></div>]]></content>
<summary type="html"><div class="note default no-icon">
<p>某人日常不务正业务现已开拓至游戏开发挥年复一年的沉积极放光吧!</p>
</div>
<div class="note default">
<p>游戏具体情况暂且不提,后续也将在 github 上开源。<</summary>
<category term="开发随记" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/"/>
<category term="游戏开发" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/"/>
<category term="conquest of star" scheme="https://blog.yukx.io/categories/%E5%BC%80%E5%8F%91%E9%9A%8F%E8%AE%B0/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/conquest-of-star/"/>
<category term="Unity" scheme="https://blog.yukx.io/tags/Unity/"/>
<category term="HUD" scheme="https://blog.yukx.io/tags/HUD/"/>
<category term="小地图" scheme="https://blog.yukx.io/tags/%E5%B0%8F%E5%9C%B0%E5%9B%BE/"/>
</entry>
<entry>
<title>Steam记住密码失效的一种原因</title>
<link href="https://blog.yukx.io/2022/06/one-possible-reason-for-steam-not-rememebering-password/"/>
<id>https://blog.yukx.io/2022/06/one-possible-reason-for-steam-not-rememebering-password/</id>
<published>2022-06-02T06:14:28.000Z</published>
<updated>2023-12-17T08:19:33.835Z</updated>
<content type="html"><![CDATA[<p>你可能有第二个设备在登录时记住了密码,第一个设备就无法记住密码了。</p><p>取消所有其他设备授权也没有用,<br />实在是让我恼火了好久,直到今天打开了很久没用的另一个电脑,退出了上面的 Steam。</p>]]></content>
<summary type="html"><p>你可能有第二个设备在登录时记住了密码,第一个设备就无法记住密码了。</p>
<p>取消所有其他设备授权也没有用,<br />
实在是让我恼火了好久,直到今天打开了很久没用的另一个电脑,退出了上面的 Steam。</p>
</summary>
<category term="闲话" scheme="https://blog.yukx.io/categories/%E9%97%B2%E8%AF%9D/"/>
<category term="Steam无法记住密码" scheme="https://blog.yukx.io/tags/Steam%E6%97%A0%E6%B3%95%E8%AE%B0%E4%BD%8F%E5%AF%86%E7%A0%81/"/>
<category term="Steam" scheme="https://blog.yukx.io/tags/Steam/"/>
</entry>
</feed>