徐麟家的博客

站在巨人的肩膀上

点评

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。

Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的哪些内部状态。

Memento(备忘录):负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。

Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查

命令模式可以使用备忘录模式来存储可撤销操作的状态[DP]。有时一些对象的内部信息必须保存在对象以外的地方,但是必须要由对象自己读取,这时,使用备忘录可以把复杂的对象内部信息对其他的对象屏蔽起来[DP],从而可以恰当地保持封装的边界。

点评

备忘录模式很好的展示单一职责。程序设计中注重的边界,合理组织类功能的协作,对未来程序的拓展和使用有着至关重要的的影响!

点评

当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。优点:状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。

本文总结个人使用unity调试第三方库的些许经验

解释关于dll,pdb,mdb的概念
dll:
DLL(Dynamic Link Library)是一种微软Windows操作系统中常见的文件类型,它包含了一系列的可执行代码以及数据,这些代码和数据可以被其他程序调用和使用。 DLL文件通常包含了一个或多个函数、数据、类、资源等,这些可以被其他程序使用。与静态链接库(Static Link Library)不同,DLL在运行时动态加载到内存中,因此它们被称为动态链接库。 DLL文件的主要优点是可以共享代码和数据,避免了代码的重复编写,提高了代码的重用性。通过将常用的功能封装到DLL中,其他程序可以通过简单地调用DLL中的函数或使用其中的类来实现相应的功能,从而简化了开发过程。
pdb:
PDB(Program Database)是一种微软Windows平台上的调试信息文件格式,用于存储编译后的程序的调试信息。这些调试信息包括了源代码文件、行号、变量名称、函数名称等。

PDB文件通常与编译后的可执行文件(例如.EXE或.DLL)一起生成。它们包含了编译器产生的调试符号信息,以及源代码的位置信息,使得调试器能够将执行的机器码映射回源代码,并且在调试器中显示正确的变量名称和行号等信息。

在调试过程中,开发者可以使用PDB文件来设置断点、查看变量值、跟踪函数调用等操作,以帮助定位和解决代码中的问题。
mdb:
在上下文中,"mdb"通常指的是Mono调试符号文件(Mono Debug Symbol),它是用于在Mono环境中进行调试的文件。

在Unity中,当你编译C#脚本时,Unity会生成相应的可执行文件(例如.dll文件),以及用于调试的.mdb文件。这个.mdb文件包含了调试信息,如源代码文件、行号、变量名称等,以便在Unity编辑器中进行调试。调试信息使得你能够在代码中设置断点、查看变量的值以及执行其他调试操作。

