前言
本次总结针对我的第一个Unity实战项目(TOWER DEFENSE),在创作过程中的一些分析和感悟以及对部分机制的探讨。
序曲
一个塔防游戏,重要的对象应该是防御塔和敌人,而机制无一例外都是基于消灭敌人防止其进入key point。
敌人
敌人因有的属性如下:
1.属于自己的基础血量,伤害值(不一定),移动速度,特殊能力(不一定)等。
2.一定的行动轨迹。
3.对key point造成影响
防御塔
防御塔有以下属性:
1.建造所需的价格,场地。
2.攻击范围,攻击方式,攻击伤害。
3.特殊能力
经过以上分析,我们便拥有了游戏设计的思路。
创作
场景的构建
1.场地
在平面中以相同size的白方块作为放置防御塔的场地格,棕色连贯道路即为敌人行动轨迹。
2.出生点&key point
红色块为出生点,蓝色块为key point
防御塔素材
借助SIKI学院官方公众号获得了所需要的素材(不叫白嫖),详情可去siki学院官网 获取。
敌人基础属性
1.敌人用不同颜色,体型的小球代表,并创建一个管理机制
在游戏开始自动生成敌人,代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
public static int CountEnemyAlive = 0;
public Wave[] waves;
public Transform START;
public float waveRate = 3;
void Start()
{
StartCoroutine(SpawnEnemy());
}
IEnumerator SpawnEnemy()
{
foreach(Wave wave in waves)
{
for(int i=0;i<wave.count;i++)
{
GameObject.Instantiate(wave.enemyPrefab, START.position, Quaternion.identity);
if(i!=wave.count-1)
yield return new WaitForSeconds(wave.rate);
}
while (CountEnemyAlive >0)
{
yield return 0;
}
yield return new WaitForSeconds(waveRate);
}
}
}
2.敌人移动通过路径点达成
在添加脚本控制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WayPoints : MonoBehaviour
{
public static Transform[] positions;
void Awake()
{
positions = new Transform[transform.childCount];
for (int i=0;i<positions.Length;i++)
{
positions[i] = transform.GetChild(i);
}
}
}
以及给敌人命令脚本
void Move()
{
if (index > positions.Length - 1)
{
index = 0;
transform.position = new Vector3(5f, 2f, 5f);
}
transform.Translate((positions[index].position - transform.position).normalized * Time.deltaTime * speed);
if(Vector3.Distance(positions[index].position,transform.position)<0.2f)
{
index++;
}
if(index>positions.Length-1)
{
ReachDestination();
}
}
3.血量及被消灭机制
暂未实现
4.对目标点伤害
暂未实现
防御塔属性
1.建造页面UI
游戏内画面
建造代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class BuildManager : MonoBehaviour
{
public TurretData LaserTurretData;
public TurretData MissileTurretData;
public TurretData StandardTurretData;
private TurretData selectedTurretData;
public Text moneyText;
public Animator moneyAnimator;
public int money = 1000;
void ChangeMoney(int change=0)
{
money += change;
moneyText.text = "¥" + money;
}
void Update()
{
if(selectedTurretData!=null&&Input.GetMouseButtonDown(0))
{
if(EventSystem.current.IsPointerOverGameObject()==false)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool isCollider = Physics.Raycast(ray,out hit, 1000, LayerMask.GetMask("MapCube"));
if(isCollider )
{
MapCube mapCube = hit.collider.GetComponent<MapCube>();
if(mapCube.turretGO ==null)
{
if(money>selectedTurretData.cost)
{
ChangeMoney(-selectedTurretData.cost);
mapCube.BuildTurret(selectedTurretData.turretPrefab);
}
else
{
moneyAnimator.SetTrigger("Flicker");
}
}
else
{
}
}
}
}
}
public void OnLaserSelected(bool isOn)
{
selectedTurretData = LaserTurretData;
}
public void OnMissileSelected(bool isOn)
{
selectedTurretData = MissileTurretData;
}
public void OnstandardSelected(bool isOn)
{
selectedTurretData = StandardTurretData;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapCube : MonoBehaviour
{
[HideInInspector ]
public GameObject turretGO;
public GameObject buildEffect;
public void BuildTurret(GameObject turretPrefab)
{
turretGO = GameObject.Instantiate(turretPrefab, transform.position, Quaternion.identity);
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);
Destroy(effect, 1);
}
}//与地面做交互
2.防御塔属性
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class TurretData
{
public GameObject turretPrefab;
public int cost;
public GameObject turretUpgradePrefab;
public int costUpgraded;
public TurretType type;
}
public enum TurretType
{
LaserTurret,
MissileTurret,
StandardTurret
}
3.防御塔攻击
通过BoxCollider实现,检测敌人的tag并攻击
攻击代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public int damage = 50;
public float speed = 20;
public GameObject explosionEffectPrefab;
private Transform target;
public void SetTarget(Transform _target)
{
this.target = _target;
}
void Update()
{
transform.LookAt(target.position);
transform.Translate(Vector3.forward * speed * Time.deltaTime);
Vector3 dir = target.position - transform.position;
if(dir.magnitude <1)
{
target .GetComponent<Enemy>().TakeDamage(damage);
GameObject.Instantiate(explosionEffectPrefab, transform.position, transform.rotation);
Destroy(this.gameObject);
}
}
}
总结
这是个未完成品,但是确实让我理解了很多,我相信以后可以做出更好的作品