移动

当gameobject被加上rigidbody2d组件时,如果想移动它,不要这样写:

1
2
3
4
void Update()
{
this.transform.Translate (Vector3.left * speed * Time.deltaTime);
}

这种写法,主要针对无rigidbody2d的gameobject对象,否则,性能很差。
正确的写法:

1
2
3
4
5
6
7
8
9
void FixedUpdate()
{
rigidbody2D.MovePosition (rigidbody2D.position + Vector2.left * speed * Time.fixedDeltaTime);
}

void Start ()
{
rigidbody2D.velocity = Vector2.left * speed;
}

Body Type属性

rigidbody2d最为重要的一个属性,不同的选项,不同的物理效果:

Dynamic(动态的)

具有完全的物理特性;
会与所有类型的Rigidbody2D进行碰撞;
是最常用的Rigidbody2D类型、也是默认的类型;
是最耗费性能的类型;

Kinematic(运动学)

仅在用户控制下运动,不会受到重力和AddForce等力相关函数的影响;
只与Dynamic的Rigidbody2D发生碰撞(不勾选Use Full Kinematic Contacts);
不能通过力或碰撞改变速度,但是可以设置其速度和位置、旋转;
比Dynamic性能高;

Static (静态的)

具有无限质量、不可移动的物体;
velocity、AddForce、gravity、MovePosition、MoveRotation都不可用;
只与Dynamic的Rigidbody2D发生碰撞;
性能最高;

Simulated 物理模拟

阅读全文 »

游戏说明

游戏开始,下方随机生成不同品质小人,在场景中来回走动,不同品质的小人,移动速度不一样,被抓到后获得的积分也不一样。按住移动按钮,上方机械手臂会左右来回移动,当松开按钮,机械手臂会掉下来,当手臂下落碰到场景中小人时,检测当前手臂抓取范围内的小人,在抓取范围内的小人会被抓走。然后计算获得分数,如果机械手臂抓空,则碰到地面后手臂也会自动回弹,每轮游戏有4次抓取机会。

功能实现

移动的小人

创建移动小人AmusementParkDollMachineGameRole,跟据不同品质小人,移动速度不同实现小人在可控范围内随机位置移动。在移动过程中通过修改sortingOrder值来调整小人在不同位置的层级显示。小人在移动是播放walk动作,被抓住时拖放drag动作,同时将小人从场景节点移动到机械手臂抓取小人的节点内,当手臂上升时,小人跟着手臂一起向上移动,抓取结束移除被抓取的小人。

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
---待抓取的游戏小人
---@class AmusementParkDollMachineGameRole
local m = {
View = nil,
---@type AmusementParkDollMachineRoleData
RoleData = nil,
---@type Spine.Unity.SkeletonGraphic
Animation = nil,
---@type number
EntityId = 0,
---@type Vector3 下一个移动位置
NextPos = Vector3.New(0,0,0),
---@type boolean 是否在移动中
IsMoving = false,
---@type number 下一次开始移动的时间
NextMovieTimer = 0,
---@type boolean 小人是否已成功创建
IsCreateRole = false,
---@type boolean 小人是否被抓住
IsCatch = false,
---@type UnityEngine.Collider2D 小人Collider
RoleCollider = nil,
RoleObj = nil,
}

function m.New(view)
local obj = Clone(m)
obj:Init(view)
return obj
end

function m:Init(view)
self.View = view
LuaCodeInterface.BindOutlet(self.View, self)
self.OnShowSpineSuccessDelegate = function(sender, args) self:OnShowSpineSuccess(sender, args) end

self.RoleCollider = self.View:GetComponent(typeof(UnityEngine.Collider2D))

self:AddListener()
end

function m:AddListener()
GameEntry.LuaEvent:Subscribe(UnityGameFramework.Runtime.ShowEntitySuccessEventArgs.EventId, self.OnShowSpineSuccessDelegate)
end

function m:RemoveListener()
GameEntry.LuaEvent:Unsubscribe(UnityGameFramework.Runtime.ShowEntitySuccessEventArgs.EventId, self.OnShowSpineSuccessDelegate)
end

