打算做一个仿照节奏光剑的游戏,先是花了一晚上找了找解决方案,有一个Openpose
还有一个ThreeDPoseTracker
,看了看配置好麻烦,而且都太吃配置了,我的1060还想多用几年,所以最后还是买了个Kinect
下面先探究下怎么去实现物体切割,用到了ezy-slice
这个插件https://github.com/DavidArayan/ezy-slice
简单的切割
首先摆好场景,一个Plane
和两个Cube
然后给Slicer
添加代码,并把Cube
设为Slice
层
using System.Collections;
using System.Collections.Generic;
using EzySlice;
using UnityEngine;
public class Slicer : MonoBehaviour {
void Start () {
}
void Update () {
Collider[] colliders = Physics.OverlapBox (transform.position, transform.localScale / 2, transform.rotation, LayerMask.GetMask ("Slice"));
if (Input.GetKeyDown (KeyCode.D)) {
foreach (var collider in colliders) {
Destroy (collider.gameObject);
//位置与法线获得切割面
collider.gameObject.SliceInstantiate (transform.position, transform.up);
}
}
}
}
这样当Slicer
与Cube
接触并按下D
键,就会切割物体
还可以给生成的切块施加一个方向的力,这样就不会一起掉落
Collider[] colliders = Physics.OverlapBox (transform.position, transform.localScale / 2, transform.rotation, LayerMask.GetMask ("Slice"));
if (colliders.Length > 0) {
foreach (var collider in colliders) {
Destroy (collider.gameObject);
//位置与法线获得切割面
GameObject[] objs = collider.gameObject.SliceInstantiate (transform.position, transform.up);
//添加刚体并设为凸多面体
foreach (var obj in objs) {
obj.gameObject.AddComponent<Rigidbody> ();
obj.gameObject.AddComponent<MeshCollider> ().convex = true;
}
//施加力
objs[0].gameObject.GetComponent<Rigidbody> ().AddForce (transform.up * 100);
objs[1].gameObject.GetComponent<Rigidbody> ().AddForce (-transform.up * 100);
}
}
给切割面添加材质
public Material sliceSurface;
//省略
Collider[] colliders = Physics.OverlapBox (transform.position, transform.localScale / 2, transform.rotation, LayerMask.GetMask ("Slice"));
if (colliders.Length > 0) {
foreach (var collider in colliders) {
Destroy (collider.gameObject);
//位置与法线获得切割面
SlicedHull hull = collider.gameObject.Slice (transform.position, transform.up);
if (hull != null) {
GameObject upper = hull.CreateLowerHull (collider.gameObject, sliceSurface);
GameObject lower = hull.CreateUpperHull (collider.gameObject, sliceSurface);
GameObject[] objs = new GameObject[] { upper, lower };
foreach (var obj in objs) {
//添加刚体并设为凸多面体
obj.gameObject.AddComponent<Rigidbody> ();
obj.gameObject.AddComponent<MeshCollider> ().convex = true;
}
//施加力
objs[0].gameObject.GetComponent<Rigidbody> ().AddForce (transform.up * 100);
objs[1].gameObject.GetComponent<Rigidbody> ().AddForce (-transform.up * 100);
}
}
}
使用DoTween制作动画
节奏光剑的物块都是从玩家面前出现的,所以先简单地做一个物体从前方出现并移动到玩家面前的动画
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
public class CubeManager : MonoBehaviour {
public GameObject cubePb;
public Transform[] originTrans;
public Transform[] targetTrans;
void Start () {
InvokeRepeating ("creatCube", 0, 2f);
}
void Update () {
}
void creatCube () {
int random = Random.Range (0, 2);
GameObject gb = Instantiate (cubePb, originTrans[random].position, cubePb.transform.rotation);
gb.transform.DOMove (targetTrans[random].position, 5).OnComplete (delegate () {
//播放完动画后销毁
Destroy (gb);
});
}
}
效果
美化
再使用这个插件做一个简易的光剑
https://assetstore.unity.com/packages/tools/particles-effects/volumetric-lines-29160
还可以添加切割特效
切割的优化
四个切割方向
向左下右上移分别是 1,2,3,4,然后在update里面调用
void setMoveDir () {
moveDir = 0;
Vector3 dir = transform.position - lastPos;
//分别是 左移 下移 右移 上移
if (dir.x < 0) {
moveDir = 1;
}
if (dir.y < 0) {
moveDir = 2;
}
if (dir.x > 0) {
moveDir = 3;
}
if (dir.y > 0) {
moveDir = 4;
}
}
由于切割时要根据一个点和轴来确定切割面,而这个光剑应该是各个方向都是开刃的,轴不好确定,所以还是把切割方法写在被切割的物体身上
放置一个空物体到中心偏前的位置,根据这个物体来切割物块
public void slice () {
//位置与法线获得切割面
SlicedHull hull = gameObject.Slice (slicePoint.position, slicePoint.right);
if (hull != null) {
GameObject upper = hull.CreateLowerHull (gameObject, sliceSurface);
GameObject lower = hull.CreateUpperHull (gameObject, sliceSurface);
GameObject[] objs = new GameObject[] { upper, lower };
foreach (var obj in objs) {
//添加刚体并设为凸多面体
obj.gameObject.AddComponent<Rigidbody> ();
obj.gameObject.AddComponent<MeshCollider> ().convex = true;
}
}
Destroy (gameObject);
}
最后让它能够朝四个方向旋转
void setAllowDir () {
allowDir = Random.Range (1,5);
transform.Rotate (Vector3.forward * 90 * allowDir, Space.Self);
}
效果
视觉优化
由于默认的Cube添加贴图六个面都会加上,但是我又不会用建模工具,所以使用Probuilder工具让物块只有一个面有箭头
找了个箭头的资源https://github.com/764424567/Unity-plugin/tree/master/Menu/Unity3D-ArrowImg
然后使用Probuilder建一个立方体,进入Material编辑面板选择要编辑的面更改Material即可
然后再随便弄个场景
使用Koreographer音游插件
装好Koreographer
插件后分别创建这两个资源
需要音频文件,然后定义EventID
之后通过编辑窗口在音乐对应的时间点添加事件,图上每一小段是0.5s,而我们又是“下落式”的音游,关键点是根据物块最终的位置打的,所以设定好物块从起点到终点的移动时间还要将此处的时间点统一前移n秒,比如我物块的移动时间是2s,所以这里就统一前移了2s
给物体添加Koreographer
和SimpleMusicPlayer
两个组件
在同样的物体上添加脚本
public class MusicManager : MonoBehaviour {
public float offsetTime; //偏移时间
public string eventID; //事件ID
public GameObject cubePb;
public Transform originTrans;
public Transform targetTrans;
void Start () {
Koreographer.Instance.RegisterForEvents (eventID, AddCubeEvent);
}
void AddCubeEvent (KoreographyEvent koreoEvent) {
GameObject gb = Instantiate (cubePb, originTrans.position, cubePb.transform.rotation);
gb.transform.DOMove (targetTrans.position,offsetTime).OnComplete (delegate () {
//播放完动画后销毁
Destroy (gb);
}).SetEase (Ease.Linear);
}
}
优化1
给Cube
添加刚体和碰撞体,给Slicer
添加碰撞体,重新把检测切割的方法写到OnCollisionEnter
里
void OnCollisionEnter (Collision other) {
if (other.gameObject.layer == LayerMask.NameToLayer ("Slice")) {
if (moveDir == other.gameObject.GetComponent<MoveCube> ().allowDir) {
effect.GetComponent<ParticleSystem> ().Play ();
other.transform.GetComponent<MoveCube> ().slice ();
}
}
}
看下最后的效果,虽然没有音乐,不过物块都是根据音乐节拍生成的
使用InfiniteRunner生成无限地形
https://assetstore.unity.com/packages/templates/systems/2d-3d-infinite-runner-engine-51328
这个插件是一些跑酷类游戏的原型,插件中也有各种应用场景的demo,不过我只需要用到无限连接的地形生成就行了
先随便整两个平面
然后添加这几个脚本
其中
LinkedSpawnedObject
说明这是个Linked
类型(可以连接)的物体,In和Out分别是连接的头和尾,这样在生成物体时就会自动帮我们把当前物体和前一个物体的尾连接起来PoolableObject
表示这是一个对象池的物体MovingObject
来让物体移动OutOfBoundRecycle
可以确定物体在距离回收范围多远后被回收
然后给一个物体添加MultipleObjectPooler
和LinkedSpawer
两个脚本,前者是对象池的设定,后者用来生成Linked
类型的物体
然后在另外一个物体上添加LevelManager脚本,然后在场景中编辑RecycleBounds
和DeathBounds
的范围
最后简单的效果就像这样
优化2
场景
我又在资源商店里找到个音乐可视化的地形https://assetstore.unity.com/packages/vfx/particles/spells/living-particles-105817
以下是其中一个场景
这个场景也是一个个方形区域,正好用上面的InfiniteRunner
可以生成无限连续的场景
人物
搭配一个UnityChan的模型,并试给两个“光剑”设定手部为父物体
void Start () {
if (leftHand != null) {
transform.SetParent (leftHand);
}
if (rightHand != null) {
transform.SetParent (rightHand);
}
transform.localPosition=Vector3.zero;
}
现在的样子
而今天我的Kinect也终于到货了
摄像头视角是这样的
接下来的任务就是学习Kinect的使用,如何把现实中人的动作和模型绑定起来
使用kinect
要想在unity配合kinect开发需要安装SDK和相应的插件
首先在微软官方安装kinectSDKhttps://developer.microsoft.com/zh-cn/windows/kinect/
安装后也可能出现各种问题,比如USB3.0,切换独显,省电模式等等,比如我的KinectStdio界面帧率就很低,但是录视频和在游戏里并不卡顿,也不知道是什么问题
KinectStdio界面
安装好SDK后,就要装unity插件https://assetstore.unity.com/packages/3d/characters/kinect-v2-examples-with-ms-sdk-18708
这个插件里面包含了各个场景的示例,稍微改改就能直接用
由于暂时还不知道怎么修改模型(用之前的unity酱试了试效果不太理想),所以我直接把示例场景里的模型和必要的物体复制到我的音游场景里
连接kinect运行场景,下面就是目前的样子,已经具备可玩性了,就是操作有点蹩脚