Canvas-Scaler

话说坑在何方?想当年年少轻狂时,层做了个类似下图的玩意:

勃主大笑三声,把screen的大小拖动了一下,然后它就变成了这个样子:

这是一件相当窝巢的事情,勃主苦练锚点三十年,终究还是没有搞定,知道师父他老人家蛋蛋的提点了一句“看看Canvas Scaler”。。。。。。

上图,勃主当时的scaler设定是这样的:

嗯,问题就在这里了,UI扩展模型——固定像素大小!!!!

好吧,淡淡的改成了下面这样:

问题解决了,ui怎么捏都不会变形了。。。

到这里,好奇心颇重的勃主撩起三脚猫的English打开了官方API:

[官方API的老巢](file:///D:/Program%20Files%20%28x86%29/Unity/Editor/Data/Documentation/html/en/Manual
/script-CanvasScaler.html)

对于Canvas Scaler的描述是这样的“The Canvas Scaler component is used for controlling

the overall scale and pixel density of UI elements in the Canvas. This scaling
affects everything under the Canvas, including font sizes and image
borders.”(画布定标器组件是用于控制UI元素的整体规模和像素密度在画布上。这个扩展影响在画布上的一切,包括字体大小和图像边界。)我知道,谁都受不了这该死的鸡翻,所以我还得重新翻过:Canvas
Scaler是用来控制Canvas上的UI元素整体规模和像素的组件,这个扩展影响Canvas上的一切,包括字体大小和图像边界。

Canvas Scaler的ui scale mode有三种值(constan pixel size、scale with screen

size和constant physical size),接下来我就来介(翻)绍(译)一下这三种情况下的各参数代表的含义

1.Constant Pixel Size 不变像素大小

参数:

Scale Factor–大小比例;

Reference Pixels Per Unit – ,每单位代表像素量

2.Scale With Screen Size根据屏幕大小定标

-Reference Resolution(参考分辨率)

The resolution the UI layout is designed for. if the screen resolution is
larger, the UI will be scaled up, and if it’s smaller, the UI will be scaled
down.

参照这个UI布局所依据的分辨率,如果屏幕分辨率更大,那么UI会变大,如果屏幕分辨率更小,那么UI会变小。

-Screen Match Mode(屏幕匹配模式)

Match Width or Height 参考宽或者高或者两者来规划画布

Expand 横纵两个方向扩大画布使画布不小于参考

Shrink 裁切画布使画布不大于参考

-Reference Pixels Per Unit 每单位的参考像素

当选择Match Width or Height时会有Match滑块,用来决定width和height的影响比例

3.Constant Physical Size 不变的物理尺寸

Physical Unit可以设置物理单位

Fallback Screen DPI屏幕分辨率不明是采用的分辨率

Default Sprite DPI 精灵每英寸的默认像素

Reference Pixels Per Unit

4.当Canvas的Render Mode属性为world space时

Canvas Scaler的ui Scale Mode为world不可改变

脚本批量打包渠道包研究

最近在研究Unity3D脚本批量打包,比如在Android平台下各种不同分辨率和不同内存大小的机器,可能还有不同的渠道包,不同渠道可能用的SDK都不一样,这一切的一切都表明你的代码无法做到自适应的,除非批量打包提供各个平台的预定义标签#define

Unity默认提供了一些预定义标签如:

UNITY_EDITOR : 编辑器模式下。

UNITY_STANDALONE:PC Mac Linux模型下。

UNITY_IPHONE:IOS模式下。

UNITY_ANDROID:ANDROID模式下。

还有很多预定义标签、大家可以在这里看到:http://docs.unity3d.com/Documentation/Manual/PlatformDependentCompilation.html

官方提供的标签属于比较大的范围标签,比如我希望在UNITY_ANDROID下面在写一些自定义的标签、类似 QQ UC
CMCC这样的渠道标签该如何呢?如下图所示,ProjectSetting打包界面每个平台都会有Scripting Define
Symbols这个选项,可以在这里添加每个平台下对应的自定义标签(多个标签用“;”号隔开),这里我设置的是Android平台,如果IOS也需要打这样的渠道标签那么也要在IOS页面Scripting
Define Symbols选项处添加对应的标签。

标签做出来了就好办了,然后在代码中我们可以这样来写。如果在Scripting Define Symbols中没有出现的标签默认是不启用的,就像

#define Test 一样,会自动被注释掉。

