Unity案例 - 实现冰墩墩方阵
👉关于作者
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!
专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
欢迎关注公众号【空名先生】获取更多资源和交流!
👉前提
这是小空坚持写的Unity新手向系列,欢迎品尝。
小空为了方便更多的人(新手)看明白,使用的汉字,真实项目尽量使用英文规则昂。
新手(√√√)
大佬(√)
感谢新发大佬的思路
👉实践过程
这几天冰墩墩属实刷屏了,赶上年假没什么产量,造成冰墩墩一墩难求。
女朋友想要,虽然拿不倒真的,但是完全可以整个虚拟的嘛。哈哈哈
开干开干,迎冬奥,一起向未来。
😜思路前瞻
- 准备图片资源
- 程序实现对图片资源采样,保存点阵坐标
- 根据点阵坐标数组创建角色
- 按键进行矩阵变换
😜第一步
准备多张黑白图片,图片尺寸限制在400像素以下,否则生成的太多电脑就炸了,哈哈。
😜第二步
图片采样说白了就是读取图片像素,我们利用Texture的GetPixel(坐标x, 坐标y)方法获取坐标位置的像素颜色,注意我们不是一个像素一个像素的读(即使那样精确度更高,且复原图像更逼真),但那样对电脑来说太费劲了,我们需要进行处理,一个小方块小方块的去取,进而最大程度的去实现相似。
“切割”后读取每个块内的像素点,如果有颜色的部分大于该块的一半,则记录该值并且取中心坐标放到【坐标点集合】中,后续创建模型的坐标位置就是读取的【坐标点集合】。
😜第三步
脚本控制逻辑,根据点阵数据生成角色物体,切换矩阵的时候增删角色
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)
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。
- 点赞
- 收藏
- 关注作者
评论(0)