123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.InputSystem;
- /* * WalkDogs 场景挂载在2D Player上
- * SoundGameController.cs
- * Author: 2023-10-12
- * Description: 音乐游戏控制器
- * 1. 读取音轨数据
- * 2. 创建音符
- * 3. 检测音符点击
- */
- public class SoundGameController : MonoBehaviour
- {
- SoundTrackManager soundTrackManager = new();
- GameObject notePrefabSwipe, notePrefabTap;
- GameObject Leaves;
- float gameStartTime;
- float GameEndTime;
- // 游戏得分统计
- int score, combo, maxCombo, NGCombo, perfectCount, goodCount, poorCount, missCount, totalCount;
- // 游戏数据
- string currentDogState = "walking"; // 是否有狗在跑
- // TapOrSwipe 触控检测
- Vector2 pressDownPosition = new Vector2(0, 0);
- Vector2 pressUpPosition = new Vector2(0, 0);
- float pressDownTime = 0f;
- float pressUpTime = 0f;
- // Start is called once before the first execution of Update after the MonoBehaviour is created
- void Start()
- {
- TextAsset soundTrackJson = Resources.Load<TextAsset>("WalkDogs/SoundTrack/track_1");
- if (soundTrackJson != null)
- {
- string soundTrackString = soundTrackJson.text;
- soundTrackManager.ImportFromJson(soundTrackString);
- soundTrackManager.GenRandomActions();
- // soundTrackManager.speed = 4;
- }
- notePrefabSwipe = Resources.Load<GameObject>("WalkDogs/Note/NoteSwipe");
- notePrefabTap = Resources.Load<GameObject>("WalkDogs/Note/NoteTap");
- StartCoroutine(PlaySoundGame());
- StartCoroutine(DogComponentInstaller());
- Leaves = GameObject.Find("Leaves_orange");
- StartCoroutine(DogMovementController());
- }
- // Update is called once per frame
- void Update()
- {
- DogStatusUpdate();
- UpdateAndShowScoreUI();
- }
- IEnumerator DogComponentInstaller()
- {
- yield return null;
- // 找到所有标签为 "dog" 的 GameObject
- GameObject[] dogObjects = GameObject.FindGameObjectsWithTag("dog");
- foreach (GameObject dog in dogObjects)
- {
- // 加载指定的Animator controller
- Animator animator = dog.GetComponent<Animator>();
- DogProperty dogProperty = new DogProperty();
- foreach (var dogProp in UserProperty.dogs)
- {
- if (dogProp.dog_name == dog.name)
- {
- dogProperty = dogProp;
- break;
- }
- }
- RuntimeAnimatorController animatorController = Resources.Load<RuntimeAnimatorController>("WalkDogs/Animation/shibaInu");
- if (dogProperty.breed == "shibaInu")
- {
- animatorController = Resources.Load<RuntimeAnimatorController>("WalkDogs/Animation/shibaInu");
- }
- animator.runtimeAnimatorController = animatorController;
- // 加载Rigidbody
- Rigidbody rigidbody = dog.AddComponent<Rigidbody>();
- //rigidbody.isKinematic = true;
- rigidbody.mass = 10;
- rigidbody.linearDamping = 10;
- rigidbody.angularDamping = 10;
- //rigidbody.freezeRotation = true;
- rigidbody.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezeRotation;
- rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
- rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
- // 加载box collider
- BoxCollider boxCollider = dog.AddComponent<BoxCollider>();
- boxCollider.isTrigger = false;
- boxCollider.center = new Vector3(0, 0.25f, 0);
- boxCollider.size = new Vector3(0.2f, 0.5f, 0.6f);
- }
- }
- IEnumerator PlaySoundGame()
- {
- // 加载背景
- List<string> backgroundList = new List<string>
- {
- "WalkDogs/Background/bg_1",
- "WalkDogs/Background/bg_2",
- "WalkDogs/Background/bg_3",
- "WalkDogs/Background/bg_4",
- };
- var Background = GameObject.Find("Background");
- MeshRenderer backgroundMeshRenderer = Background.GetComponent<MeshRenderer>();
- float lastBackgroundTime;
- // 加载音乐
- AudioClip audioClip = Resources.Load<AudioClip>(soundTrackManager.soundTrack);
- AudioSource audioSource = gameObject.AddComponent<AudioSource>();
- audioSource.clip = audioClip;
- yield return new WaitForSeconds(2f); // 等待音频加载完成
- audioSource.Play();
- gameStartTime = Time.time;
- GameEndTime = gameStartTime + soundTrackManager.length;
- lastBackgroundTime = gameStartTime;
- while (Time.time < GameEndTime)
- {
- // 每隔15秒切换一次背景
- if (Time.time - lastBackgroundTime > 15f)
- {
- lastBackgroundTime = Time.time;
- int randomIndex = UnityEngine.Random.Range(0, backgroundList.Count);
- string backgroundPath = backgroundList[randomIndex];
- Material myMaterial = Resources.Load<Material>(backgroundPath);
- if (myMaterial != null)
- {
- backgroundMeshRenderer.material = myMaterial;
- // Debug.Log("Background changed to: " + backgroundPath);
- }
- else
- {
- Debug.LogWarning("Background material not found: " + backgroundPath);
- }
- }
- // 用于提前n秒创建音符
- foreach (var note in soundTrackManager.soundAction)
- {
- if (!note.isActive && Time.time >= (gameStartTime + note.time - GameData.noteStartLeadTime))
- {
- note.isActive = true;
- CreateNote(note.time, note.action, soundTrackManager.soundAction.IndexOf(note).ToString());
- continue;
- }
- }
- // 检测音符是否超时未被点击
- foreach (var note in soundTrackManager.soundAction)
- {
- float TapTimeDeadline = note.time + gameStartTime + 0.35f; // 计算点击事件超时
- if (note.isActive && !note.isTapped && Time.time > TapTimeDeadline)
- {
- note.isTapped = true;
- missCount++;
- NGCombo++;
- combo = 0; // 重置连击
- // Debug.Log("Miss!" + Time.time + " Tap time deadline: " + TapTimeDeadline + " total miss:" + missCount);
- // Debug.Log("index of note:" + soundTrackManager.soundAction.IndexOf(note));
- break;
- }
- }
- // 检测游戏是否结束并统计分数
- totalCount = perfectCount + goodCount + poorCount + missCount;
- if (totalCount == soundTrackManager.soundAction.Count)
- {
- GameEndTime = Time.time;
- Debug.Log("Game Over!");
- Debug.Log($"Perfect: {perfectCount}, Good: {goodCount}, Poor: {poorCount}, Miss: {missCount}");
- Debug.Log($"Total Count: {totalCount}");
- Debug.Log($"Score: {score}");
- Debug.Log($"Combo: {combo}");
- Debug.Log($"Max Combo: {maxCombo}");
- // 结束游戏
- UpdateAndShowScoreUI();
- break; // 跳出 while 循环
- }
- // 当NGCombo大于5时,播放音效提示
- if (NGCombo > 5)
- {
- SoundGameEffectController.Instance.PlaySoundEffect(0);
- NGCombo = 0;
- }
- yield return new WaitForSeconds(0.01f);
- }
- yield return null;
- }
- private void CreateNote(float hitTime, string action, string noteName)
- {
- GameObject note;
- if (action == "tap")
- {
- note = Instantiate(notePrefabTap);
- // Debug.Log("Create Tap Note: " + noteName);
- // Debug.Log("Hit Time: " + hitTime + ", Action: " + action);
- // Debug.Log("Create Time: " + Time.time);
- }
- else
- {
- note = Instantiate(notePrefabSwipe);
- // Debug.Log("Create Tap Note: " + noteName);
- // Debug.Log("Hit Time: " + hitTime + ", Action: " + action);
- // Debug.Log("Create Time: " + Time.time);
- }
- note.gameObject.name = "note_" + noteName;
- NoteController noteController = note.GetComponent<NoteController>();
- noteController.speed = soundTrackManager.speed;
- noteController.hitTime = hitTime;
- noteController.action = action;
- }
- // 触控检测,检测通过按下和和抬起的触控点位置计算点击或者上下左右滑动
- public void TapOrSwipe(InputAction.CallbackContext context)
- {
- if (context.phase == InputActionPhase.Started)
- {
- pressDownPosition = Pointer.current.position.ReadValue();
- pressDownTime = Time.time;
- return;
- }
- if (context.phase == InputActionPhase.Canceled)
- {
- pressUpPosition = Pointer.current.position.ReadValue();
- pressUpTime = Time.time;
- float deltaX = pressUpPosition.x - pressDownPosition.x;
- float deltaY = pressUpPosition.y - pressDownPosition.y;
- float distance = Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY);
- // Debug.Log($"deltaX: {deltaX}, deltaY: {deltaY}, distance: {distance}");
- float timeDelta = pressUpTime - pressDownTime;
- string action;
- if (timeDelta > 0.2f)
- {
- return;
- }
- else
- {
- if (distance < 20f)
- {
- action = "tap";
- }
- else
- {
- if (Mathf.Abs(deltaX) > Mathf.Abs(deltaY))
- {
- if (deltaX > 0)
- {
- action = "right";
- }
- else
- {
- action = "left";
- }
- }
- else
- {
- if (deltaY > 0)
- {
- action = "up";
- }
- else
- {
- action = "down";
- }
- }
- }
- }
- TouchResponse touchResponse = new TouchResponse(action, pressUpTime);
- // Debug.Log($"TouchResponse: {touchResponse.action}, {touchResponse.time}");
- // 检测点击的音符
- ScoreCheck(touchResponse);
- }
- return;
- }
- private void ScoreCheck(TouchResponse touchResponse)
- {
- if (touchResponse != null)
- {
- foreach (var note in soundTrackManager.soundAction)
- {
- float TapTimeDelta = Mathf.Abs(touchResponse.time - (note.time + gameStartTime)); // 计算点击时间和音符时间的差值
- if (note.isActive && !note.isTapped && TapTimeDelta < 0.3f)
- {
- note.isTapped = true;
- if (touchResponse.action == note.action)
- {
- if (TapTimeDelta < 0.1f)
- {
- score += 100;
- combo++;
- if (combo > maxCombo)
- {
- maxCombo = combo;
- }
- perfectCount++;
- NGCombo = 0;
- // Debug.Log("Perfect!" + Time.time + " total perfect:" + perfectCount);
- string noteName = soundTrackManager.soundAction.IndexOf(note).ToString();
- DestroyNote(noteName);
- }
- else if (TapTimeDelta < 0.2f)
- {
- score += 30;
- combo = 0;
- goodCount++;
- NGCombo = 0;
- // Debug.Log("Good!" + Time.time + " total good:" + goodCount);
- string noteName = soundTrackManager.soundAction.IndexOf(note).ToString();
- DestroyNote(noteName);
- }
- else
- {
- score += 10;
- combo = 0;
- poorCount++;
- NGCombo++;
- // Debug.Log("Poor!" + Time.time + " total poor:" + poorCount);
- }
- }
- else
- {
- combo = 0;
- missCount++;
- NGCombo++;
- // Debug.Log("Wrong!" + Time.time + " total miss:" + missCount);
- }
- // Debug.Log("index of note:" + soundTrackManager.soundAction.IndexOf(note));
- break;
- }
- }
- }
- }
- private void DestroyNote(string noteName)
- {
- GameObject note = GameObject.Find("note_" + noteName);
- if (note != null)
- {
- Destroy(note);
- }
- else
- {
- Debug.Log("Note not found: " + noteName);
- }
- }
- // 设置狗的状态
- private void DogStatusUpdate()
- {
- GameObject[] dogObjects = GameObject.FindGameObjectsWithTag("dog");
- Debug.Log("combo:" + combo);
- // combo = 5; // 这里是为了测试用,实际应该从游戏逻辑中获取当前连击数
- if (combo >= 5 && combo < 10)
- {
- currentDogState = "running";
- foreach (GameObject dog in dogObjects)
- {
- Animator animator = dog.GetComponent<Animator>();
- if (animator != null)
- {
- animator.SetTrigger("run");
- SetLeavesParticleSpeed(5.0f, 10.0f); // 设置leaves粒子效果的Start Speed 和 Rate over Time
- // animator.Play("Run");
- }
- }
- }
- else if (combo >= 10)
- {
- currentDogState = "fastRunning";
- foreach (GameObject dog in dogObjects)
- {
- Animator animator = dog.GetComponent<Animator>();
- if (animator != null)
- {
- animator.SetTrigger("fastRun");
- SetLeavesParticleSpeed(10.0f, 20.0f); // 设置leaves粒子效果的Start Speed 和 Rate over Time
- // animator.Play("Fast Run");
- }
- }
- }
- else if (combo == 0)
- {
- if (currentDogState == "running" || currentDogState == "fastRunning")
- {
- currentDogState = "walking";
- foreach (GameObject dog in dogObjects)
- {
- Animator animator = dog.GetComponent<Animator>();
- if (animator != null)
- {
- // animator.Play("Walk");
- animator.SetTrigger("walk");
- SetLeavesParticleSpeed(2.0f, 5.0f); // 设置leaves粒子效果的Start Speed 和 Rate over Time
- }
- }
- }
- }
- }
- // 设置leaves粒子效果的Start Speed 和 Rate over Time
- public void SetLeavesParticleSpeed(float speed, float rate)
- {
- if (Leaves != null)
- {
- ParticleSystem particleSystem = Leaves.GetComponent<ParticleSystem>();
- if (particleSystem != null)
- {
- var main = particleSystem.main;
- main.startSpeed = speed;
- var emission = particleSystem.emission;
- emission.rateOverTime = rate;
- }
- else
- {
- Debug.LogWarning("ParticleSystem not found on Leaves object.");
- }
- }
- else
- {
- Debug.LogWarning("Leaves object not found.");
- }
- }
- // 协程控制场景里面所有的狗静止或者在x:-0.5到0.5之间, z:-6到-7之间随机移动
- IEnumerator DogMovementController()
- {
- while (true)
- {
- GameObject[] dogObjects = GameObject.FindGameObjectsWithTag("dog");
- foreach (GameObject dog in dogObjects)
- {
- // 让狗在x:-0.5到0.5之间, z:-6到-7之间随机移动
- float randomX = UnityEngine.Random.Range(-0.5f, 0.5f);
- float randomZ = UnityEngine.Random.Range(-7f, -6f);
- // dog.transform.Translate(new Vector3(randomX, -0.5f, randomZ) * Time.deltaTime);
- var position = new Vector3(randomX, dog.transform.position.y, randomZ);
- Debug.Log($"Dog {dog.name} moving to position: {position}");
- StartCoroutine(DogMoveToPosition(dog, position, 0.5f));
- }
- yield return new WaitForSeconds(5f); // 每5秒更新一次位置
- }
- }
- // 协程控制场景里面的狗按照指定速度移动到指定的位置
- IEnumerator DogMoveToPosition(GameObject dog, Vector3 targetPosition, float speed = 0.5f)
- {
- while (Vector3.Distance(dog.transform.position, targetPosition) > 0.1f)
- {
- dog.transform.position = Vector3.MoveTowards(dog.transform.position, targetPosition, speed * Time.deltaTime);
- yield return null;
- }
- }
- private void UpdateAndShowScoreUI()
- {
- // 更新分数显示逻辑
- // 这里可以添加代码来更新UI上的分数显示
- // 例如:scoreLabel.text = "Score: " + score;
- var UI = GameObject.Find("UI");
- var scorePanel = UI.transform.Find("ScorePanel").gameObject;
- scorePanel.SetActive(true);
- var walkDogsScoreController = scorePanel.transform.Find("UIDocument").GetComponent<WalkDogsScoreController>();
- walkDogsScoreController.score = score;
- walkDogsScoreController.maxCombo = maxCombo;
- walkDogsScoreController.perfect = perfectCount;
- walkDogsScoreController.good = goodCount;
- walkDogsScoreController.poor = poorCount;
- walkDogsScoreController.miss = missCount;
- }
- }
- public class TouchResponse
- {
- public string action = ""; // 触控动作 up, down, left, right, tap, none(表示无效)
- public float time;
- public TouchResponse(string action, float time)
- {
- this.action = action;
- this.time = time;
- }
- }
|