拼图测试场景

This commit is contained in:
xinkl
2025-11-09 23:36:29 +08:00
parent 011c274bcf
commit 4ecd1d0e7e
22 changed files with 1398 additions and 117 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using A2W;
using Unity.Cinemachine;
using UnityEngine;
@@ -15,11 +16,10 @@ public class MusicGame : SceneSingleton<MusicGame>
public Vector3 judgeLine;
private List<GameObject> tickNote = new List<GameObject>();
double startDsp;
public int Sroce = 0;
void Start()
{
mainCamera = Camera.main;
}
void Update()
@@ -27,6 +27,11 @@ public class MusicGame : SceneSingleton<MusicGame>
// if (Keyboard.current.qKey.wasPressedThisFrame) Play();
}
public async Task openGameUI()
{
await UIManager.instance.ShowPanel<MusicGamePanel>();
}
public void Play()
{
mainCamera.transform.position = new Vector3(0, 100, -10);
@@ -93,11 +98,13 @@ public class MusicGame : SceneSingleton<MusicGame>
// ActivateTick(musicData.musicTicks[tickId]);
else
{
UIManager.instance.HidePanel<MusicGamePanel>();
gameObject.GetComponent<AudioSource>().Stop();
isPlaying = false;
tickId = 0;
noteId = 0;
mainCamera.GetComponent<CinemachineBrain>().enabled = true;
Debug.Log("完成所有tick");
Debug.Log($"完成所有tick,分数{Sroce}");
GameFlowMgr.instance.completeLevel(0);
}
}

View File

@@ -56,6 +56,7 @@ public class Note : MonoBehaviour
Debug.Log($"音符 {Uid}击中");
judged = true;
lastSpaceTime = double.NegativeInfinity;
MusicGame.instance.Sroce += 10;
MusicGame.instance.onNoteHit(Uid);
}
else

View File

@@ -12,8 +12,8 @@ public class PianoInteractable : MonoBehaviour, IInteractable
Debug.Log("OnExitInteractionRange");
}
public void OnInteract()
public async void OnInteract()
{
MusicGame.instance.Play();
await MusicGame.instance.openGameUI();
}
}

View File

