一颗Q弹的屎该怎么做技术美术

文:许哲欣
游戏:不可燃E飛,付美君,鱼师傅,许哲欣,李琼宇
技术美术: 许哲欣

《斯巴拉西 (うん、この世界は素晴らしい)》是一款音乐节奏动作游戏

工作和生活的重压下,一个社畜患上了肠道菌群紊乱的疾病

人类的肠道不受大脑控制,往往会有它自己的想法。药物公司研发了一种新型活性药剂,可以有效的维护肠道稳定,让我们的生活变得更”通畅“。主人公是药物中的活性因子,但是他还有另外一重身份需要玩家自己去探究。轻松愉悦的氛围,动感魔性的节奏,放空大脑,跟着节奏探索身体的秘密~难得放松!Take me somewhere NICE!!!

本作品参加了今年机核的BoooM game jam,游戏包含了4个关卡大约10分钟的简单流程

游戏方法:跟随游戏内指示,按方向键“↑,↓,←,→”和空格键“空格”操作

 ▷ 在线游戏链接-itch.io链接

在今年的机核“Booom” Game Jam中,我和几个同学制作了一款音乐节奏游戏《斯巴拉西 (うん、この世界は素晴らしい)》

我负责了其中的技术美术部分,实现了主角——屎——的表现

为了配合Game Jam主题「Take Me Somewhere Nice」,游戏策划同学将主角设计成了一颗Q弹的屎,随着音乐的节奏,被玩家拉扯,探索整个世界

我要做一颗真正自由的屎!

史莱姆效果

首先我想到的是,将主角设计成史莱姆的感觉,给屎的边界添加流体效果

我将先生成空间圆点,并给它加上正弦波

并且,为了让它变得丝滑,我在正弦波上加上了周期性滚动

private void InitialRadius()
    {
        float x;
        float y;
        float z = 0f;

        float ang = 0f;  // start from 0 degree

        for (int i = 0; i < pointsNum; i++)
        {
            x = Mathf.Sin(Mathf.Deg2Rad * ang) * originRadius;
            y = Mathf.Cos(Mathf.Deg2Rad * ang) * originRadius;

            originalPos[i] = new Vector3(x, y, z);
            afterJellyPos[i] = originalPos[i];
            afterCollider[i] = afterJellyPos[i];

            ang += (360f / segments);
        }
    }

private void SimulateWave()
{
    // 正弦周期波动
    startAngle += speed;
    staticWaveAngle = startAngle;
    startRandomWaveAngle += randomWaveSpeed;
    randomWaveAngle = startRandomWaveAngle;

    // 添加正弦函数波动
    for (int i = 0; i < pointsNum; i++)
    {
        float x = Mathf.Cos(staticWaveAngle) * amplitude;
        float y = Mathf.Sin(staticWaveAngle) * amplitude;
        float z = 0;
        Vector3 wave = new Vector3(x, y, z);

        renderPos[i] = afterShrink[i] + wave;
        //renderPos[i] = afterShrink[i];

        staticWaveAngle += (Mathf.Deg2Rad * 360 / segments * waveSegments);
    }
}

不过,这个时候,这个史莱姆效果还是很怪,我们可以看到这个流体效果非常呆板

因此,我又加了一个正弦函数波动,控制两个正弦函数波动的方向和周期

// 添加随机波动
for (int i = 0; i < pointsNum; i++)
{
    float x = Mathf.Cos(randomWaveAngle) * randomWaveAmp;
    float y = Mathf.Sin(randomWaveAngle) * randomWaveAmp;
    float z = 0;
    Vector3 wave = new Vector3(x, y, z);

    renderPos[i] = renderPos[i] + wave;

    randomWaveAngle += (Mathf.Deg2Rad * 360 / segments * randomWaveSeg);
}

这个时候,史莱姆的流体效果看起来已经不错了!

拖拽特效

流体的拖拽特效如法炮制,在需要拖拽的方向上,增加一个余弦函数

为了配合音乐和方便情绪调节,我加上了力度、收缩和流体旋转的效果

if(dragDrection != KeyDirectionType.Stop)
{
    float ang = (360 - transform.localEulerAngles.z) % 360;

    float nowRange =  dragPowerfuly ? dragRangePowerful : dragRange;
    float angMin = dragAngle - nowRange;
    float angMax = dragAngle + nowRange;

    for (int i = 0; i < pointsNum; i++)
    {
        if (ang > angMin && ang < angMax)
        {
            float disAngle = Mathf.Deg2Rad * (ang - dragAngle) * 90 / nowRange;

            //nowDragDis = Mathf.Max(Mathf.Lerp(nowDragDis, 0, Time.deltaTime / 5), 0);

            float x = Mathf.Sin(Mathf.Deg2Rad * (ang + transform.localEulerAngles.z)) * nowDragDis
                * Mathf.Pow(Mathf.Cos(disAngle), 4);
            float y = Mathf.Cos(Mathf.Deg2Rad * (ang + transform.localEulerAngles.z)) * nowDragDis
                * Mathf.Pow(Mathf.Cos(disAngle), 4);

            renderPos[i] += new Vector3(x, y, 0);
        }

        ang = (ang + (360f / segments)) % 360;
    }

    nowDragDis = Mathf.Max(Mathf.Lerp(nowDragDis, 0, Time.deltaTime * dragSpeed), 0);
}

收缩和流体加速效果

小力度拖拽特效

大力度拖拽特效

墙壁边界

当主角碰到墙壁边界时,这颗屎也需要有边界收缩效果

我在计算流程中,给基础的圆添加碰撞的模拟,将碰撞的横竖面上将基础的圆变成平的

private void SimulateColliding()
{
    float segAngle = 360f / triggers.Length;

    float ang = (360 - transform.localEulerAngles.z) % 360;

    for (int i = 0; i < pointsNum; i++)
    {
        bool colliderEnter = false;

        for (int t = 0; t < triggers.Length; t++)
        {

            if(triggers[t].triggerEnter)
            {
                float nowRange = colliderRange;
                float angMin = t * segAngle - nowRange;
                float angMax = t * segAngle + nowRange;

                if (ang > angMin && ang < angMax)
                {
                    float disAngle = Mathf.Deg2Rad * (ang - t * segAngle) * 90 / nowRange;

                    float x = Mathf.Sin(Mathf.Deg2Rad * (ang + transform.localEulerAngles.z)) * triggers[t].colliDis * colliderIntense
                        * Mathf.Sqrt(Mathf.Cos(disAngle));
                    float y = Mathf.Cos(Mathf.Deg2Rad * (ang + transform.localEulerAngles.z)) * triggers[t].colliDis * colliderIntense
                        * Mathf.Sqrt(Mathf.Cos(disAngle));

                    afterCollider[i] = afterJellyPos[i] - new Vector3(x, y, 0);

                    colliderEnter = true;
                }
            }
        }

        ang = (ang + (360f / segments)) % 360;
    }

}

看起来效果已经非常不错了!

最后给我们的屎加上渲染和脸的动画

这样可爱的屎,在下面的链接中就能下载并玩到:

 ▷ 斯巴拉西在线游戏链接-itch.io链接


一颗Q弹的屎该怎么做技术美术
http://xzxthu.github.io/xzxthu.github.io/2022/04/27/Subarashii/
Author
Kyo
Posted on
April 27, 2022
Licensed under