跳到窗口内容

文档 / 2025GMTK

文档

2025GMTK

2025年GMTKGameJam的开发记录

建立 2025-08-10 大小 6.3 KB 分类 GameJam

目录

尝试制作了一些音效,感觉还是挺好玩的,可以积累一些自己的音效库以备不时之需

用射线检测制作了3D卡牌效果,感觉有潜力做成一个有意思的交互(无缝3D交互),逻辑:发射RAY检测物体层级并且是否带xx组件,如果是则执行对应点击反应

private void Update()
{
    Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
    if (Physics.Raycast(ray, out RaycastHit hit, 100f))
    {
        // ====== 按钮悬浮 ======
        var btn = hit.collider.GetComponent<BuyButton3D>();
        if (btn != null)
        {
            if (btn != lastHoveredButton)
            {
                lastHoveredButton?.OnHoverExit();
                btn.OnHovered();
                lastHoveredButton = btn;
            }

            // 离开卡片
            lastHoveredCard?.OnHoverExit();
            lastHoveredCard = null;
            return;
        }

        // ====== 卡片悬浮 ======
        var card = hit.collider.GetComponent<WorldShopItem>();
        if (card != null)
        {
            if (card != lastHoveredCard)
            {
                lastHoveredCard?.OnHoverExit();
                card.OnHovered();
                lastHoveredCard = card;
            }

            // 离开按钮
            lastHoveredButton?.OnHoverExit();
            lastHoveredButton = null;
            return;
        }
    }

    // ====== 没有悬浮任何物体 ======
    lastHoveredButton?.OnHoverExit();
    lastHoveredCard?.OnHoverExit();
    lastHoveredButton = null;
    lastHoveredCard = null;

    if (shopOpen && Keyboard.current.anyKey.wasPressedThisFrame)
    {
        // 检查是否是鼠标左键点击(不要误触)
        if (Mouse.current.leftButton.wasPressedThisFrame) return;

        // 关闭商店
        CloseShop();
    }

}

private void OnClick(InputAction.CallbackContext ctx)
{
    Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
    if (Physics.Raycast(ray, out RaycastHit hit, 100f))
    {
        // 点击了购买按钮
        var buyBtn = hit.collider.GetComponent<BuyButton3D>();
        if (buyBtn != null)
        {
            buyBtn.OnClicked();
            return;
        }

        // 点击了卡牌本体
        if (((1 << hit.collider.gameObject.layer) & cardLayer) != 0)
        {
            var card = hit.collider.GetComponent<WorldShopItem>();
            card?.OnClicked();
            return;
        }

        // 点击了打开商店的物体
        if (!shopOpen &&
            ((1 << hit.collider.gameObject.layer) & shopTriggerLayer) != 0 &&
            !hit.collider.gameObject.name.Contains("Mask"))
        {
            OpenShop();
            return;
        }

    }

    // 点击空地则关闭
    if (shopOpen)
    {
        CloseShop();
    }
}

Unity免费插件Tween制作动效还挺方便,好像没比DoTween差多少

TMP字体抖动效果直接用了Updata去控制mesh偏移,下次可以试试K2S安利的插件

public IEnumerator ApplyJitterToText(TMP_Text targetText)
{
    targetText.ForceMeshUpdate();
    TMP_TextInfo textInfo = targetText.textInfo;

    while (true)
    {
        targetText.ForceMeshUpdate();

        for (int i = 0; i < textInfo.characterCount; i++)
        {
            TMP_CharacterInfo charInfo = textInfo.characterInfo[i];
            if (!charInfo.isVisible)
                continue;

            Vector3[] verts = textInfo.meshInfo[charInfo.materialReferenceIndex].vertices;
            int vertexIndex = charInfo.vertexIndex;

            Vector3 offset = Random.insideUnitCircle * jitterIntensity;

            verts[vertexIndex] += offset;
            verts[vertexIndex + 1] += offset;
            verts[vertexIndex + 2] += offset;
            verts[vertexIndex + 3] += offset;
        }

        for (int i = 0; i < textInfo.meshInfo.Length; i++)
        {
            TMP_MeshInfo meshInfo = textInfo.meshInfo[i];
            meshInfo.mesh.vertices = meshInfo.vertices;
            targetText.UpdateGeometry(meshInfo.mesh, i);
        }

        yield return new WaitForSeconds(1f / jitterSpeed);
    }
}
4ff6670b3a06e5a3901cea7ff1a42991

