Unity案例 - 实现冰墩墩方阵

芝麻粒儿 发表于 2022/05/29 11:16:41 2022/05/29
【摘要】 👉关于作者众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)欢迎关注公众号【空名先生】获取更多资源和交流! 👉前提这是小空坚持写的Unity新手向系列,欢迎品尝...

👉关于作者

众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!

专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)

欢迎关注公众号【空名先生】获取更多资源和交流!

👉前提

这是小空坚持写的Unity新手向系列,欢迎品尝。

小空为了方便更多的人(新手)看明白,使用的汉字,真实项目尽量使用英文规则昂。

新手(√√√)

大佬(√)

感谢新发大佬的思路

👉实践过程

这几天冰墩墩属实刷屏了,赶上年假没什么产量,造成冰墩墩一墩难求。

女朋友想要,虽然拿不倒真的,但是完全可以整个虚拟的嘛。哈哈哈

开干开干,迎冬奥,一起向未来。

冰墩墩方阵效果.gif

😜思路前瞻

  • 准备图片资源
  • 程序实现对图片资源采样,保存点阵坐标
  • 根据点阵坐标数组创建角色
  • 按键进行矩阵变换

😜第一步

准备多张黑白图片,图片尺寸限制在400像素以下,否则生成的太多电脑就炸了,哈哈。

😜第二步

图片采样说白了就是读取图片像素,我们利用Texture的GetPixel(坐标x, 坐标y)方法获取坐标位置的像素颜色,注意我们不是一个像素一个像素的读(即使那样精确度更高,且复原图像更逼真),但那样对电脑来说太费劲了,我们需要进行处理,一个小方块小方块的去取,进而最大程度的去实现相似。

image.png

“切割”后读取每个块内的像素点,如果有颜色的部分大于该块的一半,则记录该值并且取中心坐标放到【坐标点集合】中,后续创建模型的坐标位置就是读取的【坐标点集合】。

😜第三步

脚本控制逻辑,根据点阵数据生成角色物体,切换矩阵的时候增删角色

public class CreateModel : MonoBehaviour
{
    [Tooltip("多个Texture")] public TextureUnit[] textureUnits = new TextureUnit[0];
    private Transform parentTrans;
    //当前正在展示的是哪个图片的队形
    private int curTextureIndex = 0;
    [SerializeField] private TextureSampling formation;
    //矩阵坐标点
    private List<Vector3> points = new List<Vector3>();
    //创建的模型管理数据
    private readonly List<PlayerUnit> spawnedUnits = new List<PlayerUnit>();
    [Tooltip("矩阵模型")] [SerializeField] private GameObject unitPrefab;
    [Tooltip("模型移动速度")] [SerializeField] private float unitSpeed = 2;

    private void Awake()
    {
        parentTrans = new GameObject("ModelParent").transform;
        ChangeFormation();
    }

    private void Update()
    {
        //创建角色
        GenFormation();
        //鼠标键移动
        if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
        {
            print("鼠标左键点击1");
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;
            if (Physics.Raycast(ray, out hitInfo, 200))
            {
                print("鼠标左键点击2");
                formation.transform.position = hitInfo.point;
            }
        }
         //空格键切换
        if (Input.GetKeyDown(KeyCode.Space))
        {
            ++curTextureIndex;
            ChangeFormation();
        }
    }

    private void GenFormation()
    {
        points = formation.EvaluatePoints().ToList();
        if (points.Count > spawnedUnits.Count)
        {
            var remainingPoints = points.Skip(spawnedUnits.Count);
            SpawnAvatar(remainingPoints);
        }
        else if (points.Count < spawnedUnits.Count)
        {
            DeleteAvatar(spawnedUnits.Count - points.Count);
        }

        for (var i = 0; i < spawnedUnits.Count; i++)
        {
            var unit = spawnedUnits[i];
            var distance = Vector3.Distance(points[i], unit.trans.position);
            if (distance > unitSpeed)
            {
                // 移动
                unit.trans.position = unit.trans.position + (points[i] - unit.trans.position).normalized * unitSpeed;
            }
            else
            {
                // 距离很小,直接设置目标点位置
                unit.trans.position = points[i];
            }
        }
    }
 
    // 生成角色
    private void SpawnAvatar(IEnumerable<Vector3> points)
    {
        foreach (var pos in points)
        {
            var unit = new PlayerUnit();
            var obj = Instantiate(unitPrefab, transform.position + pos, Quaternion.identity, parentTrans);
            unit.obj = obj;
            unit.trans = obj.transform;
            spawnedUnits.Add(unit);
        }
    }
 
    // 删除多余的角色
    private void DeleteAvatar(int num)
    {
        for (var i = 0; i < num; i++)
        {
            var unit = spawnedUnits.Last();
            spawnedUnits.Remove(unit);
            Destroy(unit.obj);
        }
    }
    private void ChangeFormation()
    {
        if (curTextureIndex > (textureUnits.Length - 1))
        {
            curTextureIndex = 0;
        }

        var curTextureUnit = textureUnits[curTextureIndex];
        formation.textureTarget = curTextureUnit.texture;
        formation.samplingLevel = curTextureUnit.samplingStep;
        formation.scale = curTextureUnit.scale;
        formation.posClear();
    }
}

 
public class PlayerUnit
{
    public GameObject obj;
    public Transform trans;
}

[System.Serializable]
public class TextureUnit
{
    public Texture2D texture;
    public int samplingStep;
    public float scale;
}

👉其他

📢作者:小空和小芝中的小空

📢转载说明-务必注明来源:芝麻粒儿 的个人主页 - 专栏 - 掘金 (juejin.cn)

📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。