---界面轮询。
---@param elapseSeconds number
---@param realElapseSeconds number
---@return void
function m:OnUpdate(elapseSeconds, realElapseSeconds)
if not self.IsCreateRole then
return
end
if self.RoleData == nil then
return
end
if self.IsCatch then
return
end
if not self.IsMoving then
if PlayerModule.GetServerTime() > self.NextMovieTimer then
self:StartMove()
end
return
end
local direction = self.NextPos - self.View.transform.localPosition
if direction.magnitude > self.RoleData.roleRareSpeed then
self.View.transform:Translate(direction.normalized * self.RoleData.roleRareSpeed * UnityEngine.Time.deltaTime)
self:ChangeRoleOrderZ()
else
self:StopMove()
end
end

function m:ChangeOrder()
if self.RoleObj then
local canvas = self.View:GetComponentInParent(typeof(UnityEngine.Canvas))
setGameObjectLayers(self.RoleObj.transform, "UI")
local renderers = self.RoleObj:GetComponentsInChildren(typeof(UnityEngine.Renderer))
for i = 0, renderers.Length - 1 do
renderers[i].sortingLayerID = LuaCodeInterface.SortingLayerNameToID("Default")
renderers[i].sortingOrder = canvas.sortingOrder + 1
end
end
end

function m:OnShowSpineSuccess(sender, args)
if self.EntityId == args.Entity.Id then
self.RoleObj = args.Entity.gameObject
self.Animation = args.Entity.gameObject:GetComponentInChildren(typeof(Spine.Unity.SkeletonAnimation))
self.Animation.state:SetAnimation(0,"idle", true)
self:StartMove()
self.IsCreateRole = true
self:ChangeOrder()
end
end

---获取一个随机位置 坐标Z控制小人显示层级
function m:GetRandomPos()
local rx = math.random(-self.View.transform.parent.rect.w/2,self.View.transform.parent.rect.w/2)
local ry = math.random(-self.View.transform.parent.rect.h/2,self.View.transform.parent.rect.h/2)
return Vector3.New(rx,ry,0)
end

---开始移动
function m:StartMove()
self.IsMoving = true
self.NextPos = self:GetRandomPos()
if self.Animation then
self.Animation.state:SetEmptyAnimation(0, 0)
self.Animation.state:SetAnimation(0, "walk", true)
end
self:RefreshWalkFaceTo()
end

---移动到目标位置停止移动
function m:StopMove()
self.IsMoving = false
self.View.transform.localPosition = self.NextPos
self.NextMovieTimer = math.random(0,4) + PlayerModule.GetServerTime()
if self.Animation then
self.Animation.state:SetAnimation(0,"idle", true)
end
end

---播放抓住状态
function m:CatchState()
self.IsMoving = false
self.IsCatch = true
if self.Animation then
self.Animation.AnimationName = nil
self.Animation.state:SetEmptyAnimation(0, 0)
self.Animation.state:SetAnimation(0,"drag", true)
end
end

---刷新移动朝向
function m:RefreshWalkFaceTo()
local checkRet = self.NextPos.x - self.View.transform.localPosition.x
local localScale = self.View.transform.localScale
if checkRet > 0 then
localScale.x = -math.abs(localScale.x)
else
localScale.x = math.abs(localScale.x)
end
self.View.transform.localScale = localScale
end

---@param roleData AmusementParkDollMachineRoleData
function m:SetData(roleData)
self.RoleData = roleData
self.IsCreateRole = false
self.IsCatch = false
for i = 1, 4 do
self["Quality"..i]:SetActive(self.RoleData.roleRare == i)
end
self.View.name = self.RoleData.cid
local pos = self:GetRandomPos()
self.View.transform.localPosition = pos
self:ChangeRoleOrderZ()
self.NextPos = self:GetRandomPos()
self:ShowSpine()
end

---改变小人移动Z值(移动是层级关系)
function m:ChangeRoleOrderZ()
local pos = self.View.transform.localPosition
---设置小人移动的Z值
self.OrderZ.transform.localPosition = Vector3.New(0,0,(pos.y + 150)/100)
end

