using Newtonsoft.Json; using NUnit.Framework; using System; using System.Collections.Generic; using System.Net.Sockets; using UnityEngine; using UnityEngine.InputSystem; /* 本文件用于控制手势的采集和比对 * 也包含导出和导入手势的功能 */ public class GestureManager { // Start is called once before the first execution of Update after the MonoBehaviour is created public List gesturePointOffsetList { set; get; } = new List(); public int sampleRate { set; get; } = 10; // 采样率 private Vector2 prePointLoc = new Vector2(0, 0); // 第一个点 private Vector2 curPointLoc = new Vector2(0, 0); // 第二个点 private float timer = 0f; public bool isRecording; private float interval; private float lengthTorrence = 0.25f; // 允许的长度误差 public GestureManager() { interval = (float)1 / sampleRate; } public string ExportToJson() { string json = string.Empty; if (gesturePointOffsetList.Count / 2 <= sampleRate) { return json; } json = JsonConvert.SerializeObject(this); return json; } public void ImportFromJson(string json) { this.isRecording = false; var data = JsonConvert.DeserializeObject>(json); this.sampleRate = int.Parse(data["sampleRate"].ToString()); gesturePointOffsetList.Clear(); GesturePointOffset[] pointOffsets = JsonConvert.DeserializeObject(data["gesturePointOffsetList"].ToString()); foreach (var point in pointOffsets) { gesturePointOffsetList.Add(point); } } // 添加一个运动轨迹 public void Record() { Vector2 pointLoc = Pointer.current.position.ReadValue(); if (isRecording) { if (gesturePointOffsetList.Count == 0) { prePointLoc = pointLoc; curPointLoc = pointLoc; GesturePointOffset gesturePointMovement = new GesturePointOffset(0, 0); gesturePointOffsetList.Add(gesturePointMovement); return; } else { //Debug.Log("interval:" + interval.ToString()); timer += Time.deltaTime; if (timer >= interval) { timer = 0f; curPointLoc = pointLoc; float distance = Vector2.Distance(prePointLoc, curPointLoc); float angle = Vector2.Angle(prePointLoc, curPointLoc); GesturePointOffset gesturePointMovement = new GesturePointOffset(distance, angle); if (distance * angle != 0) { gesturePointOffsetList.Add(gesturePointMovement); Debug.Log("log time:" + DateTime.Now.ToString()); } prePointLoc = curPointLoc; } } } } public float CompareGesture(GestureManager anotherGesture) { float score = 0f; if (this.sampleRate != anotherGesture.sampleRate) { Debug.Log("Sample rate not match"); return -1f; } int maxGesturePoints = Mathf.Max(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count); int minGesturePoints = Mathf.Min(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count); for (int i = 0; i < minGesturePoints; i++) { float distanceMin = Mathf.Min(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance); float distanceMax = Mathf.Max(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance); float angleMin = Mathf.Min(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle); float angleMax = Mathf.Max(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle); float distanceScore = 0f; if (distanceMin == 0) { distanceScore = 1f; } else { distanceScore = distanceMin / distanceMax; } float angleDitance1 = angleMax - angleMin; float angleDitance2 = 360 - angleDitance1; float angleScore = 1 - (Mathf.Min(angleDitance1, angleDitance2) / 180); score = score * (i / (i + 1f)) + (distanceScore + angleScore) / 2 * (1f / (i + 1)); } // 如果长度超过公差范围,就要考虑调整score if ((maxGesturePoints / minGesturePoints) > (1f+ lengthTorrence)) { int deltaGesturePoints = Mathf.RoundToInt(maxGesturePoints - minGesturePoints * (1f + lengthTorrence)); score = score * (minGesturePoints / (minGesturePoints + deltaGesturePoints)); } return score; } public void ResetGesture() { this.gesturePointOffsetList.Clear(); } }