因此,在Unity中,如果你想要在编辑器下调试C#脚本,你通常需要对应的.mdb文件。
unity Editor是运行在mono环境中的,应该使用mdb文件获取调试信息的,为什么也能使用pdb文件获取调试信息?
Unity的脚本(主要是C#脚本)在运行时是通过Mono运行时来执行的。Mono是一个跨平台的.NET实现,它与微软的.NET框架兼容,并且提供了一些额外的功能和扩展。

PDB(Program Database)是微软.NET编译器产生的调试信息文件,通常用于在Windows平台上进行调试。这些文件包含了源代码的位置、变量和函数的调试信息等。

尽管Unity使用Mono作为脚本的运行时环境,但是Unity编辑器和Mono运行时之间并没有直接关联,因此Unity编辑器默认情况下不会使用PDB文件进行调试。

然而,你可以使用一些第三方工具或技术来进行调试,比如你可以使用Visual Studio作为外部调试器来调试Unity项目,这样你就可以利用PDB文件进行调试了。不过,这种方法相对复杂,而且在跨平台开发中可能不是最佳选择。

在Unity中,通常使用的是.mdb文件来进行调试,因为Unity编辑器和Mono运行时直接支持.mdb文件,这使得在Unity编辑器中进行调试更加方便。
在unity中使用pdb特别注意点
在unity中使用的pdb要求是便携的pdb文件,如果使用通常意义的pdb,unity是没有办法读取的。会有如下警告图示,无法读取源程序符号信息。 Unity is only able to load mdb or portable-pdb symbols. Assets/GameFramework/Libraries/GameFramework.pdb is using a legacy pdb format. 我们可以通过修改dll库源代码(当然是需要有源码,或者已经提供配套的pdb文件)编译器选项解决这个问题。调试信息选择可移植,如下图:

实操

按以上方法生成好pdb文件一并放入unity资产目录中(任意Assets目录下)。 断点调试截图:

点评

好处是请求者不用管哪个对象来处理。 接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用[DP]。

点评

模板方法定义统一的流程骨架,部分差异的方法可在超类中修改。在效果上,有点类似于创建者模式。模板方法更侧重行为流程控制,结构简洁明了;创建者更侧重对象的灵活创建;创建者是多个类组合完成一个整体的功能,结构会复杂些。模板方法让我想到了unity中的可编程渲染管线,在整理流程不变的情况下,为用户开放了顶点着色器(vertex)和片元着色器(fragment),这大大丰富了用户的可操作性,又不失整体流程的控制。从某种程度讲设计模式或许就是现实方法论的总结,它一直都在我们身边。

主要是想分下集成A* Pathfinding Project作为Behavior Designer作为寻路的解决方案,官方文档记录的不是很详细,希望能帮助到大家。
首先概述下两个插件

(1)A* Pathfinding Project Pro,主要是用来做寻路,包括自动寻路网格生成的方案,能为开发省很多时间,当然也买的非常好用!

(2)Behavior Designer 做ai行为树插件,unity项目中使用的比较多。还有子集成包:

a、movement 运动包

b、Tactical Pack 战术包

c、Formations Pack 编队包

我想集成的是MovePack能支持 A* Pathfinding Project 的寻路。当我导入MovePack的插件包时候并没有发现有A* pathfinding的支持,只有默认的unity navemesh支持?

和文档上说的不一样,只有默认的集成,没有Pathfinding Project的集成,我的项目截图如下:

反复研究完文档后,原来需要在官网下载movement对A* 相关行为树的集成,并不是默认包中带的,需要输入序列号后要再下载下图第一个集成包(A* Pathfinding Project 相关集成)。

下载完,导入项目后,终于有关于pathfing的Task了。如下图:

最后,想说下在上文提到的这几个软件都是需要付费购买序列号的,希望大家使用和支持正版软件!

阴影生成的实现方式

1.实时光照
2.脚底放置假的阴影面片模拟阴影
3.变幻模型在某个平面上投影形成2d压缩模型
4.project投影器

具体做法

这里我们使用方案3方案实现,因为spine是2d的投影替换为使用旋转和切变来实现。具体实现通过两个pass,第一个pass做模型的变换处理,生成一个阴影;第二个pass使用默认的渲染画出本身的模型。

github工程连接:https://github.com/xulinjia/spine_shadow
shader代码如下:
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

Shader "Spine/SkeletonShadow" {
Properties {
_ShadowColor("ShadowColor",Color) = (0,0,0,0.5) //阴影颜色
_ShadowDdge("ShadowDege",range(0,1.507)) = 0 //绕x轴的旋转角度
_ShadowCutD("_ShadowCutD",float) = 0.5 //切变距离
_ShadowHeightScale("_ShadowHeight",float) = 1 // 影子高度比例
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
[NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default

// Outline properties are drawn via custom editor.
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
[HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1
[HideInInspector] _OutlineOpaqueAlpha("Opaque Alpha", Range(0,1)) = 1.0
[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
}

SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }

Fog { Mode Off }
Cull Off
ZWrite Off
Blend One OneMinusSrcAlpha
Lighting Off

Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Keep
}

Pass {
Name "FastShadow"
Blend SrcAlpha Zero
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "CGIncludes/Spine-Common.cginc"
sampler2D _MainTex;
fixed _Cutoff;
float4 _ShadowColor;
float _ShadowDdge;
float _ShadowCutD;
float _ShadowHeightScale;

struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};

struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};

VertexOutput vert (VertexInput v) {
VertexOutput o;
float4 vt = v.vertex;
float4 vtn;
vt.y *= _ShadowHeightScale;
vtn.x = vt.x + vt.y * _ShadowCutD;
vtn.y = cos(_ShadowDdge) * vt.y;
vtn.z = sin(_ShadowDdge) * vt.y;
vtn.w = vt.w;
o.pos = UnityObjectToClipPos(vtn);
o.uv = v.uv;
o.vertexColor = PMAGammaToTargetSpace(v.vertexColor);
return o;
}

float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);

#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
float4 shadowColor = _ShadowColor;
clip(texColor.a * i.vertexColor.a - 0.01);
return shadowColor;

}
ENDCG
}


Pass {
Name "Normal"

CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "CGIncludes/Spine-Common.cginc"
sampler2D _MainTex;

struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};

struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};

VertexOutput vert (VertexInput v) {
VertexOutput o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.vertexColor = PMAGammaToTargetSpace(v.vertexColor);
return o;
}

float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);

#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif

return (texColor * i.vertexColor);
}
ENDCG
}

Pass {
Name "Caster"
Tags { "LightMode"="ShadowCaster" }
Offset 1, 1
ZWrite On
ZTest LEqual

Fog { Mode Off }
Cull Off
Lighting Off

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _Cutoff;

struct VertexOutput {
V2F_SHADOW_CASTER;
float4 uvAndAlpha : TEXCOORD1;
};

VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) {
VertexOutput o;
o.uvAndAlpha = v.texcoord;
o.uvAndAlpha.a = vertexColor.a;
TRANSFER_SHADOW_CASTER(o)
return o;
}

float4 frag (VertexOutput i) : SV_Target {
fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy);
clip(texcol.a * i.uvAndAlpha.a - _Cutoff);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
CustomEditor "SpineShaderWithOutlineGUI"
}

点评

命令模式是一种松耦合得设计,解耦命令的请求者和命令的实现者。
优点:
1.它能较容易地设计一个命令队列
2.在需要的情况下,可以较容易地将命令记入日志
3.允许接收请求的一方决定是否要否决请求
4.可以容易地实现对请求的撤销和重做
5.由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易

设计警示

敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。

点评

观察者模式是一个解耦模型。通俗的话来讲,当一个抽象关系中一方依赖于另外一方,观察者可以让双方各自独立。即被观察者不需要知道具体有的观察者(只关心自己的变化),观察者也不需要知道具体的被观察者的细节(只关系如何响应变化)。 整理下思路:观察者的设计模式,引申出了事件设计。在大大小小的框架都会有事件的身影,主要是很好用的设计。事件的颗粒度是方法,观察者的颗粒度是类。两者在设计思想上是完全一样的,只是作用域的范围。我们可以说观察者是对类的抽象;事件是对方法的抽象。观察者显得更为重度,讲究封装,结构会更加完整些;事件就会显得小巧,使用非常灵活。但牺牲的是结构,那么事件的分布会比较零散。在业务逻辑开发的时候,因为业务本身就比较的零散个人会比较倾向于事件,用起来比较的小巧,方便。事件在C#中已经得到语法层的支持————事件和委托。

注意点

使用观察者或者事件都应该注意循环触发。

0%