function m:ShowSpine()
self:HideEntity()
self.EntityId = GameEntry.Entity:GenerateEntityID()
GameEntry.Entity:ShowUIElement(self.EntityId, self.RoleData:GetCfgData().PlayerSpine, 0, self.SpineRoot.transform, Vector3.zero)
end

function m:HideEntity()
if self.EntityId ~= 0 then
GameEntry.Entity:HideEntity(self.EntityId)
self.EntityId = 0
end
end

function m:Dispose()
AssetUtil.UnloadAsset(self)
self:RemoveListener()
self:HideEntity()

LuaCodeInterface.ClearOutlet(self.View, self)
UnityEngine.Object.Destroy(self.View)
self.View = nil
end

return m
阅读全文 »

Lua实现Unity象素鸟小游戏要点记录:

游戏玩法简介

不用物理引擎实现像素鸟在障碍物之间飞行,通过配表配置小鸟向下的加速度和点击一次屏幕给小鸟赋值一次初始速度和向上加速度来模拟小鸟飞行。障碍物根据配置难度在固定距离随机生成。

功能实现简述

飞行障碍实现

创建AmusementParkBirdObstacleCell障碍控件。游戏运行时,根据固定的配置距离,生成不同难度的障碍实例。障碍物分为上,下两部份,中间有可穿行的空隙。

AmusementParkBirdObstacleCell

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
---@class AmusementParkBirdObstacleCell
local m = {
View = nil,
---@type number 移动速度
Speed = 0,
---@type UnityEngine.Collider2D
TopCollider2D = nil,
---@type UnityEngine.Collider2D
BottomCollider2D = nil,
}

function m.New(view)
local obj = Clone(m)
obj:Init(view)
return obj
end

function m:Init(view)
self.View = view
LuaCodeInterface.BindOutlet(self.View, self)

self.TopCollider2D = self.View.transform:Find("Top").gameObject:GetComponent(typeof(UnityEngine.Collider2D))
self.BottomCollider2D = self.View.transform:Find("Bottom").gameObject:GetComponent(typeof(UnityEngine.Collider2D))

self:AddListener()
end

function m:AddListener()

end

function m:RemoveListener()

end

---界面轮询。
---@param elapseSeconds number
---@param realElapseSeconds number
---@return void
function m:OnUpdate(elapseSeconds, realElapseSeconds)
self.View.transform:Translate(Vector3.New(self.Speed * UnityEngine.Time.deltaTime * -1, 0, 0))
end

---@param speed number
function m:SetData(speed)
self.Speed = speed
end

function m:Dispose()
AssetUtil.UnloadAsset(self)
self:RemoveListener()

LuaCodeInterface.ClearOutlet(self.View, self)
UnityEngine.Object.Destroy(self.View)
self.View = nil
end

return m
阅读全文 »

用Lua实现Unity一笔画小游戏要点记录:

游戏玩法简介

选择不同难度关卡开始游戏,每一关有多个方块小格,可以从任意一个方块格作为起点开始连接到下一个方块格,下一个方块格必须与起始格上下左右相邻。同一个方块格不能重复连接,成功连接后,目标方块格又成为新的起始方块格。以此类推直至将所有方块格连完。

功能实现简述

关卡难度

关卡难度选择,不同关卡制作不同prefab预设。prefab预设摆放所有要连接的格子位置信息节点。选择关卡开始游戏时,在每一个位置信息节点下生成一个游戏连接格实例对象。创建方格数据结构 AmusementParkOneConnectBlockData 和 视图显示控件AmusementParkOneConnectBlockCell

AmusementParkOneConnectBlockData

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
---@class AmusementParkOneConnectBlockData
local m = {
---@type number
Index = 0,
---@type number
X = 0,
---@type number
Y = 0,
---@type number 0 未连接,1 已连接
State = 0,
---@type boolean 最新连通
IsFirst = false,
}

function m.New(index,x,y)
local o = Clone(m)
o:Init(index,x,y)
return o
end