然后我们看看如何实现脚本批量打包。

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
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
public class MyEditorScript
{

//得到工程中所有场景名称
static string[] SCENES = FindEnabledEditorScenes();

//一系列批量build的操作

[MenuItem("Custom/Build Android QQ")]
static void PerformAndroidQQBuild()

{

BulidTarget("QQ", "Android");
}

[MenuItem("Custom/Build Android UC")]
static void PerformAndroidUCBuild()
{
BulidTarget("UC", "Android");
}

[MenuItem("Custom/Build Android CMCC")]
static void PerformAndroidCMCCBuild()
{
BulidTarget("CMCC", "Android");
}

[MenuItem("Custom/Build Android ALL")]
static void PerformAndroidALLBuild()
{
BulidTarget("QQ", "Android");
BulidTarget("UC", "Android");
BulidTarget("CMCC", "Android");
}

[MenuItem("Custom/Build iPhone QQ")]
static void PerformiPhoneQQBuild()
{
BulidTarget("QQ", "IOS");
}

[MenuItem("Custom/Build iPhone QQ")]
static void PerformiPhoneUCBuild()
{
BulidTarget("UC", "IOS");
}

[MenuItem("Custom/Build iPhone CMCC")]
static void PerformiPhoneCMCCBuild()
{
BulidTarget("CMCC", "IOS");
}

[MenuItem("Custom/Build iPhone ALL")]
static void PerformiPhoneALLBuild()
{
BulidTarget("QQ", "IOS");
BulidTarget("UC", "IOS");
BulidTarget("CMCC", "IOS");
}

//这里封装了一个简单的通用方法。
static void BulidTarget(string name, string target)
{
string app_name = name;
string target_dir = Application.dataPath + "/TargetAndroid";
string target_name = app_name + ".apk";

BuildTargetGroup targetGroup = BuildTargetGroup.Android;
BuildTarget buildTarget = BuildTarget.Android;

string applicationPath = Application.dataPath.Replace("/Assets", "");
if (target == "Android")
{
target_dir = applicationPath + "/TargetAndroid";
target_name = app_name + ".apk";
targetGroup = BuildTargetGroup.Android;
}

if (target == "IOS")
{
target_dir = applicationPath + "/TargetIOS";
target_name = app_name;
targetGroup = BuildTargetGroup.iPhone;
buildTarget = BuildTarget.iPhone;
}

//每次build删除之前的残留
if (Directory.Exists(target_dir))
{
if (File.Exists(target_name))
{
File.Delete(target_name);
}
}
else
{
Directory.CreateDirectory(target_dir);
}

//==================这里是比较重要的东西=======================
switch (name)
{
case "QQ":
PlayerSettings.bundleIdentifier = "com.game.qq";
PlayerSettings.bundleVersion = "v0.0.1";
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, "QQ");
break;
case "UC":
PlayerSettings.bundleIdentifier = "com.game.uc";
PlayerSettings.bundleVersion = "v0.0.1";
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, "UC");
break;
case "CMCC":
PlayerSettings.bundleIdentifier = "com.game.cmcc";
PlayerSettings.bundleVersion = "v0.0.1";
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, "CMCC");
break;
}

//==================这里是比较重要的东西=======================
//开始Build场景,等待吧~
GenericBuild(SCENES, target_dir + "/" + target_name,
buildTarget, BuildOptions.None);
}
private static string[] FindEnabledEditorScenes()
{
List<string> EditorScenes = new List<string>();
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
{
if (!scene.enabled) continue;
EditorScenes.Add(scene.path);
}
return EditorScenes.ToArray();
}

