375 lines
12 KiB
C#
375 lines
12 KiB
C#
using UnityEngine;
|
|
using Yarn.Unity;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections;
|
|
using AibisDream;
|
|
using System.Linq;
|
|
using DG.Tweening;
|
|
[System.Serializable]
|
|
public class LineSegmentInfo
|
|
{
|
|
public string Name;
|
|
public Transform StartTransform;
|
|
public Transform EndTransform;
|
|
}
|
|
public class LineManager : MonoBehaviour
|
|
{
|
|
public InteractiveLineSegment interactiveLineSegmentPrefab; // InteractiveLineSegment 的预制体
|
|
[SerializeField]
|
|
private List<LineSegmentInfo> lineSegmentInfos; // 线段信息的列表
|
|
|
|
// 线段字典,用于快速查找
|
|
|
|
public GameObject physicLineSegmentPrefab;
|
|
|
|
public CustomCursor customCursor; // 自定义光标,你可以在 Inspector 中设置
|
|
|
|
private bool isScissorsMode;
|
|
|
|
public bool IsScissorsMode
|
|
{
|
|
get
|
|
{
|
|
return isScissorsMode;
|
|
}
|
|
set
|
|
{
|
|
isScissorsMode = value;
|
|
|
|
if (isScissorsMode)
|
|
{
|
|
SetScissorsCursor();
|
|
}
|
|
else
|
|
{
|
|
ResetCursor();
|
|
}
|
|
}
|
|
}
|
|
private Dictionary<string, InteractiveLineSegment> lineSegmentDictionary = new Dictionary<string, InteractiveLineSegment>();
|
|
|
|
public IEnumerable<string> GetLineSegmentNames()
|
|
{
|
|
return lineSegmentDictionary.Keys;
|
|
}
|
|
private InteractiveLineSegment currentLineSegment; // 当前要被剪断的线段
|
|
|
|
private const float LONG_PRESS_THRESHOLD = 0.01f; // 长按阈值,可以根据需要调整
|
|
private float longPressTime = 0.0f; // 长按时间
|
|
private float detectionRadius=0.25f;
|
|
|
|
private void SaveCutLine(string lineName)
|
|
{
|
|
PlayerPrefs.SetString(lineName, "cut");
|
|
PlayerPrefs.Save();
|
|
}
|
|
|
|
private bool IsLineCut(string lineName)
|
|
{
|
|
return PlayerPrefs.HasKey(lineName);
|
|
}
|
|
|
|
public void CutLine(InteractiveLineSegment originalLineSegment, Vector3 splitPoint)
|
|
{
|
|
// 如果线段不可剪断,就直接返回,不进行剪断操作
|
|
if (!originalLineSegment.IsCuttable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Create the first new line segment
|
|
GameObject firstLineSegmentObject = Instantiate(physicLineSegmentPrefab, transform);
|
|
PhysicLineSegment firstLineSegment = firstLineSegmentObject.GetComponent<PhysicLineSegment>();
|
|
firstLineSegment.Initialize(originalLineSegment.StartTransform.position, splitPoint);
|
|
firstLineSegment.lineRenderer.startColor=originalLineSegment.lineRenderer.startColor;
|
|
firstLineSegment.lineRenderer.endColor=originalLineSegment.lineRenderer.endColor;
|
|
|
|
// Create the second new line segment
|
|
GameObject secondLineSegmentObject = Instantiate(physicLineSegmentPrefab, transform);
|
|
PhysicLineSegment secondLineSegment = secondLineSegmentObject.GetComponent<PhysicLineSegment>();
|
|
secondLineSegment.Initialize(originalLineSegment.EndTransform.position,splitPoint);
|
|
secondLineSegment.lineRenderer.startColor=originalLineSegment.lineRenderer.startColor;
|
|
secondLineSegment.lineRenderer.endColor=originalLineSegment.lineRenderer.endColor;
|
|
// Immediately destroy the original line segment
|
|
Destroy(originalLineSegment.gameObject);
|
|
Debug.Log("线销毁了");
|
|
StartCoroutine(ScreenEffectManager.Instance.FlashRed(0.3f));
|
|
StartCoroutine(ScreenEffectManager.Instance.ShakeScreen());
|
|
SaveCutLine(originalLineSegment.name);
|
|
|
|
// Start the coroutine to destroy the new line segments after fade in and out
|
|
StartCoroutine(DestroyNewSegmentsAfterFade(firstLineSegmentObject, secondLineSegmentObject,originalLineSegment));
|
|
}
|
|
|
|
private IEnumerator DestroyNewSegmentsAfterFade(GameObject firstLineSegmentObject, GameObject secondLineSegmentObject,InteractiveLineSegment originalLineSegment)
|
|
{
|
|
yield return new WaitForSeconds(1.5f);
|
|
|
|
yield return StartCoroutine(ScreenEffectManager.Instance.FadeIn(1));
|
|
Destroy(firstLineSegmentObject);
|
|
Destroy(secondLineSegmentObject);
|
|
yield return StartCoroutine(ScreenEffectManager.Instance.FadeOut(1));
|
|
originalLineSegment.Option.SelectOption();
|
|
}
|
|
|
|
|
|
|
|
private void AddPhysicsComponents(GameObject lineSegmentObject)
|
|
{
|
|
// Add Rigidbody2D
|
|
Rigidbody2D rb = lineSegmentObject.AddComponent<Rigidbody2D>();
|
|
rb.gravityScale = 1; // Enable gravity
|
|
|
|
// Add HingeJoint2D
|
|
HingeJoint2D hinge = lineSegmentObject.AddComponent<HingeJoint2D>();
|
|
hinge.anchor = Vector2.zero; // Set the anchor at one end of the line segment
|
|
}
|
|
public void BindOptionToLineSegment(string lineSegmentName, YarnOption option)
|
|
{
|
|
InteractiveLineSegment lineSegment = GetLineSegmentByName(lineSegmentName);
|
|
if (lineSegment != null)
|
|
{
|
|
if (option != null)
|
|
{
|
|
lineSegment.Option = option;
|
|
Debug.Log("Binded option to " + lineSegmentName);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Option is null for " + lineSegmentName);
|
|
}
|
|
}
|
|
}
|
|
private void EnterLineSegment(InteractiveLineSegment lineSegment)
|
|
{
|
|
if (currentLineSegment != null)
|
|
{
|
|
lineSegment.OnHoverExit();
|
|
}
|
|
lineSegment.OnHover();
|
|
currentLineSegment = lineSegment;
|
|
}
|
|
private void LongPressLineSegment(InteractiveLineSegment lineSegment)
|
|
{
|
|
if(!lineSegment.IsCuttable)
|
|
{
|
|
lineSegment.Option.SelectOption();
|
|
return;
|
|
}
|
|
longPressTime += Time.deltaTime;
|
|
Vector3 midpoint = (lineSegment.StartPoint + lineSegment.EndPoint) / 2;
|
|
|
|
float distance = Vector3.Distance(midpoint, lineSegment.StartPoint);
|
|
|
|
// Make the scissors shake and the line segment turn red
|
|
if (longPressTime < LONG_PRESS_THRESHOLD)
|
|
{
|
|
customCursor.Shake(longPressTime * 5.0f, 10.0f); // 抖动强度随时间增加
|
|
float progress = longPressTime / LONG_PRESS_THRESHOLD;
|
|
// Calculate the new position of the color gradient
|
|
float newPosition = progress * distance;
|
|
}
|
|
else
|
|
{
|
|
// Cut the line segment
|
|
CutLine(lineSegment,midpoint);
|
|
IsScissorsMode=false;
|
|
Debug.Log("线剪断触发了");
|
|
}
|
|
}
|
|
private void ExitLineSegment()
|
|
{
|
|
if (currentLineSegment != null)
|
|
{
|
|
currentLineSegment.OnHoverExit();
|
|
}
|
|
currentLineSegment = null;
|
|
}
|
|
private void Update()
|
|
{
|
|
if (isScissorsMode)
|
|
{
|
|
// Get the position of the mouse in world coordinates
|
|
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
|
|
|
// Check if there is a line segment in the scissors' detection range
|
|
Collider2D hitCollider = Physics2D.OverlapCircle(mousePosition, detectionRadius);
|
|
InteractiveLineSegment hitLineSegment = hitCollider != null ? hitCollider.GetComponent<InteractiveLineSegment>() : null;
|
|
if (hitLineSegment != null)
|
|
{
|
|
EnterLineSegment(hitLineSegment);
|
|
|
|
if (Input.GetMouseButtonDown(0))
|
|
{
|
|
longPressTime = 0.0f;
|
|
}
|
|
else if (Input.GetMouseButton(0))
|
|
{
|
|
LongPressLineSegment(hitLineSegment);
|
|
}
|
|
else if (Input.GetMouseButtonUp(0))
|
|
{
|
|
longPressTime = 0.0f;
|
|
//customCursor.ResetRotation(); // 假设你有一个方法来重置剪刀的旋转
|
|
//currentLineSegment.ResetColor(); // 假设你有一个方法来重置线段的颜色
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExitLineSegment();
|
|
}
|
|
}
|
|
}
|
|
private void SetScissorsCursor()
|
|
{
|
|
// 启用自定义光标
|
|
customCursor.gameObject.SetActive(true);
|
|
}
|
|
|
|
private void ResetCursor()
|
|
{
|
|
// 禁用自定义光标
|
|
customCursor.gameObject.SetActive(false);
|
|
}
|
|
|
|
|
|
[YarnCommand("reconnected_line")]
|
|
public void Reconnected(string input)
|
|
{
|
|
// Use GetLineSegmentName method to find the recognized name
|
|
string recognizedName = GetLineSegmentName(input);
|
|
|
|
if (recognizedName == null)
|
|
{
|
|
Debug.LogError("Invalid LineSegmentInfo name: " + input);
|
|
return;
|
|
}
|
|
|
|
// Find the LineSegmentInfo with the recognized name
|
|
LineSegmentInfo lineSegmentInfo = lineSegmentInfos.Find(info => info.Name == recognizedName);
|
|
|
|
if (lineSegmentInfo == null)
|
|
{
|
|
Debug.LogError("Invalid LineSegmentInfo name: " + recognizedName);
|
|
return;
|
|
}
|
|
// If the line is already cut, skip it
|
|
// if (!IsLineCut(lineSegmentInfo.Name))
|
|
// {
|
|
// return;
|
|
// }
|
|
// Instantiate a new line segment with the given info
|
|
InteractiveLineSegment newSegment = Instantiate(interactiveLineSegmentPrefab, transform);
|
|
newSegment.StartTransform = lineSegmentInfo.StartTransform;
|
|
newSegment.EndTransform = lineSegmentInfo.EndTransform;
|
|
newSegment.Initialize();
|
|
}
|
|
[YarnCommand("delete_line")]
|
|
public void DeleteLine(string input)
|
|
{
|
|
// Use GetLineSegmentName method to find the recognized name
|
|
string recognizedName = GetLineSegmentName(input);
|
|
|
|
if (recognizedName == null)
|
|
{
|
|
Debug.LogError("Invalid LineSegmentInfo name: " + input);
|
|
return;
|
|
}
|
|
|
|
if (lineSegmentDictionary.ContainsKey(recognizedName))
|
|
{
|
|
InteractiveLineSegment lineSegmentToRemove = lineSegmentDictionary[recognizedName];
|
|
//lineSegmentDictionary.Remove(recognizedName);
|
|
|
|
// Destroy the line segment GameObject
|
|
Destroy(lineSegmentToRemove.gameObject);
|
|
|
|
Debug.Log("Line segment removed: " + recognizedName);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Line segment not found in dictionary: " + recognizedName);
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
foreach (LineSegmentInfo lineSegmentInfo in lineSegmentInfos)
|
|
{
|
|
if (IsLineCut(lineSegmentInfo.Name))
|
|
{
|
|
continue;
|
|
}
|
|
InteractiveLineSegment newSegment = Instantiate(interactiveLineSegmentPrefab, transform);
|
|
newSegment.StartTransform = lineSegmentInfo.StartTransform;
|
|
newSegment.EndTransform = lineSegmentInfo.EndTransform;
|
|
newSegment.Initialize();
|
|
lineSegmentDictionary.Add(lineSegmentInfo.Name, newSegment);
|
|
}
|
|
|
|
}
|
|
|
|
public InteractiveLineSegment GetLineSegmentByName(string lineSegmentName)
|
|
{
|
|
if (lineSegmentDictionary.TryGetValue(lineSegmentName, out InteractiveLineSegment lineSegment))
|
|
{
|
|
return lineSegment;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Invalid line segment name: " + lineSegmentName);
|
|
return null;
|
|
}
|
|
}
|
|
public string GetLineSegmentName(string input)
|
|
{
|
|
// 转换为小写并移除所有的下划线
|
|
string[] inputWords = input.ToLower().Split('_');
|
|
|
|
foreach (var lineSegmentName in lineSegmentDictionary.Keys)
|
|
{
|
|
// 转换为小写并移除所有的下划线
|
|
string[] lineSegmentWords = lineSegmentName.ToLower().Split('_');
|
|
|
|
// 检查是否包含相同的单词
|
|
if (inputWords.All(word => lineSegmentWords.Contains(word)) && lineSegmentWords.All(word => inputWords.Contains(word)))
|
|
{
|
|
return lineSegmentName;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
// Yarn 命令,设置线段的可剪断性
|
|
[YarnCommand("set_line_cuttable")]
|
|
public void SetLineCuttable(string lineSegmentName, bool isCuttable)
|
|
{
|
|
string recognizedName = GetLineSegmentName(lineSegmentName);
|
|
if (recognizedName != null)
|
|
{
|
|
InteractiveLineSegment lineSegment = GetLineSegmentByName(recognizedName);
|
|
if (lineSegment != null)
|
|
{
|
|
lineSegment.IsCuttable = isCuttable;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("Invalid line segment name: " + lineSegmentName);
|
|
}
|
|
}
|
|
// Yarn 命令,设置剪刀模式
|
|
[YarnCommand("set_scissors_mode")]
|
|
public void SetScissorsMode(bool isEnabled)
|
|
{
|
|
IsScissorsMode = isEnabled;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|