function m:Init(index,x,y)
self.Index = index
self.X = tonumber(x)
self.Y = tonumber(y)
end

return m

AmusementParkOneConnectBlockCell

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
---@class AmusementParkOneConnectBlockCell
local m = {
View = nil,
---@type AmusementParkOneConnectBlockData
BlockData = nil,
---@type Vector3
StartPos = nil,
---@type function
OnBeginDragCallBack = nil,
---@type function
OnDragCallBack = nil,
---@type UnityEngine.Collider2D
BlockCollider = nil,
---@type UnityEngine.Collider2D
DrgCollider = nil,
}

function m.New(view)
local obj = Clone(m)
obj:Init(view)
return obj
end

function m:Init(view)
self.View = view
LuaCodeInterface.BindOutlet(self.View, self)

self.DelegateBtnSelf = function() self:OnClickBtnSelf() end

self.BlockCollider = self.View:GetComponent(typeof(UnityEngine.Collider2D))
self.DrgCollider = self.ImgDrag:GetComponent(typeof(UnityEngine.Collider2D))

self.StartPos = self.ImgDrag.transform.position
self.ImgDrag:GetComponent("UIDrag").onBeginDrag = function(eventData) self:OnBeginDrag(eventData) end
self.ImgDrag:GetComponent("UIDrag").onDrag = function(pointerEventData) self:OnDrag(pointerEventData) end
self.ImgDrag:GetComponent("UIDrag").onReachTargetSuccess = function(eventData) self:OnDragSuccess(eventData) end
self.ImgDrag:GetComponent("UIDrag").onReachTargetFailure = function(eventData) self:OnFailure(eventData) end

self:AddListener()
end

function m:AddListener()
self.View:GetComponent("Button").onClick:AddListener(self.DelegateBtnSelf)
end

function m:RemoveListener()
self.View:GetComponent("Button").onClick:RemoveListener(self.DelegateBtnSelf)
end

function m:OnClickBtnSelf()
if self.OnBeginDragCallBack then
self.OnBeginDragCallBack(self)
end
end

function m:OnBeginDrag()
if self.OnBeginDragCallBack then
self.OnBeginDragCallBack(self)
end
end

function m:OnDrag(eventData)
if self.OnDragCallBack then
self.OnDragCallBack(self)
end
end

function m:OnDragSuccess(eventData)
self.ImgDrag.transform.position = self.StartPos
end

function m:OnFailure(eventData)
self.ImgDrag.transform.position = self.StartPos
end

function m:UpdateView()
self.ImgDefault:SetActive(self.BlockData.State == 0)
self.ImgCheck:SetActive(self.BlockData.State == 1)
self.ImgTag:SetActive(self.BlockData.IsFirst)
end

---@param blockData AmusementParkOneConnectBlockData
function m:SetData(blockData)
self.BlockData = blockData
self.View.name = self.BlockData.Index
self:UpdateView()
end

function m:Dispose()
AssetUtil.UnloadAsset(self)
self:RemoveListener()
self.OnBeginDragCallBack = nil
self.OnDragCallBack = nil

LuaCodeInterface.ClearOutlet(self.View, self)
UnityEngine.Object.Destroy(self.View)
self.View = nil
end

return m

阅读全文 »

正交相机(Orthographic Camera)

Unity3D中的正交相机(Orthographic Camera)是一种投影方式,它不同于透视相机(Perspective Camera)的投影方式。在正交相机中,物体在视野中的大小与其与相机的距离无关,也就是说,所有物体在相机视野中呈现的大小是相同的。

Unity3D的正交相机可以看作是一个在固定位置的照相机,它将三维空间中的物体投影到一个二维图像平面上,而不考虑物体到相机的距离。因此,在正交投影中,无论物体离相机多远,它们在二维图像平面上的大小都不会改变。

正交相机的投影方式是通过一个虚拟的长方体来取景,并将场景投影到这个长方体的前面。在Unity中,可以通过更改相机参数来调整这个长方体的尺寸,进而影响相机视野中物体的显示大小。

主要特点和应用场景

物体大小不变

