基于Unity3D的塔防游戏
课题主要内容
设计建议塔防游戏,实现规定敌人移动路线,在塔的基座的基础上升级塔、卖掉塔、更换塔,来射击敌人。
要求:1、基于c#编程语言实现;
2、发射子弹攻击敌人;
记录分数,判定游戏成功与否。
课题研究方案
基于Android平台进行开发,开发工具使用Unity3D 3.7 、 PhotoshopCS6、Visual Studio 2019。
游戏UI设计与制作主要用PhotoshopCS6,包括游戏场景的背景、个性化按钮、游戏信息的显示等贴图。
游戏的模型建立使用Unity3D 开发工具,包括地图制作、环境制作、粒子效果、模型的物理特性等。
游戏中最核心部分脚本代码的编写需要使用Visual Studio 2019编辑工具,代码的语言选用比较简单易操作的C#语言。将脚本指定给游戏模型,再将各种类型参数连接,完成游戏设计方案
功能要求
此为塔防游戏,即地图一端会自动产生敌人到另一端,在中间部位玩家可按照自己的思路放置炮塔来阻击敌人的前进,一旦炮塔的放置位置不对,或者所选择的炮塔攻击力不够的话,便阻止不了敌人的前进,那么敌人很容易就能逃脱,玩家便输了。所以这类策略游戏不仅可以使玩家娱乐,还能使玩家的智力得到很好地提升,为此,要求此游戏要给玩家尽量大的个人发挥空间。
游戏描述
1.敌人从地图的一端进入,经过某个特定的路径后最终达到目的地(通常是地图相反的一端)。
2.玩家沿着路径放置一些防御炮塔,在敌人经过时朝他们开火。敌人一波一波的过来,玩家需要不断放置更多的防御工事,同时升级这些炮塔。
3.要赢得游戏,玩家得挺过1分钟,并且得分大于等于200分。
4.本游戏设计只设置玩家得分和游戏时间,而不设置宝物。并且本游戏中的关卡不会在此体现出来,不同关卡知识地图不同,开始时系统排出的出兵方式不同,其他都一样。故只对一个关卡进行分析。
游戏场景
GameController模块
public class GameController : MonoBehaviour
{
public static bool GameIsOver;
void Start()
{
GameIsOver = false;
}
void Update()
{
if (GameIsOver)
{
return;
}
if (Convert.ToInt16(Time.time) == 60)
{
if (Bullet.grade >= 200)
{
GameReturn();
}
else
{
GameEnd();
}
}
}
private void GameEnd()
{
GameIsOver = true;
Global.GetInstance().GetEvent().Invoke(EventEnum.failureMenu, gameObject);
Time.timeScale = 0;
}
private void GameReturn()
{
Global.GetInstance().GetEvent().Invoke(EventEnum.successMenu, gameObject);
Time.timeScale = 0;
}
}
Enemy模块
public class diren : MonoBehaviour
{
public GameObject pathObject;
public GameObject enemyPrefab;
public GameObject enemy;
private float currentAddEnemyTime = 0.0f;
public float addEnemyDutacion = 0.0f;
private ObjectPool enemyPool = new ObjectPool();
private List<GameObject> enemyList = new List<GameObject>();
void Start()
{
for(int i = 0;i < 10;i++)
{
GameObject enemy = this.CreateEnemy();
enemyPool.PushObject(enemy);
}
Global.GetInstance().SetEnemyController(gameObject);
}
GameObject CreateEnemy()
{
GameObject enemy = Instantiate(enemyPrefab);
enemy.transform.parent = this.transform;
enemy.transform.GetComponent<dr>().SetObjectPool(enemyPool);
return enemy;
}
public List<GameObject> GetEnemyList()
{
return enemyList;
}
void AddEnemy()
{
GameObject enemy = enemyPool.GetObject();
if(enemy == null)
{
enemy = this.CreateEnemy();
}
enemy.SetActive(true);
enemy.transform.parent = transform;
enemy.transform.position = pathObject.transform.GetChild(0).transform.position;
enemy.transform.GetComponent<dr>().InitWithData(pathObject, gameObject);
this.enemyList.Add(enemy);
}
void Update()
{
if(this.currentAddEnemyTime >= addEnemyDutacion)
{
this.AddEnemy();
this.currentAddEnemyTime = 0.0f;
}
else
{
this.currentAddEnemyTime += Time.deltaTime;
}
}
public void EnemyEnd(GameObject enemy)
{
enemyList.Remove(enemy);
Debug.Log("enemy list" + enemyList.Count);
}
}
EnemyController模块
public class dr : MonoBehaviour
{
private List<Vector3> pathList = new List<Vector3>();
private int pathIndex = 0;
private Vector3 targetPos = Vector3.zero;
private ObjectPool enemyPool = null;
private GameObject enemyController = null;
void Start()
{
}
public void SetObjectPool(ObjectPool pool)
{
enemyPool = pool;
}
void Update()
{
if(pathList.Count!=0&&targetPos.Equals(Vector3.zero)&&pathIndex<pathList.Count)
{
targetPos = pathList[pathIndex];
}
if(!targetPos.Equals(Vector3.zero))
{
transform.position = Vector3.MoveTowards(transform.position, targetPos, 0.08f);
}
float distance = Vector3.Distance(transform.position, targetPos);
if(distance < 0.1f)
{
pathIndex ++;
targetPos = Vector3.zero;
if(pathIndex == pathList.Count)
{
this.enemyController.transform.GetComponent<diren>().EnemyEnd(gameObject);
enemyPool.PushObject(gameObject);
}
}
}
public void InitWithData(GameObject path,GameObject ctl )
{
this.enemyController = ctl;
for (int i = 0; i < path.transform.childCount; i++)
{
pathList.Add(path.transform.GetChild(i).transform.position);
}
}
}
TowerBase模块
public class TowerBase : MonoBehaviour
{
void Start()
{}
void Update()
{}
public void OnMouseDown()
{
Global.GetInstance().GetEvent().Invoke(EventEnum.BuildMenu, gameObject);
}
}
Tower模块
public class Tower : MonoBehaviour
{
public GameObject body;public float attackDistance;
public float attackDuraction;public GameObject bulletPos;
public GameObject bulletPrefab; private float currentAttackTime;
private ObjectPool bulletPool = new ObjectPool();
private Color currentColor;private int towerLevel = 0;
private List<Color> levelColor = new List<Color>();
private GameObject targetEnemy = null;
GameObject enemyController = Global.GetInstance().GetEnemyController();
void Start()
{
levelColor.Add(Color.blue);
levelColor.Add(Color.red);
levelColor.Add(Color.black);
currentColor = body.transform.GetComponent<MeshRenderer>().material.color;
for(int i = 0;i < 5;i ++)
{
GameObject obj = this.CreateBullet();
bulletPool.PushObject(obj);
}
}
GameObject CreateBullet()
{
GameObject bullet = Instantiate(bulletPrefab);
bullet.transform.position = this.bulletPos.transform.position;
bullet.transform.GetComponent<Bullet>().SetObjectPool(bulletPool);
bullet.transform.parent = transform.parent;
return bullet;
}
void AddBullet(GameObject target)
{
GameObject bullet = bulletPool.GetObject();
if(bullet == null)
{
bullet = this.CreateBullet();
}
bullet.SetActive(true);
bullet.transform.position = bulletPos.transform.position;
bullet.transform.GetComponent<Bullet>().SetTarget(target);
}
void Update()
{
if (targetEnemy == null)
{ List<GameObject>enemyList=enemyController.transform.GetComponent<diren>().GetEnemyList();
for(int i = 0;i < enemyList.Count;i ++)
{
GameObject enemy = enemyList[i];
Vector3 enemyPos = enemy.transform.position;
Vector3 towerPos = transform.position;
float dis = Vector3.Distance(enemyPos,towerPos);
if(dis < attackDistance)
{
this.targetEnemy = enemy;
}
}
}
else
{
if(this.currentAttackTime > this.attackDistance)
{
this.AddBullet(this.targetEnemy);
this.currentAttackTime = 0.0f;
}
else
{
this.currentAttackTime += Time.deltaTime;
}
Vector3 towerV = new Vector3(0, 0, 1);
Vector3 enemyV = this.targetEnemy.transform.position - transform.position;
float angle = Vector3.SignedAngle(towerV, enemyV,Vector3.up);
transform.rotation = Quaternion.AngleAxis(angle,Vector3.up);
Vector3 enemyPos = this.targetEnemy.transform.position;
Vector3 towerPos = this.transform.position;
float dis = Vector3.Distance(enemyPos, towerPos);
if(dis > this.attackDistance)
{
this.targetEnemy = null;
}
}
}
public void OnMouseDown()
{
Global.GetInstance().GetEvent().Invoke(EventEnum.ShowUpdateMenu, gameObject);
}
public void UpdateLevel()
{
if(towerLevel == 3)
{
return;
}
towerLevel++;
this.body.transform.GetComponent<MeshRenderer>().material.color= levelColor[towerLevel - 1];
currentColor = levelColor[towerLevel - 1];
}
}
TowerController模块
public class TowerController : MonoBehaviour
{
public List<GameObject> towerPrefabList;
void Start()
{
Global.GetInstance().GetEvent().AddListener(ProcessEvent);
}
void ProcessEvent(EventEnum eventType, GameObject obj)
{
switch(eventType)
{
case EventEnum.BuildTower1:
this.BuildTower(towerPrefabList[0],obj);
break;
case EventEnum.BuildTower2:
this.BuildTower(towerPrefabList[1],obj);
break;
default:
break;
}
}
void BuildTower(GameObject obj,GameObject tb)
{
GameObject tower = Instantiate(obj);
tower.transform.parent = transform;
tower.transform.position = tb.transform.position;
}
void Update()
{}
}
Bullet模块
public class Bullet : MonoBehaviour
{
public static int grade = 100;public int timer = 1; private static Bullet instance;
private ObjectPool bulletPool = null; private GameObject targetEnemy = null;
public static Bullet getInstance
{
get
{
if (instance == null)
{
instance = new Bullet();
}
return instance;
}
}
void Start()
{ }
[System.Obsolete]
void Update()
{
timer -= Convert.ToInt16(Time.deltaTime);
if(timer <= 0)
{
timer = 1;
}
if(this.targetEnemy != null && this.targetEnemy.active == true)
{
Vector3 enemyPos = this.targetEnemy.transform.position;
Vector3 bulletPos = transform.position;
float dis = Vector3.Distance(enemyPos, bulletPos);
transform.position = Vector3.MoveTowards(bulletPos,enemyPos,0.1f);
if(dis < 0.5)
{
bulletPool.PushObject(gameObject);
this.targetEnemy = null;
grade = grade + 10;
}
}
}
public void SetObjectPool(ObjectPool pool)
{
bulletPool = pool;
}
public void SetTarget(GameObject target)
{
this.targetEnemy = target;
}
}
UIController 模块
public class UIController : MonoBehaviour
{
public GameObject buileMenu;public GameObject updateMenu;
public GameObject successMenu;public GameObject failureMenu;
public GameObject targetObject;public GameObject textback;
void Start()
{
Global.GetInstance().GetEvent().AddListener(ProcessEvent);
}
void ProcessEvent(EventEnum eventType, GameObject obj)
{
this.targetObject = obj;
switch(eventType)
{
case EventEnum.BuildMenu:
this.ShowBuileMenu(obj);
break;
case EventEnum.ShowUpdateMenu:
this.ShowUpdateMenu(obj);
break;
case EventEnum.successMenu:
this.ShowsuccessMenu(obj);
break;
case EventEnum.failureMenu:
this.ShowfailureMenu(obj);
break;
default:
break;
}
}
void ShowUpdateMenu(GameObject obj)
{
this.buileMenu.SetActive(false);this.updateMenu.SetActive(true);
this.updateMenu.transform.position= Camera.main.WorldToScreenPoint(obj.transform.position);
}
void ShowBuileMenu(GameObject obj)
{
this.updateMenu.SetActive(false); this.buileMenu.SetActive(true);
this.buileMenu.transform.position= Camera.main.WorldToScreenPoint(obj.transform.position);
}
void ShowsuccessMenu(GameObject obj)
{
this.successMenu.SetActive(true);
}
void ShowfailureMenu(GameObject obj)
{
this.failureMenu.SetActive(true);
}
public void OnButtonClick(string data)
{
Debug.Log("button click ="+data);
switch(data)
{
case "build-tower-1":
if (Bullet.grade >= 100)
{
Global.GetInstance().GetEvent().Invoke(EventEnum.BuildTower1, this.targetObject);
this.buileMenu.SetActive(false);
Bullet.grade = Bullet.grade - 100;
}
else
{
this.buileMenu.SetActive(false);
}
break;
case "build-tower-2":
if (Bullet.grade >= 100)
{
Global.GetInstance().GetEvent().Invoke(EventEnum.BuildTower2, this.targetObject);
this.buileMenu.SetActive(false);
Bullet.grade = Bullet.grade - 100;
}
else
{
this.buileMenu.SetActive(false);
}
break;
case "update":
if (Bullet.grade >= 100)
{
this.targetObject.transform.GetComponent<Tower>().UpdateLevel();
this.updateMenu.SetActive(false);
Bullet.grade = Bullet.grade - 100;
}
else
{
this.buileMenu.SetActive(false);
}
break;
case "sell":
Destroy(this.targetObject);
this.updateMenu.SetActive(false);
Bullet.grade = Bullet.grade + 50;
break;
default:
break;
}
}
}
CM 模块
public class CM : MonoBehaviour
{
public AudioClip music;public AudioSource back;
public float moveSpeed = 200f;private int t = 0;
void Start()
{
back = this.GetComponent<AudioSource>();
back.loop = true; //设置循环播放
back.volume = 0.5f;//设置音量最大,区间在0-1之间
back.clip = music;
back.Play(); //播放背景音乐
}
void Update()
{
float x = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
float z = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
transform.Translate(x, 0, z);
}
public void OnButtonClick(string data)
{
switch (data)
{
case "musicbutton":
++t;
if(t % 2 == 1)
{
back.Stop();
}
else
back.Play();
break;
default:
break;
}
}
}
TextShow 模块
public class TextShow : MonoBehaviour
{
public float timer = 1.0f;
void Start()
{ }
void Update()
{
timer -= Time.deltaTime;
GameObject.Find("Canvas/time").GetComponent<Text>().text = "时间:" + Convert.ToInt16(Time.time);
GameObject.Find("Canvas/grade").GetComponent<Text>().text = "分数:" + Bullet.grade;
}
}
最后有需要的朋友可以下载看看:基于Unity3D的塔防游戏
上一篇: vue.js响应式原理解析与实现
下一篇: 实训4