@@ -0,0 +1,20 @@
using System.Threading.Tasks;
using A2W;
using UnityEngine;
public class SceneInit : MonoBehaviour
{
MessagePanel messagePanel;
async Task Init()
{
// messagePanel = await UIManager.instance.ShowPanel<MessagePanel>();
// messagePanel.AddMessage("寻找有关于音乐的物品");
// Debug.Log("寻找有关于音乐的物品");
}
async void Start()
{
messagePanel = await UIManager.instance.ShowPanel<MessagePanel>();
messagePanel.AddMessage("Search for items related to music");
Debug.Log("寻找有关于音乐的物品");
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 03f01a4a562213c419a7595dcf397006

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5ed5b94a8be4cdb4f9c5f81eab4a0a36
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,244 @@
// PuzzleManager.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class PuzzleManager : MonoBehaviour
{
[Header("拼图设置")]
public Texture2D puzzleImage; // 拼图原图
public int gridSize = 3; // 网格大小3x3
public float spacing = 5f; // 拼图块间距
[Header("UI引用")]
public RectTransform puzzleArea; // 拼图区域
public Transform piecesContainer; // 拼图块容器
public TMP_Text completedText; // 完成提示文本
private List<PuzzlePiece> pieces = new List<PuzzlePiece>();
private PuzzlePiece emptyPiece; // 空白拼图块
private Vector2 pieceSize; // 拼图块尺寸
void Start()
{
CreatePuzzle();
ShufflePieces();
}
// 创建拼图
void CreatePuzzle()
{
// 计算拼图块尺寸
float areaWidth = puzzleArea.rect.width;
float areaHeight = puzzleArea.rect.height;
pieceSize = new Vector2(areaWidth / gridSize, areaHeight / gridSize);
// 创建拼图块
for (int row = 0; row < gridSize; row++)
{
for (int col = 0; col < gridSize; col++)
{
// 跳过最后一个位置(作为空白)
if (row == gridSize - 1 && col == gridSize - 1)
{
CreateEmptyPiece(row, col);
continue;
}
// 创建拼图块GameObject
GameObject pieceObj = new GameObject($"Piece_{row}_{col}");
pieceObj.transform.SetParent(piecesContainer);
// 添加Image组件
Image img = pieceObj.AddComponent<Image>();
// 设置拼图块纹理
Sprite sprite = CreateSpriteForPiece(row, col);
img.sprite = sprite;
// 设置位置和大小
RectTransform rt = pieceObj.GetComponent<RectTransform>();
rt.sizeDelta = pieceSize - Vector2.one * spacing;
rt.anchoredPosition = GetPiecePosition(row, col);
// 添加拼图块组件
PuzzlePiece piece = pieceObj.AddComponent<PuzzlePiece>();
piece.Initialize(this, row, col);
pieces.Add(piece);
// 添加按钮组件用于点击
Button btn = pieceObj.AddComponent<Button>();
btn.onClick.AddListener(() => OnPieceClick(piece));
}
}
completedText.gameObject.SetActive(false);
}
// 创建空白拼图块
void CreateEmptyPiece(int row, int col)
{
GameObject emptyObj = new GameObject("EmptyPiece");
emptyObj.transform.SetParent(piecesContainer);
// 设置位置
RectTransform rt = emptyObj.AddComponent<RectTransform>();
rt.sizeDelta = pieceSize - Vector2.one * spacing;
rt.anchoredPosition = GetPiecePosition(row, col);
emptyPiece = emptyObj.AddComponent<PuzzlePiece>();
emptyPiece.Initialize(this, row, col);
emptyPiece.isEmpty = true;
}
// 创建拼图块的Sprite
Sprite CreateSpriteForPiece(int row, int col)
{
// 计算在原图中的位置
int texWidth = puzzleImage.width / gridSize;
int texHeight = puzzleImage.height / gridSize;
// 创建纹理
Texture2D pieceTex = new Texture2D(texWidth, texHeight);
Color[] pixels = puzzleImage.GetPixels(
col * texWidth,
(gridSize - 1 - row) * texHeight,
texWidth,
texHeight
);
pieceTex.SetPixels(pixels);
pieceTex.Apply();
return Sprite.Create(
pieceTex,
new Rect(0, 0, texWidth, texHeight),
new Vector2(0.5f, 0.5f)
);
}
// 获取拼图块位置
Vector2 GetPiecePosition(int row, int col)
{
float startX = -puzzleArea.rect.width / 2 + pieceSize.x / 2;
float startY = puzzleArea.rect.height / 2 - pieceSize.y / 2;
return new Vector2(
startX + col * pieceSize.x,
startY - row * pieceSize.y
);
}
// 打乱拼图
void ShufflePieces()
{
int shuffleCount = 100;
for (int i = 0; i < shuffleCount; i++)
{
var adjacentPieces = GetAdjacentPieces(emptyPiece);
if (adjacentPieces.Count > 0)
{
int randomIndex = Random.Range(0, adjacentPieces.Count);
var targetPiece = adjacentPieces[randomIndex];
// 只交换空白块与相邻块
SwapPieces(targetPiece, emptyPiece);
}
}
}
// 获取相邻的拼图块
List<PuzzlePiece> GetAdjacentPieces(PuzzlePiece piece)
{
List<PuzzlePiece> adjacent = new List<PuzzlePiece>();
Vector2[] directions = { Vector2.up, Vector2.down, Vector2.left, Vector2.right };
foreach (Vector2 dir in directions)
{
PuzzlePiece adjacentPiece = GetPieceAtPosition(
piece.currentRow + (int)dir.y,
piece.currentCol + (int)dir.x
);
if (adjacentPiece != null)
{
adjacent.Add(adjacentPiece);
}
}
return adjacent;
}
// 点击拼图块
public void OnPieceClick(PuzzlePiece piece)
{
if (IsAdjacentToEmpty(piece))
{
SwapPieces(piece, emptyPiece);
if (CheckPuzzleComplete())
{
completedText.gameObject.SetActive(true);
}
}
}
// 检查是否与空白块相邻
bool IsAdjacentToEmpty(PuzzlePiece piece)
{
int rowDiff = Mathf.Abs(piece.currentRow - emptyPiece.currentRow);
int colDiff = Mathf.Abs(piece.currentCol - emptyPiece.currentCol);
return (rowDiff == 1 && colDiff == 0) || (rowDiff == 0 && colDiff == 1);
}
// 交换两个拼图块
void SwapPieces(PuzzlePiece piece1, PuzzlePiece piece2)
{
// 交换位置
Vector2 tempPos = piece1.GetComponent<RectTransform>().anchoredPosition;
piece1.GetComponent<RectTransform>().anchoredPosition =
piece2.GetComponent<RectTransform>().anchoredPosition;
piece2.GetComponent<RectTransform>().anchoredPosition = tempPos;
// 交换行列信息
int tempRow = piece1.currentRow;
int tempCol = piece1.currentCol;
piece1.currentRow = piece2.currentRow;
piece1.currentCol = piece2.currentCol;
piece2.currentRow = tempRow;
piece2.currentCol = tempCol;
}
// 获取指定位置的拼图块
PuzzlePiece GetPieceAtPosition(int row, int col)
{
if (row < 0 || row >= gridSize || col < 0 || col >= gridSize)
return null;
foreach (PuzzlePiece piece in pieces)
{
if (piece.currentRow == row && piece.currentCol == col)
return piece;
}
return emptyPiece.currentRow == row && emptyPiece.currentCol == col ? emptyPiece : null;
}
// 检查拼图是否完成
bool CheckPuzzleComplete()
{
foreach (PuzzlePiece piece in pieces)
{
if (piece.currentRow != piece.correctRow || piece.currentCol != piece.correctCol)
return false;
}
return emptyPiece.currentRow == gridSize - 1 && emptyPiece.currentCol == gridSize - 1;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b8ae299b38a43194f8fc79c347b32d26

View File

@@ -0,0 +1,22 @@
// PuzzlePiece.cs
using UnityEngine;
public class PuzzlePiece : MonoBehaviour
{
[HideInInspector] public int correctRow; // 正确位置的行
[HideInInspector] public int correctCol; // 正确位置的列
[HideInInspector] public int currentRow; // 当前位置的行
[HideInInspector] public int currentCol; // 当前位置的列
[HideInInspector] public bool isEmpty; // 是否是空白块
private PuzzleManager puzzleManager;
public void Initialize(PuzzleManager manager, int row, int col)
{
puzzleManager = manager;
correctRow = row;
correctCol = col;
currentRow = row;
currentCol = col;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 01e544aac3c5cce42bc8ef6c375e9ad7

View File

@@ -0,0 +1,55 @@
using A2W;
using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class MusicGamePanel : UIPanel
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
public TMP_Text scoreText;
public TMP_Text tipText;
public TMP_Text tipText2;
public Button startButton;
public override UniTask Hide()
{
return UniTask.CompletedTask;
}
public override void Init()
{
tipText.gameObject.SetActive(true);
startButton.gameObject.SetActive(true);
}
public override UniTask Show()
{
return UniTask.CompletedTask;
}
void Start()
{
// startButton.onClick.AddListener(() =>
// {
// tipText.gameObject.SetActive(false);
// startButton.gameObject.SetActive(false);
// });
}
// Update is called once per frame
bool isStart = false;
void Update()
{
scoreText.text = MusicGame.instance.Sroce.ToString();
if (Keyboard.current.spaceKey.wasPressedThisFrame && !isStart)
{
isStart = true;
tipText.gameObject.SetActive(false);
tipText2.gameObject.SetActive(false);
MusicGame.instance.Play();
startButton.gameObject.SetActive(false);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f7eee0888c08622498d86d24e7e99efd