【Holograms 101D】一步步用Unity 开发 Hologram
Holograms 101
该教程将带领你走完 Hologram 创建 的全过程。整个开发分成如下几个部分: 聚焦输入 gaze, 手势输入gesture , 声音输入voice input, 映射声音spatial sound and 映射地图spatial mapping.
整个教程大概耗时1个小时.
开始前的要求:
工程文件
- 下载该工程所需要的 开发文件
- 解压下载的 开发文件,将该文件夹命名为 Origami
Chapter 1 - "Holo" world
在这一章节,我们将要配置 我们的 第一个 Unity 工程,并走过 整个Build (编译)和 deploy(部署)过程
目标
- 设置Unity环境,以适应Hologram开发
- 创建一个Hologram
- 看到创建出来的Hologram工程效果
步骤
- 打开Unity
- 点击 Open.
- 找到之前解压并重命名为 Origami 文件夹
- 选择 Origami 并点击 Select Folder.
- 因为新工程 Origami project 并没有包含任何 scene, 所以需要保存当前的默认 scene (default scene)为一个新的scene: File / Save Scene As.
- 将新的scene命名为 Origami 并点击 Save 按钮.
配置主虚拟镜头(main virtual camera)
- 在 Hierarchy Panel 中, 选中 Main Camera.
- 在右侧的 Inspector 选项栏中,将 position 配置为 0,0,0.
- 在当前的 Clear Flags 属性中,将下拉框中的设置从Skybox 改为 Solid color
- 将 Background 属性点开
- 将 R, G, B, 和 A 设置为0

设置场景scene
- 在 Hierarchy Panel 中, 点击 Create 并 Create Empty
- 新创建的文件夹名字是 GameObject,重命名该文件夹为 OrigamiCollection
- 从 Project Panel 的 Holograms 文件夹中:
- 拖拽 Stage 到 Hierarchy Panel 中,作为 OrigamiCollection 的子项
- 拖拽 Sphere1 到 Hierarchy Panel 中,作为 OrigamiCollection 的子项
- 拖拽 Sphere2 到 Hierarchy Panel 中,作为 OrigamiCollection 的子项
- 删除 Hierarchy Panel 中的 Directional Light 项
- 从 Holograms 文件夹中,拖拽 Lights 项到 Hierarchy Panel 的根目录
- 选中 Hierarchy Panel 的 OrigamiCollection 目录
- 在右侧的 Inspector 栏,设置 tranform的position值为0, -0.5, 2.0.
- 点击 项目 正上方的 “播放”
按钮,可以预览效果 
- 再次点击 “播放”按钮,关闭预览
从Unity导出工程到Visual Studio
- 选择 File > Build Settings.
- 选择 Windows Store
- SDK 选择 Universal 10 并选择 Build Type 为 D3D.
- 选中 Unity C# Projects.
- 点击 Add Open Scenes 按钮,添加当前的视图到Scenes In Build 栏中
- 点击 Build.

- 接下来会弹出一个windows窗口,在该窗口创建文件夹 App
- 单击 App 文件夹
- 然后点击 选择文件夹. 就会开始编译

- 当编译结束,就会自动弹出编译好的文件目录
- 打开 App 文件夹
- 双击 Origami.sln.
- 在VS顶部工具栏中,修改Debug 为 Release ,并修改 ARM 为 X86 架构
- 点击设备旁的 三角形按钮,选择远程计算机( Remote Device)
- 将地址(Address) 设置为Hololens的 IP 或者 Hololens的名称
- 设置身份验证模式(Authentication Mode)为 通用(Universal)
- 点击选择( Select)
- 如果是 使用Hololens模拟器,则直接选择HoloLens Emulator 即可。
- 紧接着开始调试
- Origami 项目将会被部署在你的Hololens上(或者Hololens 模拟器上),并运行
- 带上你的Hololens开始体验吧!(译者表示完全体验不了,因为没设备啊(┬_┬),只能仿真玩玩)


