- 游戏简介
实验以捕鱼达人为基础,生成不同种类型的鱼群,每个鱼群都有独立的特征,比如外观,游向,速度等等,鱼群中的每个个体又有自己独特的性质,但他们都跟随父物体移动,有自己微小的变化,但总体趋势和父物体一致。在游戏中首先是创建一个2D的sprite来制作背景,然后创建一个空物体来随机生成鱼,鱼生成的位置始终是在背景图片下,之后才是鱼群的制作,以及鱼群的特征。
- 游戏的整体框架
游戏就是由简单的两部分组成,一部分是背景图片,一部分是随机生成鱼,其中BG是一个sprite,Spawner是一个空物体,用来随机生成鱼。
- 游戏实现
1、首先是游戏背景的设置,首先创建一个2D的sprite,然后找到一张大海的图片赋予sprite,并调整图片的大小,使图片全屏显示,效果如下
2、资源导入以及预制体的制作,在资源商店中下载一个鱼的资源导入,由于版本和付费的限制,这里下载的是Sardine,其中鱼的类型如下,我们需要的是会游动的鱼,所以选择了资源里的第三种鱼。把第三个鱼拖到场景中,通过更改鱼的外观,设置三条不同颜色的鱼,并分别把他们设置成预制体,新建一个文件夹来存储他们。
3、在背景范围内生成鱼。新建一个空物体,命名为Spawner,编写代码赋给Spawner,其中限制了鱼的数量上限,设置成公有成员,在游戏场景中可以修改,鱼生成后开始向左移动,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour
{
public GameObject []fishPrefabs;
public float timeInterval = 1;
private float timer = 0;//定时器
private int currentcount = 0;//当前鱼塘中鱼的数量
public int maxCount = 10;//鱼塘中鱼的上限
private Transform Bg;//背景图片
// Start is called before the first frame update
void Start()
{
Bg = GameObject.Find("BG").transform;
}
// Update is called once per frame
void Update()
{
//判断鱼塘是否饱和
if (currentcount >= maxCount)
{
return;
}
CreateFish();
}
void CreateFish()
{
timer += Time.deltaTime;//计时
if (timer >= timeInterval)
{
currentcount++;
timer -= timeInterval;
GameObject go = fishPrefabs[Random.Range(0, fishPrefabs.Length)];
//随机视口坐标系的点
Vector3 viewPort = new Vector3(Random.value, Random.value, 0);
Vector3 worldPoint = Camera.main.ViewportToWorldPoint(viewPort);
worldPoint.z = Bg.position.z-1; //使得鱼和背景处于同一个xy平面
//实例化
Instantiate(go, worldPoint, go.transform.rotation);
}
}
}
4、鱼群的生成,生成一群鱼,并使他们在父物体的引导下移动,每个鱼群个体又有自己独立的行为重新编写代码,赋给Spawner,原有的脚本要删除,在游戏中把预制体赋给对象,全新代码如下:
using UnityEngine;
using System.Collections;
public class SardineBoidsController : MonoBehaviour {
public GameObject sardinePrefab;
GameObject[] sardines;
public int maxXNum=2;
public int maxYNum=3;
public int maxZNum=4;
public Vector3 meanPos;
public int sardineCount;
public float rotateSpeed=1f;
public GameObject meanDummy;
void Start () {
sardineCount = maxZNum *maxYNum* maxXNum;
sardines = new GameObject[sardineCount];
for (int k=0; k<maxZNum; k++) {
for (int j=0; j<maxYNum; j++) {
for (int i=0; i<maxXNum; i++) {
int sNum=k*maxXNum*maxYNum+j*maxXNum+i;
sardines[sNum]=(GameObject)GameObject.Instantiate (sardinePrefab, transform.position+Vector3.right*i+Vector3.up*j+Vector3.forward*k, transform.rotation);
Collider[] cols=sardines[k*maxXNum*maxYNum+j*maxXNum+i].GetComponentsInChildren<Collider>();
foreach(Collider col in cols){
col.name="SardineCol";
}
}
}
}
}
void Update () {
meanPos = Vector3.zero;
for (int i=0; i<sardineCount; i++) {
meanPos=meanPos+sardines[i].transform.position;
}
meanPos = meanPos / sardineCount;
meanDummy.transform.position = meanPos;
for (int i=0; i<sardineCount; i++) {
Vector3 targetRelPos = meanPos - sardines[i].transform.position;
targetRelPos.Normalize();
float dottigawa = Vector3.Dot (targetRelPos,sardines[i].transform.right);
Rigidbody iwasirigid = sardines[i].GetComponent<Rigidbody> ();
iwasirigid.AddTorque (sardines[i].transform.up * dottigawa*rotateSpeed);
sardines[i].GetComponent<Animator>().SetFloat("Turn",dottigawa*rotateSpeed);
dottigawa = Vector3.Dot (targetRelPos,sardines[i].transform.up);
iwasirigid.AddTorque (-sardines[i].transform.right * dottigawa*rotateSpeed);
sardines[i].GetComponent<Animator>().SetFloat("Up", dottigawa*rotateSpeed);
}
}
}
最终运行结果如下: