Unity安卓端震动与震屏效果实现指南

一、震动效果基础实现

Unity在安卓平台实现震动效果主要通过AndroidJavaClass调用系统原生API完成。核心原理是利用Android的Vibrator服务,该服务允许应用控制设备的震动马达。

1.1 基本震动实现

  1. using UnityEngine;
  2. public class AndroidVibration : MonoBehaviour
  3. {
  4. public static void Vibrate(long milliseconds)
  5. {
  6. #if UNITY_ANDROID && !UNITY_EDITOR
  7. AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  8. AndroidJavaObject context = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
  9. AndroidJavaObject vibrator = context.CallStatic<AndroidJavaObject>("getSystemService", "vibrator");
  10. if (vibrator != null)
  11. {
  12. vibrator.Call("vibrate", milliseconds);
  13. }
  14. #endif
  15. }
  16. }

关键点说明

  • 条件编译指令#if UNITY_ANDROID确保代码仅在安卓平台执行
  • 通过UnityPlayer获取当前Activity上下文
  • 调用getSystemService获取Vibrator实例
  • 震动时长参数单位为毫秒

1.2 权限配置

在Unity的Player Settings中需添加以下权限:

  1. <!-- AndroidManifest.xml配置示例 -->
  2. <uses-permission android:name="android.permission.VIBRATE"/>

注意事项

  • 现代安卓版本(API 26+)要求震动权限声明
  • 无需动态请求权限,系统级震动无需运行时权限

二、震屏效果实现方案

震屏效果通常通过修改Camera组件的transform实现,常见技术方案包括:

2.1 基础震屏实现

  1. using UnityEngine;
  2. public class ScreenShake : MonoBehaviour
  3. {
  4. public float shakeDuration = 0.5f;
  5. public float shakeMagnitude = 0.2f;
  6. private Vector3 originalPosition;
  7. private float shakeElapsedTime = 0f;
  8. void OnEnable()
  9. {
  10. originalPosition = transform.localPosition;
  11. }
  12. void Update()
  13. {
  14. if (shakeElapsedTime > 0)
  15. {
  16. shakeElapsedTime -= Time.deltaTime;
  17. float x = Random.Range(-1f, 1f) * shakeMagnitude;
  18. float y = Random.Range(-1f, 1f) * shakeMagnitude;
  19. transform.localPosition = originalPosition + new Vector3(x, y, 0);
  20. }
  21. else
  22. {
  23. transform.localPosition = originalPosition;
  24. this.enabled = false;
  25. }
  26. }
  27. public void StartShake()
  28. {
  29. shakeElapsedTime = shakeDuration;
  30. this.enabled = true;
  31. }
  32. }

优化建议

  • 使用对象池管理震屏实例
  • 添加缓动函数使震动更自然
  • 支持多轴震动(X/Y/Z轴独立控制)

2.2 高级震屏控制

  1. // 改进版支持多种震动模式
  2. public enum ShakePattern
  3. {
  4. Random,
  5. SineWave,
  6. SquareWave
  7. }
  8. public class AdvancedScreenShake : MonoBehaviour
  9. {
  10. public ShakePattern pattern;
  11. public float duration = 1f;
  12. public float magnitude = 0.5f;
  13. public float frequency = 10f;
  14. private float timer;
  15. private Vector3 originalPos;
  16. void OnEnable()
  17. {
  18. originalPos = transform.localPosition;
  19. timer = 0;
  20. }
  21. void Update()
  22. {
  23. timer += Time.deltaTime;
  24. float progress = timer / duration;
  25. if (progress >= 1)
  26. {
  27. transform.localPosition = originalPos;
  28. this.enabled = false;
  29. return;
  30. }
  31. float shake = 0;
  32. switch (pattern)
  33. {
  34. case ShakePattern.Random:
  35. shake = Random.Range(-1f, 1f);
  36. break;
  37. case ShakePattern.SineWave:
  38. shake = Mathf.Sin(progress * frequency * Mathf.PI * 2);
  39. break;
  40. case ShakePattern.SquareWave:
  41. shake = Mathf.Sign(Mathf.Sin(progress * frequency * Mathf.PI * 2));
  42. break;
  43. }
  44. transform.localPosition = originalPos +
  45. new Vector3(shake * magnitude, 0, 0);
  46. }
  47. }

模式对比
| 模式 | 特点 | 适用场景 |
|——————|———————————————-|————————————|
| Random | 完全随机震动 | 爆炸、碰撞等突发效果 |
| SineWave | 平滑正弦波动 | 持续环境震动 |
| SquareWave | 尖锐方波震动 | 机械装置运作效果 |

三、性能优化与最佳实践

3.1 震动系统优化

  1. 对象池管理

    1. public class VibrationPool : MonoBehaviour
    2. {
    3. public static VibrationPool Instance;
    4. public GameObject vibrationPrefab;
    5. private Stack<ScreenShake> pool = new Stack<ScreenShake>();
    6. void Awake()
    7. {
    8. Instance = this;
    9. for (int i = 0; i < 5; i++)
    10. {
    11. var obj = Instantiate(vibrationPrefab);
    12. obj.SetActive(false);
    13. pool.Push(obj.GetComponent<ScreenShake>());
    14. }
    15. }
    16. public ScreenShake GetVibration()
    17. {
    18. return pool.Count > 0 ? pool.Pop() : Instantiate(vibrationPrefab).GetComponent<ScreenShake>();
    19. }
    20. public void ReturnVibration(ScreenShake vibration)
    21. {
    22. vibration.gameObject.SetActive(false);
    23. pool.Push(vibration);
    24. }
    25. }
  2. 多线程处理

  • 使用AsyncTask处理复杂震动计算
  • 避免在Update中执行耗时操作

