上一篇:Unity打包到安卓(一)
这一次打算简单做一个手机版的roll a ball。
1.输入
Unity给了移动端输入的API,比如触摸、加速度计的输入,也可以调用手机的震动反馈。
详见:Android 移动端脚本、移动设备输入、Input、Handheld 等。
当然我们可以用这些API写我们自己的输入方式,但是我现在想要用一个虚拟摇杆来控制roll a ball中小球的移动。自己写一个有点麻烦,搜了一下商店里的都是收费的。幸好在github上找到一个符合预期的项目 Unity3D-Simple-Mobile-Joystick。
下载下来之后有一个package,导入package,demo和demo相关的就不需要导入了。只要下图中勾选的内容。
接下来把MobileJoyStick预制体放置到场景中,因为我不需要右摇杆,就把RightJoyStick给禁用掉了。效果如下图所示。并且右键->UI->EventSystem
新建一个EventSystem,否则无法拖动摇杆。
并且把LeftJoyStick的锚点改成左下角,确保UI的位置保持在屏幕左下角。
接下来稍微写点东西测试测试一下,看看能不能用。
using UnityEngine;
using UnityEngine.UI;
public class MyInputTest : MonoBehaviour
{
// 摇杆
public MobileInputController controller;
// UI
public Text horiText;
public Text vertText;
private void Update()
{
horiText.text = "Hori:" + controller.Horizontal;
vertText.text = "Vert:" + controller.Vertical;
}
}
没有问题。
2.Roll a ball
2.1.导入
直接去商店下 成品 ,我可懒得重新写了。
导入roll a ball的完整项目。(ProjectSettings我就不导了,我怕把我之前的一些设置给覆盖了,问题应该不大)
导入完成之后打开Roll-a-ball场景,运行一下没有问题。
2.2.修改
然后现在把他改成用虚拟摇杆输入。首先把MobileJoyStick预制体放入Roll-a-ball场景,这里已经有EventSystem就不用再加了。
然后打开PlayerController.cs这个脚本进行一些修改,修改后如下。(原来的所有注释都删掉了,不难。现在注释的都是修改或添加的地方)
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
// 虚拟摇杆
public MobileInputController joystick;
public float speed;
public Text countText;
public Text winText;
private Rigidbody rb;
private int count;
void Start ()
{
rb = GetComponent<Rigidbody>();
count = 0;
SetCountText ();
winText.text = "";
// 屏幕旋转 设置为跟随设备的旋转
Screen.orientation = ScreenOrientation.AutoRotation;
}
void FixedUpdate ()
{
// 修改前
//float moveHorizontal = Input.GetAxis ("Horizontal");
//float moveVertical = Input.GetAxis ("Vertical");
// 修改后
float moveHorizontal = joystick.Horizontal;
float moveVertical = joystick.Vertical;
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
// 只有在安卓平台才震动
#if UNITY_ANDROID
// 震动 只能震动0.5s
Handheld.Vibrate();
#endif
other.gameObject.SetActive (false);
count = count + 1;
SetCountText ();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString ();
if (count >= 12)
{
winText.text = "You Win!";
}
}
}
然后记得在编辑器内给public MobileInputController joystick
赋值。然后按上面的方法,把Scenes In Build改成当前场景然后打包出来在手机上运行。
效果如视频所示,手机上播放可能看到的视频不对,可以到原视频观看。
震动的话,Unity的API只给了Handheld.Vibrate()
这一个函数,也没有设置震动时间的。感觉这个时间太长了。但是查了一下发现要修改震动时间还得重新打包SDK,算了下次吧。参考自《Unity3D —— 手机设备震动接口》《Unity+Android交互教程——让手机"动"起来》。
3.扩展
虽然项目已经成功的打包并运行了,但是还有一些地方是可以完善的。
3.1.画面
这是在手机上运行的截图,可以看出来远处的方块没有阴影了。但是在Unity编辑器中看是好好的。
要解决这个,就打开编辑器中的Editor->ProjectSetting->Quality
。
可以看到这里Unity给我们预先设置了6个等级的质量选项,这里默认PC平台是最高质量,安卓平台是中等质量(当然这里有几个等级,默认是什么等级,每个等级的具体设置是什么都是可以自行修改的) 。
选择Medium可见,这一等级的阴影距离只有20,而最高等级的Ultra有150。这就是问题所在,阴影距离太近了。
我们可以把Medium的阴影距离改大,也可以把安卓的默认等级调为Ultra。我这就直接调成Ultra好了,这么简单的一个场景手机还是撑得住的。
3.2.更多设置
如果刚才留意过的话,我们会发现我们每一次导出的安卓应用图标和名称都是这个。
可以修改吗?当然可以。
打开Editor->ProjectSetting->Player
,就可以看到这样一个界面。在这里可以修改我们的公司姓名、应用的名称、版本号和图标等等。
详情可见Android Player 设置,根据自己的需求进行设置即可。
3.3.摇杆的位置
实际运行的过程中(可看前面的演示视频),可以看出虚拟摇杆的位置移动的太小了,根本移不到遥感背景的边缘。在编辑器中是可以的。研究了一通发现是分辨率有关系,因为这一个虚拟遥感的插件计算遥感的位置的时候,对手机的分辨率有一定的需求。涉及到一些UI适配的问题,没有深究。
稍微改了一下代码就解决了。打开MobileInputController.cs文件(前面github上下的那个插件中的脚本) ,改成下面代码的让子,然后记得给CanvasScaler赋值为这样就解决了。(其实现在这种方式,当手机的长宽比例变化太大的时候还是会出问题,我不想改了)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
[RequireComponent(typeof(AspectRatioFitter))]
public class MobileInputController : MonoBehaviour, IDragHandler, IEndDragHandler, IPointerDownHandler, IPointerUpHandler {
public RectTransform Background;
public RectTransform Knob;
[Header("Input Values")]
public float Horizontal = 0;
public float Vertical = 0;
Vector2 PointPosition;
public CanvasScaler canvasScaler;
private Vector2 insideWidth; // 摇杆背景和摇杆的内部宽度差
private Vector2 canvasScale; // 参考分辨率与实际分辨率的比例
public void OnDrag(PointerEventData eventData)
{
PointPosition = new Vector2(
(eventData.position.x - Background.position.x) / insideWidth.x * canvasScale.x,
(eventData.position.y - Background.position.y) / insideWidth.y * canvasScale.y);
PointPosition = (PointPosition.magnitude>1.0f)?PointPosition.normalized :PointPosition;
Knob.anchoredPosition = new Vector2
(PointPosition.x * insideWidth.x,
PointPosition.y * insideWidth.y);
}
public void OnEndDrag(PointerEventData eventData)
{
PointPosition = new Vector2(0f,0f);
Knob.transform.position = Background.position;
}
public void OnPointerDown(PointerEventData eventData)
{
// 计算摇杆背景和摇杆的内部宽度差
insideWidth.x = (Background.rect.size.x - Knob.rect.size.x) / 2;
insideWidth.y = (Background.rect.size.y - Knob.rect.size.y) / 2;
// 计算参考分辨率与实际分辨率的比例
canvasScale.x = canvasScaler.referenceResolution.x / Screen.currentResolution.width;
canvasScale.y = canvasScaler.referenceResolution.y / Screen.currentResolution.height;
OnDrag(eventData);
}
public void OnPointerUp(PointerEventData eventData) {
OnEndDrag(eventData);
}
void Update () {
Horizontal = PointPosition.x;
Vertical = PointPosition.y;
}
public Vector2 Coordinate()
{
return new Vector2(Horizontal,Vertical);
}
}
记得把ReferenceResolution改成和手机分辨率一样的或者比例一样的。
(roll a ball告一段落,下一步是尝试AR)
(还有就是,可以把上面脚本中Screen.orientation = ScreenOrientation.AutoRotation;删掉,直接在projectSetting->player中把orientation默认设置为横屏)