Unity 3D游戏-塔防类游戏源码:重要方法和功能的实现
Unity-塔防游戏源码
本文提供全流程,中文翻译。 Chinar坚持将简单的生活方式,带给世人! (拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) |
1
有耐心的朋友可以跳转到SiKi学院,观看视频:SiKi学院
SiKi学院——是本人发现的网络教程做的很完善的网络课堂,推荐大家多学,多看
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// 建筑物控制脚本
/// </summary>
public class BuildManager : MonoBehaviour
{
public TurretData StandarTurretData; //标准炮塔数据
public TurretData MissileTurretData; //导弹炮塔数据
public TurretData LaserTurretData; //激光炮塔数据
private TurretData SelectedTurretData; //当前选择的炮塔(即将要建造的炮台)
private MapCube _selectedMapCube; //当前选择的游戏炮台
private int Money = 1000; //金币
public Text MoneyText; //金币文本框
public Animator MoneyAnimator;
public GameObject UpgradeCanvas;
public Button ButtonUpGrade;
private Animator UpgradeCanvasAnimator;
void Start()
{
UpgradeCanvasAnimator = UpgradeCanvas.GetComponent<Animator>();
}
void Update()
{
//容错,炮台的建造,需要满足2个条件
if (SelectedTurretData != null && Input.GetMouseButtonDown(0)) //如果鼠标右键按下;
{
if (EventSystem.current.IsPointerOverGameObject() == false) //检测鼠标在不在UI上。
{
//射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//被照射物体
RaycastHit hit;
//是否照射到物体 (射线,被照射物体,射线长度,MapCuber层的物体)
bool isCollider = Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("MapCube"));
if (isCollider)
{
MapCube mapcube = hit.collider.GetComponent<MapCube>(); //得到点击的mapcube
//如果底板上 没有炮塔,则可以创建
if (mapcube.TurretGo == null)
{
//可以创建,然后判断钱够不够,
if (Money >= SelectedTurretData.Cost)
{
ChangeMoney(-SelectedTurretData.Cost); //减少钱
mapcube.BuildTurret(SelectedTurretData); //创建炮塔
}
else
{
//提示钱不够
MoneyAnimator.SetTrigger("Flicker");
}
}
else if (mapcube.TurretGo != null)
{
//选择的是否是同一个炮台&&UI升级框是否显示
if (mapcube.TurretGo == _selectedMapCube && UpgradeCanvas.activeInHierarchy)
{
StartCoroutine(HideUpGradeUi());
}
else
{
Vector3 upgraded = new Vector3(mapcube.transform.position.x, mapcube.transform.position.y + 2.6f, mapcube.transform.position.z);
//升级
ShowUpGradeUI(upgraded, mapcube.IsUpgraded);
}
//选择的炮台,被赋值
_selectedMapCube = mapcube;
}
}
}
}
}
public void OnStandarSelected(bool isOn)
{
if (isOn)
{
SelectedTurretData = StandarTurretData;
}
}
public void OnMissileSelected(bool isOn)
{
if (isOn)
{
SelectedTurretData = MissileTurretData;
}
}
public void OnLaserSelected(bool isOn)
{
if (isOn)
{
SelectedTurretData = LaserTurretData;
}
}
/// <summary>
/// 金钱的变动
/// </summary>
/// <param name="change"></param>
private void ChangeMoney(int change = 0)
{
Money += change; //金币的变动
MoneyText.text = "¥" + Money; //金币文本框赋值
}
/// <summary>
/// 显示升级按钮
/// </summary>
/// <param name="pos"></param>
/// <param name="isDisableUp"></param>
private void ShowUpGradeUI(Vector3 pos, bool isDisableUp = false) //是否禁用升级按钮
{
StopCoroutine(HideUpGradeUi());
UpgradeCanvas.SetActive(false); //显示按钮
UpgradeCanvas.transform.position = pos;
UpgradeCanvas.SetActive(true); //显示按钮
ButtonUpGrade.interactable = !isDisableUp; //是否可以交互/ false
}
/// <summary>
/// 隐藏升级按钮
/// </summary>
IEnumerator HideUpGradeUi()
{
UpgradeCanvasAnimator.SetTrigger("Hide");
yield return new WaitForSeconds(0.6f);
UpgradeCanvas.SetActive(false);
}
/// <summary>
/// 点击升级按钮,升级炮塔
/// </summary>
public void OnUpGradeButtonDown()
{
if (Money >= _selectedMapCube._turretData.Cost) //钱够不够
{
ChangeMoney(-_selectedMapCube._turretData.Cost);
_selectedMapCube.UpGradeTurret();
}
else
{
MoneyAnimator.SetTrigger("Flicker");
}
StartCoroutine(HideUpGradeUi());
}
/// <summary>
/// 点击拆按钮。拆炮塔
/// </summary>
public void OnDestroyButtonDown()
{
_selectedMapCube.DestroyTurret();
StartCoroutine(HideUpGradeUi());
}
}
2
using UnityEngine;
/// <summary>
/// 子弹类脚本
/// </summary>
public class Bullet : MonoBehaviour
{
public int Damage = 50; //伤害
public float Speed = 20; //速度
private Transform Target; //目标
public GameObject ExplosionEffectPrefab; //子弹特效
private float DistanceArriveTarget = 2; //子弹于目标物体,向量长度
void Start()
{
}
void Update()
{
if (Target == null)
{
Die();
return;
}
transform.LookAt(Target.position); //面向目标位置
transform.Translate(Vector3.forward * Speed * Time.deltaTime);
Vector3 dir = Target.position - transform.position;
if (dir.magnitude < DistanceArriveTarget) //向量的长度magnitude
{
//子弹打到敌人,掉血
Target.GetComponent<Enemy>().TakeDamage(Damage);
Die();
}
}
private void Die()
{
//实例化特效
GameObject effect = Instantiate(ExplosionEffectPrefab, transform.position, transform.rotation) as GameObject;
//删除特效
Destroy(effect, 1f);
//销毁子弹
Destroy(this.gameObject);
}
/// <summary>
/// 设置目标
///
/// </summary>
/// <param name="_target"></param>
public void SetTarget(Transform _target)
{
this.Target = _target;
}
}
3
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
/// <summary>
/// 敌人脚本
/// </summary>
public class Enemy : MonoBehaviour
{
//位置数组
private Transform[] positions;
//下标,从0开始
private int index = 0;
//速度
public float Speed = 10;
public float Hp = 150;
private float TotalHp; //总HP
public GameObject ExplosionEffect; //敌人爆炸特效
private Slider HpSlider;
void Start()
{
positions = WayPoints.positions;
TotalHp = Hp;
HpSlider = GetComponentInChildren<Slider>();
}
void Update()
{
Move();
}
void Move()
{
//下标越界,就跳出;
if (index > positions.Length - 1) return;
//找一个方向,(目标位置-当前位置).normalized 取得这个向量的单位向量 ;
transform.Translate((positions[index].position - transform.position).normalized * Time.deltaTime * Speed);
//判断 两点 之间的距离
if (Vector3.Distance(positions[index].position, transform.position) < 0.5f)
{
index++;
}
if (index > positions.Length - 1)
{
ReachDestination();
}
}
/// <summary>
/// ReachDestination 到达 目的地 销毁
/// </summary>
void ReachDestination()
{
Destroy(this.gameObject);
GameManager.instance.Failed();
}
/// <summary>
/// 监听销毁敌人
/// </summary>
void OnDestroy()
{
EnemySpawner.CountEnemyAlive--;
}
/// <summary>
/// 敌人受到伤害
/// </summary>
/// <param name="damage"></param>
public void TakeDamage(float damage)
{
if (Hp <= 0) return; //死了不处理
Hp -= damage; //减少血量
HpSlider.value = (float) Hp / TotalHp; //血条
if (Hp <= 0)
{
Die();
}
}
private void Die()
{
GameObject effect = Instantiate(ExplosionEffect, transform.position, transform.rotation) as GameObject;
Destroy(effect, 1.5f);
Destroy(this.gameObject);
}
}
4
using UnityEngine;
using System.Collections;
/// <summary>
/// 敌人生成控制脚本
/// </summary>
public class EnemySpawner : MonoBehaviour
{
//属性面板
public Wave[] Waves;
//生成位置
public Transform StartTran;
//孵化间隔
public float WaveRate = 0.2f;
//存活敌人的数量
public static int CountEnemyAlive = 0;
private Coroutine coroutine;
void Start()
{
coroutine = StartCoroutine(SpawnEnemy());
}
/// <summary>
/// 敌人孵化器
/// </summary>
/// <returns></returns>
IEnumerator SpawnEnemy()
{
//遍历所有Waves中的 数组
foreach (Wave wave in Waves)
{
for (int i = 0; i < wave.Count; i++)
{
//实例化预设物(每一波敌人的预设物,开始位置,无旋转的)旋转前的初始角
GameObject.Instantiate(wave.EnemyPrefab, StartTran.position, Quaternion.identity);
CountEnemyAlive++; //存活数量增加
if (i != wave.Count - 1) //检测生成是否完毕
{
//时间间隔
yield return new WaitForSeconds(wave.Rate);
}
}
//当存活数量大于0
while (CountEnemyAlive > 0)
{
yield return 0; //暂停0帧,不执行下边代码
}
//每一波暂停 WaveRate 秒
yield return new WaitForSeconds(WaveRate);
}
}
/// <summary>
/// 停止生成
/// </summary>
public void Stop()
{
StopCoroutine(coroutine);
}
}
5
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 地图版块控制脚本
/// </summary>
public class MapCube : MonoBehaviour
{
[HideInInspector] //不显示在 Inspector 面板
public GameObject TurretGo; //保存当前Cube身上的炮台
[HideInInspector] public TurretData _turretData;
public GameObject BuildEffect;
private Renderer CubeRenderer;
[HideInInspector] public bool IsUpgraded; //MapCub上的炮塔是否升级过
void Start()
{
CubeRenderer = GetComponent<Renderer>();
}
/// <summary>
/// 点击创建炮塔
/// </summary>
/// <param name="turretPrefab"></param>
public void BuildTurret(TurretData turretData)
{
this._turretData = turretData;
IsUpgraded = false;
//创建炮塔,位置,旋转,强转
TurretGo = Instantiate(turretData.TurretPrefab, transform.position, Quaternion.identity) as GameObject;
GameObject effectobj = Instantiate(BuildEffect, transform.position, Quaternion.identity) as GameObject;
Destroy(effectobj, 1f);
}
/// <summary>
/// 升级炮台
/// </summary>
/// <param name="turretgo"></param>
public void UpGradeTurret()
{
if (IsUpgraded == true) return; //容错
Destroy(TurretGo); //删除低级炮塔
IsUpgraded = true; //升级状态变化
//创建炮塔,位置,旋转,强转
TurretGo = Instantiate(_turretData.TurretUpGradedPrefab, transform.position, Quaternion.identity) as GameObject;
GameObject effectobj = Instantiate(BuildEffect, transform.position, Quaternion.identity) as GameObject;
}
/// <summary>
/// 拆除炮台
/// </summary>
public void DestroyTurret()
{
Destroy(TurretGo);
GameObject effectobj = Instantiate(BuildEffect, transform.position, Quaternion.identity) as GameObject;
IsUpgraded = false; //升级状态变化
TurretGo = null;
_turretData = null;
}
/// <summary>
/// 鼠标移入
/// </summary>
private void OnMouseEnter()
{
//Cube上没有炮台,且,鼠标没有放在UI上
if (TurretGo == null && EventSystem.current.IsPointerOverGameObject() == false)
{
CubeRenderer.material.color = Color.red; //变红
}
}
/// <summary>
/// 鼠标移出
/// </summary>
private void OnMouseExit()
{
CubeRenderer.material.color = Color.white; //变红
}
}
6
using UnityEngine;
/// <summary>
/// 炮塔模型类
/// </summary>
[System.Serializable] //可序列化
public class TurretData
{
//炮塔预设物
public GameObject TurretPrefab;
//花费
public int Cost;
//炮塔升级预设物
public GameObject TurretUpGradedPrefab;
//升级炮塔花费
public int CostUpGraded;
//默认枚举类型
public TurretType Type;
}
/// <summary>
/// 枚举一个炮塔类
/// </summary>
public enum TurretType
{
StandardTurret, //标准
MissileTurret, //导弹
LaserTurret //激光
}
7
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 炮塔控制脚本类
/// </summary>
public class Turret : MonoBehaviour
{
private List<GameObject> Enemys = new List<GameObject>(); //进入方位的敌人
public float AttackRateTime = 1; //攻击间隔
private float Timer = 0; //计时器
public GameObject BulletPrefab; //子弹 预设物
public Transform FirePos;
public Transform Head;
public bool UseLaser = false; //默认攻击方式
public float DamageRate = 70; //激光炮塔,持续伤害 速率。每秒70点伤害
public LineRenderer LaseRenderer;
public GameObject LaserEffect; //激光特效
void Start()
{
Timer = AttackRateTime;
}
void Update()
{
if (Enemys.Count > 0 && Enemys[0] != null)
{
Vector3 targetPosition = Enemys[0].transform.position;
targetPosition.y = Head.position.y;
Head.LookAt(targetPosition);
}
if (UseLaser == false)
{
Timer += Time.deltaTime;
//敌人数量大于0,且满足间隔时间
if (Enemys.Count > 0 && Timer >= AttackRateTime)
{
Timer = 0;
Attack();
}
}
else if (Enemys.Count > 0)
{
if (LaseRenderer.enabled == false) LaseRenderer.enabled = true;
if (Enemys[0] == null)
{
UpDateEnemys();
}
if (Enemys.Count > 0)
{
//激光炮塔朝向
LaseRenderer.SetPositions(new Vector3[] {FirePos.position, Enemys[0].transform.position});
//激光炮塔攻击
Enemys[0].GetComponent<Enemy>().TakeDamage(DamageRate * Time.deltaTime);
LaserEffect.SetActive(true);
LaserEffect.transform.position = Enemys[0].transform.position;
//激光特效,朝向炮塔
Vector3 pos = transform.position;
pos.y = Enemys[0].transform.position.y;
LaserEffect.transform.LookAt(pos);
}
}
else
{
LaserEffect.SetActive(false);
LaseRenderer.enabled = false;
}
}
/// <summary>
/// 攻击方法
/// </summary>
private void Attack()
{
if (Enemys[0] == null)
{
UpDateEnemys();
}
if (Enemys.Count > 0)
{
//实例化子弹
GameObject bullet = Instantiate(BulletPrefab, FirePos.position, FirePos.rotation) as GameObject;
//子弹 指向目标
bullet.GetComponent<Bullet>().SetTarget(Enemys[0].transform);
}
else
{
Timer = AttackRateTime; //下次来敌人,直接攻击
}
}
/// <summary>
/// 进入区域
/// </summary>
/// <param name="col"></param>
private void OnTriggerEnter(Collider col)
{
if (col.tag == "Enemy")
{
Enemys.Add(col.gameObject);
}
}
/// <summary>
/// 离开区域
/// </summary>
/// <param name="col"></param>
private void OnTriggerExit(Collider col)
{
if (col.tag == "Enemy")
{
Enemys.Remove(col.gameObject);
}
}
/// <summary>
/// 更新集合
/// </summary>
private void UpDateEnemys()
{
//用来存空元素下标 的数组
List<int> EmptyIndex = new List<int>();
//移除所有为空的元素,遍历进入范围的敌人数组长度。
for (int i = 0; i < Enemys.Count; i++)
{
if (Enemys[i] == null)
{
EmptyIndex.Add(i);
}
}
//移除 所有空元素
for (int i = 0; i < EmptyIndex.Count; i++)
{
//由于Enemys移除元素,下标会变动。所以减去,移除的个数;
Enemys.RemoveAt(EmptyIndex[i] - i);
}
}
}
8
using UnityEngine;
using System.Collections;
/// <summary>
/// 玩家视角控制脚本
/// </summary>
public class ViewController : MonoBehaviour
{
public float Speed = 1; //速度
public float MouseSpeed = 249; //速度
void Start()
{
}
void Update()
{
//获取水平和垂直参数
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float mouse = Input.GetAxis("Mouse ScrollWheel") * MouseSpeed;
//控制移动,并根据时间平滑移动,根据世界坐标移动
transform.Translate(new Vector3(h * Speed, mouse, v * Speed) * Time.deltaTime, Space.World);
}
}
9
using UnityEngine;
/// <summary>
/// 保存每一波敌人生成所需要的属性
/// </summary>
[System.Serializable] //可以被序列化的属性
public class Wave
{
public GameObject EnemyPrefab; //敌人
public int Count; //数量
public float Rate; //时间间隔
}
10
有耐心的朋友可以跳转到SiKi学院,观看视频:SiKi学院
using UnityEngine;
/// <summary>
/// 路径导航脚本
/// </summary>
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);
}
}
}
1 —— 云服务器超全购买流程 (新手必备!)
2 —— 阿里ECS云服务器自定义配置 - 购买教程(新手必备!)
3—— Windows 服务器配置、运行、建站一条龙 !
4 —— Linux 服务器配置、运行、建站一条龙 !
" role="presentation">
技术交流群:806091680 ! Chinar 欢迎你的加入
END
本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究
对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com
对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址>
Unity 3D游戏-塔防类游戏源码:重要方法和功能的实现的更多相关文章
- unity3D游戏开发实战原创视频讲座系列9之塔防类游戏开发第一季
解说文件夹 塔防游戏0基础篇... 第一讲 游戏演示和资源介绍... 第二讲 游戏场景的完毕... 第三讲 预制体的制作... 第四讲 敌人的随机产生和按路径行走... 第五讲 塔防工具的产 ...
- 一款类似塔防类的保卫羊村游戏android源码
一款类似塔防类的保卫羊村游戏源码,这个游戏很像我们平时玩的塔防游戏的,游戏的源码比较完整的,大家可以修改一下或者添加一些广告就可以上线到应用商店了,而且这个游戏目前已经上线国内的一些应用商店了,360 ...
- 3D单机游戏《天鹰教》源码发布(二)
3D单机游戏<天鹰教>源码发布 作者 作者: 游蓝海 博客: http://blog.csdn.net/you_lan_hai mail: you_lan_hai@foxmail. ...
- 25 BasicUsageEnvironment0基本使用环境基类——Live555源码阅读(三)UsageEnvironment
25 BasicUsageEnvironment0基本使用环境基类——Live555源码阅读(三)UsageEnvironment 25 BasicUsageEnvironment0基本使用环境基类— ...
- 24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment
24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment 24 UsageEnvironment使用环境抽象基类——Live555源码阅读 ...
- 12 哈希表相关类——Live555源码阅读(一)基本组件类
12 哈希表相关类--Live555源码阅读(一)基本组件类 这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 ...
- String类的源码分析
之前面试的时候被问到有没有看过String类的源码,楼主当时就慌了,回来赶紧补一课. 1.构造器(构造方法) String类提供了很多不同的构造器,分别对应了不同的字符串初始化方法,此处从源码中摘录如 ...
- IDEA定位到类的代码区域(查看类的源码)
经常需要查看某一个类中的成员变量和方法,那么怎么进入到这个类的源码区域呢?在IDEA中只需要使用快捷键: ctrl+shift+t 就可以快速定位到这个类的源码.
- 分享自己用的php分页类实例源码
分享一个我自己用着的php分页类实例源码,供大家参考,具体内容如下: <?php /** file: page.class.php 完美分页类 Page */ class Page { priv ...
随机推荐
- JavaMai——邮箱验证用户注册
这篇文章简单的模拟了网上利用邮箱激活用户注册这样的一个功能 1. 呈现给用户的注册界面:(为了简单起见,就剩下两个输入域,邮箱和昵称) <%@ page language="java& ...
- Qt_Android_书
1. http://bbs.csdn.net/topics/390942701 <<Qt on Android 核心编程>> Qt Quick核心编程 2.
- [原][osg][osgearth]简单的通过osgDB,读取高程tif,修改高程tif
ReadResult result; osg::ref_ptr<osgDB::ReaderWriter> reader = osgDB::Registry::instance()-> ...
- 《剑指offer》第二十题(表示数值的字符串)
// 面试题20:表示数值的字符串 // 题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数).例如, // 字符串“+100”.“5e2”.“-123”.“3.1416”及“-1E-16 ...
- 【Python】Http Post请求四种请求体的Python实现
前言 前几天一个刚接触Python不深的朋友问我的Python的xml格式Post请求怎么发送,刚好最近也在学习Http请求相关的内容,所以决定总结一下各类Post请求的Python实现. Happy ...
- Illumina Sequence Identifiers 序列标识符 index详解
大家基本都知道什么是 FASTA 和 FastQ 格式了,但这是不够的. 我们还需要了解世界上最大的测序公司自己定制的 FastQ 格式,因为你可能会经常用到,有时还会亲自去处理它们. 本文主题:Il ...
- Jersey 2.x 探索新建的工程
如果用 Jersey maven archetype 成功创建了这个项目,那么在你当前的路径下就已经创建了一个名为simple-service项目.它包含了一个标准的Maven项目结构: 说明 文件目 ...
- Sasha and Interesting Fact from Graph Theory CodeForces - 1109D (图论,计数,Caylay定理)
大意: 求a->b最短路长度为m的n节点树的个数, 边权全部不超过m 枚举$a$与$b$之间的边数, 再由拓展$Caylay$定理分配其余结点 拓展$Caylay$定理 $n$个有标号节点生成k ...
- Docker+Hadoop+Hive+Presto 使用Docker部署Hadoop环境和Presto
Background 一. 什么是Presto Presto通过使用分布式查询,可以快速高效的完成海量数据的查询.如果你需要处理TB或者PB级别的数据,那么你可能更希望借助于Hadoop和HDFS来完 ...
- OAF 获取页面路径
--模糊查询某个页面 SELECT * FROM JDR_PATHS jp WHERE JP.PATH_NAME LIKE '%XXXX%'; --精确的查找过程 -- DocID --参数通过关于此 ...