由于正交相机不考虑物体到相机的距离,所以物体在相机视野中的大小是固定的,这使得在2D游戏或者UI设计中非常方便。

无透视收缩效果

在正交投影中,远处的物体和近处的物体在图像平面上的大小是相同的,不会有透视收缩效果,这使得场景中的物体之间的相对距离
保持不变。

适用于2D游戏和UI设计

正交相机由于其特殊的投影方式,非常适合用于2D游戏和UI设计,可以很容易地实现平铺纹理或者背景等效果。

易于实现像素化效果

正交相机由于物体大小固定,所以可以很容易地实现像素化效果,这在一些复古风格的2D游戏中非常常见。

总的来说,Unity3D的正交相机通过忽略物体到相机的距离,实现了一种特殊的投影方式,这种方式在2D游戏和UI设计中有广泛的应用。

正交相机的主要属性

- 投影模式(Projection Type)

这是设置相机投影方式的属性,Unity中提供了多种投影模式,但对于正交相机来说,通常只会选择“正交(Orthographic)”这一项。
选择正交投影后,相机的视野不会因物体距离的增加而产生大小变化。

- 视野大小(Field of View)

在正交投影中,视野大小实际上定义了相机的视锥体的大小,它决定了相机的可视范围。Unity中是以角度来定义的,数值越大,
视野范围越宽。

- 近平面(Near Plane)和远平面(Far Plane)

这两个属性定义了相机视锥体的近边界和远边界。在正交相机中,这两个平面是固定垂直于相机前后的,不会因为相机的移动而改变。
近平面和远平面的距离决定了相机的深度范围。

- 正交尺寸(Orthographic Size)

这个属性定义了相机的虚拟长方体视野的尺寸。相机将场景投影到一个虚拟的长方体上,这个长方体的长、宽、高分别由正交尺寸的
X、Y、Z分量决定。物体在相机视野中的大小实际上是由这个长方体的尺寸决定的。例如,如果正交尺寸的X为10,Y为5,那么相机视野
的宽高比就是2:1。

- 平移(Position)

这是相机在三维空间中的位置,可以自由设置。

- 旋转(Rotation)

这是相机在三维空间中的旋转,同样可以自由设置。旋转会影响相机的朝向,从而改变拍摄的视角。

- 缩放(Scale)

在Unity中,相机也有缩放属性,但这通常指的是相机视锥体的缩放,而不是像物体一样改变大小。这个属性在正交相机中不太常用。
阅读全文 »

鼠标键盘

鼠标键盘输入控制,Input类,要在Update()函数中检测

鼠标点击

0左键 1右键 2滚轮

按下鼠标左键:

Input.GetMouseButtonDown(0)

持续按下鼠标左键:

Input.GetMouseButton(0)

抬起鼠标左键:

Input.GetMouseButtonUp(0)

GetMouseButtonDown()和GetMouseButtonUp()成对出现

按钮键盘按键

KeyCode 枚举

按下键盘A键:

Input.GetKeyDown(KeyCode.A)

持续按下A键:

Input.GetKey(KeyCode.A)

抬起键盘按键:

Input.GetKeyUp(KeyCode.A)

GetKeyDown() 和 GetKeyUp()成对出现

实例

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
// Update is called once per frame
void Update()
{
//鼠标点击
//按下鼠标 0左键 1右键 2滚轮
if (Input.GetMouseButtonDown(0))
{
Debug.Log("按下了鼠标左键");
}
//持续按下
if (Input.GetMouseButton(0))
{
Debug.Log("持续按下鼠标左键");
}
//抬起鼠标
if (Input.GetMouseButtonUp(0))
{
Debug.Log("抬起了鼠标左键");
}

//键盘
//按下键盘
if (Input.GetKeyDown(KeyCode.A))
{
Debug.Log("按下A键");
}
//持续按下A键
if (Input.GetKey(KeyCode.A))
{
Debug.Log("持续按下A键");
}
//抬起键盘按键
if (Input.GetKeyUp(KeyCode.A))
{
Debug.Log("松开抬起A键");
}
}
阅读全文 »