await的用法:等待执行完再继续执行后面的代码,在做演出效果或者回合类型的上很合适

在 Unity 里,await 一般是配合 异步方法async)使用的,用来让代码在等待某个异步任务完成后再继续执行,而不会卡住主线程(UI 和游戏逻辑照常运行)。

不过 Unity 自带的 API(像 WaitForSecondsyield return)默认是 协程(Coroutine) 体系,不是 async/await
如果你想在 Unity 里用 await,主要有两种方式:


1. 基础用法(纯 C# 异步)#

using System.Threading.Tasks;
using UnityEngine;

public class AwaitExample : MonoBehaviour
{
    async void Start()
    {
        Debug.Log("开始任务");

        await Task.Delay(2000); // 等待 2 秒(不会卡主线程)

        Debug.Log("任务完成");
    }
}

特点

  • async 标记方法允许使用 await
  • Task.Delay 是纯 C# 的延时(毫秒),不会阻塞主线程
  • 缺点是:不能直接等待 Unity 的 MonoBehaviour 生命周期/协程

2. 在 Unity 中等待帧或秒(推荐用 UniTask / Cysharp.Threading.Tasks)#

Unity 原生不支持 await 等待 WaitForSeconds,但你可以用 UniTask(一个专门给 Unity 做的 async/await 库)

安装方式(Unity 2021+):

  • 打开 Package Manager
  • Add package from git URL
https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask

使用示例

using Cysharp.Threading.Tasks;
using UnityEngine;

public class UniTaskExample : MonoBehaviour
{
    async void Start()
    {
        Debug.Log("等待 2 秒...");
        await UniTask.Delay(TimeSpan.FromSeconds(2));

        Debug.Log("等待下一帧...");
        await UniTask.Yield();

        Debug.Log("等待直到条件满足...");
        await UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Space));

        Debug.Log("空格被按下!");
    }
}

好处

  • 能直接 await Unity 异步逻辑(延时、下一帧、条件成立等)
  • 性能比协程更好(GC 少)
  • 代码是顺序结构,可读性比嵌套协程高

3. 协程转 await(不装 UniTask)#

如果你不想装库,可以自己写个扩展,把协程转换为 Task:

using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public static class CoroutineExtensions
{
    public static Task AsTask(this IEnumerator coroutine, MonoBehaviour owner)
    {
        var tcs = new TaskCompletionSource<bool>();
        owner.StartCoroutine(Wrap(coroutine, tcs));
        return tcs.Task;
    }

    private static IEnumerator Wrap(IEnumerator coroutine, TaskCompletionSource<bool> tcs)
    {
        yield return coroutine;
        tcs.SetResult(true);
    }
}

使用:

async void Start()
{
    await MyCoroutine().AsTask(this);
    Debug.Log("协程结束");
}

IEnumerator MyCoroutine()
{
    yield return new WaitForSeconds(2);
}

4. 注意事项#

  • Unity 主线程必须返回到 Update 循环,所以 await 后的代码依然会在主线程继续运行
  • 不能在 Update 里频繁开 async void,否则会有很多挂起任务
  • 推荐用 async UniTaskasync Task 而不是 async void(除非是事件回调)
  • await 是非阻塞的,和 Thread.Sleepyield return 不同

2025GMTK 配图 2

Blender雕刻里的布料模拟有一个膨胀很适合做枕头类效果

2025GMTK 配图 3
只读 · UTF-8 2025-08-10

按任意键跳过