static void GenericBuild(string[] scenes, string target_dir,
BuildTarget build_target, BuildOptions build_options)
{
EditorUserBuildSettings.SwitchActiveBuildTarget(build_target);
string res =
BuildPipeline.BuildPlayer(scenes, target_dir, build_target, build_options);
if (res.Length <= 0)
{
throw new Exception("BuildPlayer failure: " + res);
}
}
}{

这里面忘说了一点,如果我们希望在性能高的手机上用一套好的资源,在性能低的手机上用一套差一点的资源该怎么办?那么首先我们先搞清楚Unity会把什么资源打包,什么资源不打包?

1.Resources文件夹

Resources文件夹是一个只读的文件夹,通过Resources.Load()来读取对象。因为这个文件夹下的所有资源都可以运行时来加载,所以Resources文件夹下的所有东西都会被无条件的打到发布包中。建议这个文件夹下只放Prefab或者一些Object对象,因为Prefab会自动过滤掉对象上不需要的资源。举个例子我把模型文件还有贴图文件都放在了Resources文件夹下,但是我有两张贴图是没有在模型上用的,那么此时这两张没用的贴图也会被打包到发布包中。假如这里我用Prefab,那么Prefab会自动过滤到这两张不被用的贴图,这样发布包就会小一些了。

2.StreamingAssets

StreamingAssets文件夹也是一个只读的文件夹,但是它和Resources有点区别,Resources文件夹下的资源会进行一次压缩,而且也会加密,不使用点特殊办法是拿不到原始资源的。但是StreamingAssets文件夹就不一样了,它下面的所有资源不会被加密,然后是原封不动的打包到发布包中,这样很容易就拿到里面的文件。所以StreamingAssets适合放一些二进制文件,而Resources更适合放一些GameObject和Object文件。StreamingAssets
只能用过www类来读取!!

3.
最后凡是在Hierarchy视图对象引用过的资源文件也会被无条件打包到发布包中。如果有一部分文件可能没有在Resources文件夹下也没有在StreamingAssets文件夹下,也没有被Hierarchy视图游戏对象引用,那么这类资源是不会被打包到发布包中的。

OK!搞清楚这一点就好办了!在处理不同包对应不同资源包的时候,尽量让可配置的资源放在Resources
或StreamingAssets文件夹下,运行的时候程序动态的来读取它们,最后显示在游戏中就可以了。在批量打包前,在Project视图下创建不同包的资源文件夹,
然后脚本 AssetDatabase 动态的将资源拷贝至Resources或StreamingAssets 文件夹中,

http://docs.unity3d.com/Documentation/Manual/StreamingAssets.html

1
2
3
4
5
6
7
8
[MenuItem("Custom/Build Android QQ")]
static void PerformAndroidQQBuild()
{
//先把资源拷贝到Resources或者StreamingAssets
AssetDatabase.CopyAsset("path", "newPath");
//然后开始编译版本
BulidTarget("QQ", "Android");
}

代码中说到还有一个重要的东西就是PlayerSettings类。因为在Build的时候不同平台下可能会有一些PlatformSettings是不一样的,所以需要在脚本里面动态的设置它,强大的参数列表在这里:http://docs.unity3d.com/Documentation/ScriptReference/PlayerSettings.html。根据情况来批量构建自己的工程吧~

另外,由于IOS工程比较特殊,使用这样的方法我们只能生成出来多个IOS的工程文件,但是这并不是最终发布的版本。如果想一键生成.ipa文件的话。

1.通过命令行来Build
IOShttp://docs.unity3d.com/Documentation/Manual/CommandLineArguments.html

2.通过shell来自动打包 1生成的xcode工程,最终生成渠道包。

这两种方法我已经在网上找到了答案,今天太晚了就不在研究了,下一篇的时候我在补上。 祝大家学习愉快!!不早了,晚安!欢迎大家一起来讨论与学习,嘿嘿!!!

代码下载地址:http://vdisk.weibo.com/s/HUf2W

Unity5开发Oculus项目入门范例

今天为大家介绍使用Unity 5开发Oculus项目的入门范例Oculus Sample
Framework,该范例由Oculus制作,是为VR开发者和设计师提供的实验性示例集合。

其中包含了一系列的解决VR典型问题的示例场景,有第一人称视角的运动机制和基于注视的交互界面。每个范例都提供了在应用内调整参数的控制面板,这些参数包括传送过程中从透明到消失的时长,界面控制元素的延迟或瞄准器的Z深度等。该控制面板本身就很好的展示了VR中的控制器,可以直接将其用于自己的VR项目。

项目中的每个场景都展示了一个与VR开发相关的概念。整个范例是一个Unity 5 的项目。可以在Windows平台上执行,并且可以在Gear VR
Concepts
商城免费下载。这个应用可以让使用者在不打开Unity编辑器的情况下深入到场景中理解一些VR开发的概念。每个VR场景中都包含一份文档,所以可以深入到VR场景中直接学习。

如果想要深入探索并实现示例内的VR操作界面没有提供的功能,建议在Unity中打开并编辑该项目。

示例的主要作用是提供一套探索VR设计概念的工具,并非推荐大家都这么做。每个示例都包含了可供测试的游戏机制,其中有些设置会让玩家产生不适感,这是我们设计VR时需要避免的。这些功能的主要用途就是让开发者体验到什么是可行的,什么是不可行的。

示例场景简介

整个示例框架包含了很多场景。最好的学习方法就是进入场景中尝试。我们先作为测试人员来看看这几个场景。

十字准星

这个示例展示了基于注视位置的十字准星或者瞄准器,并探讨了一些必须注意的相关因素。在非VR游戏中,十字准星是否位于视野中心是无关紧要的,但VR开发者则必须要确定十字准星显示位置所代表的深度信息。十字准星的位置如果太近,观察者就会不舒服。如果太远,当准星看起来比场景中位于它下面的物体还远时,又会让玩家产生深度上的错觉。

解决该问题的方法之一,是沿着玩家的视角进行光线投射,并将十字准星定位在视线接触到的第一个物体上。这样就能保证十字准星处在一个合适位置的同时不与场景中的深度信息冲突。你可以在示例中尝试上述方法或一些其它的解决方法,还可以在运行时手动控制十字准星的深度。

这个示例也展示了一些其它概念,例如导弹是如何投射的。如果将十字准星对准导弹,并且该准星与玩家保持固定的距离,就必须决定导弹是沿着从枪口出发的一条轨迹穿过十字准星,还是沿着玩家视觉中心与准星连线的平行线穿过十字准星。后者是非VR游戏的常用做法,这种方法很直观。这个示例可以让你更直接的感受并理解这种区别。

运动

这个示例场景可以体验到第一人称视角的实时移动控制,从而可以更好理解相关设计上的权衡。第一人称视角的移动控制设计需要非常小心,因为这种移动很容易造成不适感。

这个场景可以调整的变量有:

移动速度

旋转速度

玩家朝向是否由视觉方向控制

旋转的步长(持续旋转或者使用固定步骤指定步长的旋转)

当执行“每一步”旋转时的动画速度(非瞬间完成)

瞬移

瞬移是VR中常用的移动方式,因为这样可以避免第一人称视角控制运动引起的不适感。这个示例场景实现了简单的瞬移机制。

这个示例中展示的一个巧妙设计是玩家在瞬移后视角位置的旋转方式。这种模式中,瞬移后视角的方向是由玩家控制的,这个方向可以在瞬移前就设定好。上面的截图展示的就是这个操作,一个发光的虚拟人物出现在了瞬移的终点,展示了瞬移后玩家的朝向且可以由玩家来控制。在瞬移结束后,玩家面对的方向与之前设定的虚拟人的朝向是一致的。

这看起来很直观,但可能存在玩家需要旋转头部才能看到瞬移终点的情况。这时玩家在瞬移完成后朝向与模型保持一致同时头部旋转呢?还是将最终朝向与旋转头部后的自然前方保持一致呢?

这个示例展示了以上两种方式,至于哪一种更直观则取决于另一些因素。示例可以帮助你很直观的理解这两种模式的区别,并探索出个性化的解决方案。

UI(用户界面)

场景“Pointers” (指示点)和“Pointers – Gaze
Click”(指示点-凝视点击)展示了利用指示点来实现VR中的UI交互。两个场景均展示了基于凝视的交互机制,包含了与物理对象和平面UI的交互。

场景“Pointers” (指示点)和“Pointers – Gaze Click”(指示点-凝视点击)很相似,只是“Pointers – Gaze
Click”(指示点-凝视点击)并不需要手柄或者触摸板。在这个场景中,凝视一个UI元素时会在凝视光标附近产生一个圆形的进度条,进度条会很快填充满(如上图所示)。当环形进度条填充完毕,就会执行相应UI所负责的动作。

其它示例场景

篇幅有限无法一一介绍每个场景,各场景都包含对应的文档,我们可以在VR应用内查看这些文档。其它场景包括:

Keyboard:VR键盘的简单实现。

Mirror:展示了模型头部按照玩家头部动作进行运动,以实现场景中的镜像效果。

Stairs:探索楼梯效果在第一人称视角下体验的舒适度。

Surface Detail:探索不同着色技术所描绘出的不同表面细节,可以更好的理解它们在VR中的效果。

Tracking Volume:展示一些方法,在用户离跟踪边界范围太近时给予提示。

结论

这些示例只能作为理解和探索VR中一些常用设计的出发点。事实上,这些示例只是不断发展的VR交互中最浅显的部分。希望各位开发者能觉得这个出发点对你将来的新设计思路有一定帮助。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×