3.2 兼容性处理

  1. 设备差异处理

    1. public static bool HasVibrator()
    2. {
    3. #if UNITY_ANDROID && !UNITY_EDITOR
    4. AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    5. AndroidJavaObject context = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    6. AndroidJavaObject vibrator = context.CallStatic<AndroidJavaObject>("getSystemService", "vibrator");
    7. return vibrator != null && vibrator.Call<bool>("hasVibrator");
    8. #else
    9. return false;
    10. #endif
    11. }
  2. 版本适配

  • Android 10+需要检查VIBRATOR_MANAGER_SERVICE
  • 旧版本使用VIBRATOR_SERVICE

3.3 震动强度控制

  1. 动态强度调节

    1. public class DynamicVibration : MonoBehaviour
    2. {
    3. public AnimationCurve intensityCurve;
    4. public float baseDuration = 0.5f;
    5. public void TriggerVibration(float eventIntensity)
    6. {
    7. float duration = baseDuration * eventIntensity;
    8. float strength = intensityCurve.Evaluate(eventIntensity);
    9. // 实现具体震动逻辑
    10. }
    11. }
  2. 用户偏好设置

  • 提供震动强度滑块(0-100%)
  • 保存设置到PlayerPrefs

四、常见问题解决方案

4.1 震动无效问题排查

  1. 权限检查

    • 确认AndroidManifest.xml包含VIBRATE权限
    • 检查Player Settings的Minimum API Level(建议API 23+)
  2. 设备兼容性

    • 调用hasVibrator()检查设备支持
    • 测试不同品牌设备的震动表现差异

4.2 震屏卡顿优化

  1. LateUpdate替代

    1. void LateUpdate()
    2. {
    3. // 将震屏逻辑移到LateUpdate减少输入延迟
    4. }
  2. 简化计算

    • 使用预计算的震动模式表
    • 限制每帧的随机数生成次数

4.3 多摄像头处理

  1. public class MultiCamShake : MonoBehaviour
  2. {
  3. public Camera[] targetCameras;
  4. public float shakeAmount = 0.1f;
  5. private Vector3[] originalPositions;
  6. void Start()
  7. {
  8. originalPositions = new Vector3[targetCameras.Length];
  9. for (int i = 0; i < targetCameras.Length; i++)
  10. {
  11. originalPositions[i] = targetCameras[i].transform.localPosition;
  12. }
  13. }
  14. public void ShakeAll()
  15. {
  16. for (int i = 0; i < targetCameras.Length; i++)
  17. {
  18. float x = Random.Range(-1f, 1f) * shakeAmount;
  19. float y = Random.Range(-1f, 1f) * shakeAmount;
  20. targetCameras[i].transform.localPosition = originalPositions[i] + new Vector3(x, y, 0);
  21. }
  22. }
  23. }

五、进阶应用场景

5.1 节奏游戏震动

  1. public class RhythmVibration : MonoBehaviour
  2. {
  3. public AudioClip beatClip;
  4. public float beatInterval = 0.5f;
  5. private float nextBeatTime;
  6. void Start()
  7. {
  8. nextBeatTime = Time.time + beatInterval;
  9. }
  10. void Update()
  11. {
  12. if (Time.time >= nextBeatTime)
  13. {
  14. AndroidVibration.Vibrate(50); // 短促震动
  15. nextBeatTime += beatInterval;
  16. }
  17. }
  18. }

5.2 触觉反馈系统

  1. public class HapticFeedbackSystem : MonoBehaviour
  2. {
  3. public enum FeedbackType
  4. {
  5. LightTap,
  6. MediumTap,
  7. HeavyTap,
  8. Continuous
  9. }
  10. public static void Trigger(FeedbackType type)
  11. {
  12. long duration = 0;
  13. switch (type)
  14. {
  15. case FeedbackType.LightTap:
  16. duration = 20;
  17. break;
  18. case FeedbackType.MediumTap:
  19. duration = 50;
  20. break;
  21. case FeedbackType.HeavyTap:
  22. duration = 100;
  23. break;
  24. case FeedbackType.Continuous:
  25. duration = 300;
  26. break;
  27. }
  28. AndroidVibration.Vibrate(duration);
  29. }
  30. }

5.3 震动序列控制

  1. public class VibrationSequence : MonoBehaviour
  2. {
  3. public float[] pattern; // 例如 new float[]{50, 100, 50, 200}
  4. public void PlaySequence()
  5. {
  6. StartCoroutine(PlaySequenceCoroutine());
  7. }
  8. IEnumerator PlaySequenceCoroutine()
  9. {
  10. for (int i = 0; i < pattern.Length; i++)
  11. {
  12. if (i % 2 == 0) // 偶数索引为震动时长
  13. {
  14. AndroidVibration.Vibrate((long)pattern[i]);
  15. }
  16. yield return new WaitForSeconds(pattern[i] / 1000f); // 奇数索引为间隔
  17. }
  18. }
  19. }

六、总结与建议

  1. 分层实现策略

    • 基础层:封装Android原生震动
    • 表现层:实现各种震屏效果
    • 控制层:管理震动序列和强度
  2. 性能监控指标

    • 每秒震动调用次数(建议<30次)
    • 震屏对象的GC分配量
    • 主线程耗时占比
  3. 测试建议

    • 在不同安卓版本设备测试
    • 测试低电量模式下的表现
    • 测试后台运行时的行为

通过系统化的震动与震屏效果实现,可以显著提升游戏的沉浸感和操作反馈质量。建议开发者根据项目需求选择合适的实现方案,并持续优化性能表现。