Chapter 2 - Gaze
在本节中,将会描述Hololens三种交互方式之一的 -- 凝视输入(gaze).
目标
- 让我们的凝视输入可视化(视线所指会出现一个圆圈).
介绍
- 返回 Unity 工程
- 选择 Holograms 文件夹
- 将 Cursor 组建拖入 Hierarchy panel 的根目录中

- 右击 Scripts 文件夹,进入Create 目录,并选择C# Script.

- 将新创建的脚本命名为 WorldCursor
- 选中 Cursor 组件
- 拖拽 WorldCursor 脚本到Inspector panel 中的 Cursor 组件上

- 这时候,再双击 WorldCursor 脚本文件,会自动打开 Visual Studio
- 复制下面的代码到 WorldCursor.cs 文件中,保存
|
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
|
using UnityEngine;public class WorldCursor : MonoBehaviour{ private MeshRenderer meshRenderer; // Use this for initialization 初始化时候调用 void Start() { // Grab the mesh renderer that's on the same object as this script. // 获取 meshRenderer meshRenderer = this.gameObject.GetComponentInChildren<MeshRenderer>(); } // Update is called once per frame 每一帧都会自动更新 void Update() { // Do a raycast into the world based on the user's // head position and orientation. var headPosition = Camera.main.transform.position; var gazeDirection = Camera.main.transform.forward; RaycastHit hitInfo; if (Physics.Raycast(headPosition, gazeDirection, out hitInfo)) { // If the raycast hit a hologram... // Display the cursor mesh. meshRenderer.enabled = true; // Move the cursor to the point where the raycast hit. this.transform.position = hitInfo.point; // Rotate the cursor to hug the surface of the hologram. this.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal); } else { // If the raycast did not hit a hologram, hide the cursor mesh. meshRenderer.enabled = false; } }} |
- 进入目录 File > Build Settings 重新生成工程
- 返回Visual Studio 解决方案中
- 这时会提示 是否需要重新加载 ,选择是。
- 然后继续点击调试

- 现在可以看到视线聚焦之处,有一个红色圆环。

Chapter 3 - Gestures
在这一章节中,我们将学习使用 手势输入gestures。通过使能 Unity 的物理引擎,打开重力模拟, 当用户选择了一个纸球,就会让该纸球下落。
目标
- 使用选择手势控制Hologram
步骤
接下来创建一个脚本,使得程序能够检测到 选择手势
- 在 Scripts 目录中,创建一个名为 GazeGestureManager 的脚本
- 将 GazeGestureManager 脚本拖入 OrigamiCollection 目录中

- 打开 GazeGestureManager 脚本,并复制如下code:
|
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
|
using UnityEngine;using UnityEngine.VR.WSA.Input;public class GazeGestureManager : MonoBehaviour{ public static GazeGestureManager Instance { get; private set; } // Represents the hologram that is currently being gazed at. public GameObject FocusedObject { get; private set; } GestureRecognizer recognizer; // Use this for initialization void Start() { Instance = this; // Set up a GestureRecognizer to detect Select gestures. recognizer = new GestureRecognizer(); recognizer.TappedEvent += (source, tapCount, ray) => { // Send an OnSelect message to the focused object and its ancestors. if (FocusedObject != null) { FocusedObject.SendMessageUpwards("OnSelect"); } }; recognizer.StartCapturingGestures(); } // Update is called once per frame void Update() { // Figure out which hologram is focused this frame. GameObject oldFocusObject = FocusedObject; // Do a raycast into the world based on the user's // head position and orientation. var headPosition = Camera.main.transform.position; var gazeDirection = Camera.main.transform.forward; RaycastHit hitInfo; if (Physics.Raycast(headPosition, gazeDirection, out hitInfo)) { // If the raycast hit a hologram, use that as the focused object. FocusedObject = hitInfo.collider.gameObject; } else { // If the raycast did not hit a hologram, clear the focused object. FocusedObject = null; } // If the focused object changed this frame, // start detecting fresh gestures again. if (FocusedObject != oldFocusObject) { recognizer.CancelGestures(); recognizer.StartCapturingGestures(); } }} |
- 创建另外一个脚本 SphereCommands.
- 占看 OrigamiCollection 目录
- 拖拽 SphereCommands 脚本到 Sphere1 模型上
- 拖拽 SphereCommands 脚本到 Sphere2 模型上

- 打开 visual studio 编辑,复制如下代码到 SphereCommands 脚本中:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
using UnityEngine;public class SphereCommands : MonoBehaviour{ // Called by GazeGestureManager when the user performs a Select gesture void OnSelect() { // If the sphere has no Rigidbody component, add one to enable physics. if (!this.GetComponent<Rigidbody>()) { var rigidbody = this.gameObject.AddComponent<Rigidbody>(); rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous; } }} |
- 重新生成Hologram
- 注视纸球
- 采用选择手势,查看纸球下落过程

Chapter 4 - Voice
这一章节,我们将要添加两个语音输入命令( voice commands ):
"Reset world": 将掉落的小球,初始化到原始位置
"Drop sphere":令小球掉落
目标
- 添加常驻后台的声音识别命令.
- 创建一个能对声音产生反应的应用
步骤
- 在 Scripts 目录中,创建一个名为 SpeechManager 的脚本
- 拖拽 SpeechManager 脚本到 OrigamiCollection 目录中
- 双击打开 SpeechManager 脚本
- 复制如下代码到脚本 SpeechManager.cs 中:
|
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
|
using System.Collections.Generic;using System.Linq;using UnityEngine;using UnityEngine.Windows.Speech;public class SpeechManager : MonoBehaviour{ KeywordRecognizer keywordRecognizer = null; Dictionary<string, System.Action> keywords = new Dictionary<string, System.Action>(); // Use this for initialization void Start() { keywords.Add("Reset world", () => { // Call the OnReset method on every descendant object. this.BroadcastMessage("OnReset"); }); keywords.Add("Drop Sphere", () => { var focusObject = GazeGestureManager.Instance.FocusedObject; if (focusObject != null) { // Call the OnDrop method on just the focused object. focusObject.SendMessage("OnDrop"); } }); // Tell the KeywordRecognizer about our keywords. keywordRecognizer = new KeywordRecognizer(keywords.Keys.ToArray()); // Register a callback for the KeywordRecognizer and start recognizing! keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized; keywordRecognizer.Start(); } private void KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args) { System.Action keywordAction; if (keywords.TryGetValue(args.text, out keywordAction)) { keywordAction.Invoke(); } }} |
- 打开 SphereCommands脚本
- 更新其代码如下:
|
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
|
using UnityEngine;public class SphereCommands : MonoBehaviour{ Vector3 originalPosition; // Use this for initialization void Start() { // Grab the original local position of the sphere when the app starts. originalPosition = this.transform.localPosition; } // Called by GazeGestureManager when the user performs a Select gesture void OnSelect() { // If the sphere has no Rigidbody component, add one to enable physics. if (!this.GetComponent<Rigidbody>()) { var rigidbody = this.gameObject.AddComponent<Rigidbody>(); rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous; } } // Called by SpeechManager when the user says the "Reset world" command void OnReset() { // If the sphere has a Rigidbody component, remove it to disable physics. var rigidbody = this.GetComponent<Rigidbody>(); if (rigidbody != null) { DestroyImmediate(rigidbody); } // Put the sphere back into its original local position. this.transform.localPosition = originalPosition; } // Called by SpeechManager when the user says the "Drop sphere" command void OnDrop() { // Just do the same logic as a Select gesture. OnSelect(); }} |
- 重新build整个工程
- 注视某一个球体,说出命令 "Drop Sphere".
- 说出命令"Reset World",让球体返回原来位置。
- (译者表示Emulator中也是可以使用声音来控制的,Follow me, say " Drop sphere~")
Chapter 5 - Spatial sound
在这一章节中,我们将要添加一段音乐到应用app中,然后在特定动作下,触发音乐。我们将要使用 声音映射spatial sound 来 将插入的音乐定位到指定的位置上。
目标
- 在我们的世界中,听到Hologram
步骤
- 进入选项 Edit > Project Settings > Audio

- 在右边的 Inspector Panel 中,, 找到 Spatializer Plugin 并选择 MS HRTF Spatializer.

- 将 Holograms 文件夹中的 Ambience 模型,拖拽到 OrigamiCollection 目录中
- 选中 OrigamiCollection 目录,并在右边Inspector panel找到 Audio Source ,修改如下属性:
- 选中 Spatialize
- 选中 Play On Awake.
- 修改 Spatial Blend 为 3D
- 选中 Loop
- 展开 3D Sound Settings,并在Doppler Level 中输入 0.1
- 设置 Volume Rolloff 为 Custom Rolloff.

- 在 Scripts 目录中,创建一个 SphereSounds 脚本
- 将脚本 SphereSounds 拖拽到 Sphere1 和 Sphere2 模型上
- 打开 SphereSounds 脚本,并更新如下代码:
|
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
|
using UnityEngine;public class SphereSounds : MonoBehaviour{ AudioSource audioSource = null; AudioClip impactClip = null; AudioClip rollingClip = null; bool rolling = false; void Start() { // Add an AudioSource component and set up some defaults audioSource = gameObject.AddComponent<AudioSource>(); audioSource.playOnAwake = false; audioSource.spatialize = true; audioSource.spatialBlend = 1.0f; audioSource.dopplerLevel = 0.0f; audioSource.rolloffMode = AudioRolloffMode.Custom; // Load the Sphere sounds from the Resources folder impactClip = Resources.Load<AudioClip>("Impact"); rollingClip = Resources.Load<AudioClip>("Rolling"); } // Occurs when this object starts colliding with another object void OnCollisionEnter(Collision collision) { // Play an impact sound if the sphere impacts strongly enough. if (collision.relativeVelocity.magnitude >= 0.1f) { audioSource.clip = impactClip; audioSource.Play(); } } // Occurs each frame that this object continues to collide with another object void OnCollisionStay(Collision collision) { Rigidbody rigid = this.gameObject.GetComponent<Rigidbody>(); // Play a rolling sound if the sphere is rolling fast enough. if (!rolling && rigid.velocity.magnitude >= 0.01f) { rolling = true; audioSource.clip = rollingClip; audioSource.Play(); } // Stop the rolling sound if rolling slows down. else if (rolling && rigid.velocity.magnitude < 0.01f) { rolling = false; audioSource.Stop(); } } // Occurs when this object stops colliding with another object void OnCollisionExit(Collision collision) { // Stop the rolling sound if the object falls off and stops colliding. if (rolling) { rolling = false; audioSource.Stop(); } }} |
- 保存代码,重新build工程
- 这时候两个小球,相当于一个声源,当移动视角,带上耳机体验的话,是能够感觉到双通道声音的赶脚的!(棒)
Chapter 6 - Spatial mapping
现在我们要使用 spatial mapping ,将 我们的应用放置到物理世界中的实物上。
目标
- 将真实世界代入到虚拟世界中
- 随意放置我们的Hologram
步骤
- 在Unity 中,选中Holograms 目录
- 拖拽 Spatial Mapping 到 Hierarchy 的根目录下
- 选中 Spatial Mapping
- 在右边的 Inspector panel 中,修改如下属性:
- 选中 Draw Visual Meshes 选项
- 将Draw Material 选项选为 "wireframe"
- 重新编译build工程
- 当应用运行,可以看到 (网格模型)wireframe mesh 将在物理世界中显示
- 观察小球是怎么在当前场景下落的
下面将指导你如何将 OrigamiCollection 移动到一个新的位置:
- 在 Scripts 文件夹中,创建一个脚本名叫TapToPlaceParent.
- 在 Hierarchy 中,展开 OrigamiCollection 目录,并选中Stage 模型
- 将脚本 TapToPlaceParent 拖拽到 Stage 模型上
- 更新代码如下:
|
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
|
using UnityEngine;public class TapToPlaceParent : MonoBehaviour{ bool placing = false; // Called by GazeGestureManager when the user performs a Select gesture void OnSelect() { // On each Select gesture, toggle whether the user is in placing mode. placing = !placing; // If the user is in placing mode, display the spatial mapping mesh. if (placing) { SpatialMapping.Instance.DrawVisualMeshes = true; } // If the user is not in placing mode, hide the spatial mapping mesh. else { SpatialMapping.Instance.DrawVisualMeshes = false; } } // Update is called once per frame void Update() { // If the user is in placing mode, // update the placement to match the user's gaze. if (placing) { // Do a raycast into the world that will only hit the Spatial Mapping mesh. var headPosition = Camera.main.transform.position; var gazeDirection = Camera.main.transform.forward; RaycastHit hitInfo; if (Physics.Raycast(headPosition, gazeDirection, out hitInfo, 30.0f, SpatialMapping.PhysicsRaycastMask)) { // Move this object's parent object to // where the raycast hit the Spatial Mapping mesh. this.transform.parent.position = hitInfo.point; // Rotate this object's parent object to face the user. Quaternion toQuat = Camera.main.transform.localRotation; toQuat.x = 0; toQuat.z = 0; this.transform.parent.rotation = toQuat; } } }} |
- 重新编译build工程
- 现在我们应该可以通过凝视(gazing)将我们的目标重新定位。使用选择手势(Select gesture)就可以移动位置

Chapter 7 - Holographic fun
Objectives
- Reveal the entrance to a holographic underworld.
Instructions
Now we'll show you how to uncover the holographic underworld:
- From the Holograms folder in the Project Panel:
- Drag Underworld into the Hierarchy to be a child of OrigamiCollection.
- In the Scripts folder, create a script named HitTarget.
- In the Hierarchy, expand the OrigamiCollection.
- Expand the Stage object and select the Target object (blue fan).
- Drag the HitTarget script onto the Target object.
- Open the HitTarget script in Visual Studio, and update it to be the following:
using UnityEngine;public class HitTarget : MonoBehaviour{// These public fields become settable properties in the Unity editor.public GameObject underworld;public GameObject objectToHide;// Occurs when this object starts colliding with another objectvoid OnCollisionEnter(Collision collision){// Hide the stage and show the underworld.
objectToHide.SetActive(false);
underworld.SetActive(true);// Disable Spatial Mapping to let the spheres enter the underworld.SpatialMapping.Instance.SetMappingEnabled(false);}}
- In Unity, select the Target object.
- Two public properties are now visible on the Hit Target component and need to reference objects in our scene:
- Drag Underworld from the Hierarchy panel to the Underworld property on the Hit Target component.
- Drag Stage from the Hierarchy panel to the Object to Hide property on the Hit Target component.
- Export, build and deploy the app.
- Place the Origami Collection on the floor, and then use the Select gesture to make a sphere drop.
- When the sphere hits the target (blue fan), an explosion will occur. The collection will be hidden and a hole to the underworld will appear.
The end
And that's the end of this tutorial!
You learned:
- How to create a holographic app in Unity.
- How to make use of gaze, gesture, voice, sounds, and spatial mapping.
- How to build and deploy an app using Visual Studio.
You are now ready to start creating your own holographic apps!
【Holograms 101D】一步步用Unity 开发 Hologram的更多相关文章
- 微软Hololens学院教程- Holograms 100: Getting Started with Unity【微软教程已经更新,本文是老版本】
这是老版本的教程,为了不耽误大家的时间,请直接看原文,本文仅供参考哦!原文链接:https://developer.microsoft.com/EN-US/WINDOWS/HOLOGRAPHIC/ho ...
- Unity开发概览(HoloLens开发系列)
本文翻译自:Unity development overview 要开始使用Unity创建全息应用,点此安装包含Unity HoloLens技术预览的开发工具.Unity HoloLens技术预览基于 ...
- Vuforia unity开发摄像头问题
Vuforia unity开发摄像头问题 项目一直在赶进度,写博的时间越来越少了~从事Unity开发也快两个月了,AR方向~ 使用的是高通家的SDK Vuforia...从工程融合一直到对unity和 ...
- HoloLens开发手记 - Unity development overview 使用Unity开发概述
Unity Technical Preview for HoloLens最新发行版为:Beta 24,发布于 09/07/2016 开始使用Unity开发HoloLens应用之前,确保你已经安装好了必 ...
- 【使用Unity开发Windows Phone上的2D游戏】(1)千里之行始于足下
写在前面的 其实这个名字起得不太欠当,Unity本身是很强大的工具,可以部署到很多个平台,而不仅仅是可以开发Windows Phone上的游戏. 只不过本人是Windows Phone 应用开发出身, ...
- Unity开发Android应用程序:调用安卓应用程序功能
开发环境: Eclipse3.4 + adt12 + jdk6 + AndroidSDK2.2 Unity3.4 + windows7 测试设备: HTC Desire HD 本文要涉及到的几个重点问 ...
- 使用Unity开发HoloLens应用
https://developer.microsoft.com/en-us/windows/holographic/install_the_tools 导读:开发者们在陆续收到HoloLens开发者版 ...
- [Unity]Unity开发NGUI代码实现ScrollView(放大视图)
Unity开发NGUI代码实现ScrollView(放大视图) 下载NGUI包 导入NGUI3.9.1版本package 创建MainCameraScript.cs脚本 MainCameraScrip ...
- [Unity]Unity开发NGUI代码实现ScrollView(滚动视图)
Unity开发NGUI代码实现ScrollView(滚动视图) 下载NGUI包 导入NGUI3.9.1版本package 链接: http://pan.baidu.com/s/1mgksPBU 密码: ...
随机推荐
- win10下安装Django
Django的核心(1.4+)可以运行在从2.5到2.7之间的任何Python版本. 我的电脑是操作系统是window10 ,内存是4G. 1.下载django 官网地址:https://www.dj ...
- 5-jQuery - AJAX get()/post()页面请求即执行
get 前台页面 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> &l ...
- C socket指南
1.介绍 Socket 编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的程序,但是为你在调用 connect() 前的bind() 的结构而不知所措? ...
- aws部署从无到有(二)windows管理aws
1 AMI正常启动后会进入下面页面 2 远程链接点击如何连接至您的 Linux 实例进入下载页 Windows下使用 PuTTY连接到 Linux 实例 http://www.chiark.green ...
- java 导出excel(复杂案例)
import java.io.FileOutputStream;import java.io.IOException; import org.apache.poi.hssf.usermodel.HSS ...
- mysql字段更改操作命令
1) 加索引 mysql> alter table 表名 add index 索引名 (字段名1[,字段名2 …]); 例子: mysql> alter table employee ...
- python读取CSV文件
python中有一个读写csv文件的包,直接import csv即可.利用这个python包可以很方便对csv文件进行操作,一些简单的用法如下. 1. 读文件 csv_reader = csv.rea ...
- FZU 2086 餐厅点餐
好久不写博客了……得有快一个月了……看到大神们一篇篇博文 唉……差好多……这一个月 有蓝桥杯还有校赛……校赛签到题都没签完 实力铁牌……不过蓝桥杯一等奖 五月份帝都之行还挺令人期待……清明小长假之前 ...
- Java comparable 和 comparator
一.comparator 接口继承 public class ComparatorTest { /** * @param args */ public static void main(String[ ...
- 小米2s刷机
每次系统内存不足,卡的不行就恨不得马上换新手机,发现手机也没有什么大的毛病,也没有其他苛刻的要求. 换个新系统继续使用吧,除了屏幕小了一点,将就了吧.物尽其责,坚决抵制过度消费. 小米手机2s 16G ...