项目代码见→坦克大战1.1.0
1)人机交互
2)相机
3)坦克属性
4)炮弹属性
5)敌方坦克生成策略
6)敌方坦克作战策略
7)血条
8)杀敌计数
9)摇杆
10)死亡策略
1)游戏界面
2)游戏对象层级结构
Hierarchy 窗口游戏对象:
预设体游戏对象:
3)Transform组件参数
1. Tank Transform 组件参数
Name | Type | Position | Rotation | Scale |
Tank | Empty | (0, 0.25, 0) | (0, 0, 0) | (1, 1, 1) |
Botton | Cube | (0, 0, 0) | (0, 0, 0) | (2, 0.5, 2) |
Top | Cube | (0, 0.5, 0) | (0, 0, 0) | (1, 0.5, 1) |
Gun | Cylinder | (0, 0, 1.5) | (90, 0, 0) | (0.2, 1, 0.4) |
FirePoint | Empty | (0, 1.15, 0) | (0, 0, 0) | (1, 1, 1) |
补充:Tank 游戏对象添加了刚体组件,并修改 Mass = 100,Drag = 1,AngularDrag = 0.5,Tank 作为预设体拖拽到 Assets/Resources/Prefabs 目录下,敌方坦克和己方坦克共用 Tank 预设体。
2. 玩家 Blood RectTransform 组件参数
Name | Type | Pos | Width/Height | Anchors | Pivot | Color/Texture |
Blood | Empty | (25, -30, 0) | (0, 0) | (0, 1), (0, 1) | (0.5, 0.5) | —— |
Progress | Empty | (45, 0, 0) | (0, 0) | (0, 0.5), (0, 0.5) | (0, 0.5) | —— |
Background | Image | (0, 0, 0) | (200, 20) | (0, 0.5), (0, 0.5) | (0, 0.5) | #FFFFFFFF |
Value | Image | (0, 0, 0) | (200, 20) | (0, 0.5), (0, 0.5) | (0, 0.5) | #F63C3CFF |
Rate | Text | (5, 0, 0) | (60, 30) | (0, 0.5), (0, 0.5) | (0, 0.5) | —— |
Description | Text | (0, 0, 0) | (50, 20) | (0, 0.5), (0, 0.5) | (0, 0.5) | —— |
补充:Value 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal,Fill Origin 设置为 Left。
3. Kill RectTransform 组件参数
Name | Type | Pos | Width/Height | Anchors | Pivot | Color/Texture |
Kill | Empty | (25, -60, 0) | (0, 0) | (0, 1), (0, 1) | (0.5, 0.5) | —— |
Progress | Empty | (45, 0, 0) | (0, 0) | (0, 0.5), (0, 0.5) | (0, 0.5) | —— |
Background | Image | (0, 0, 0) | (200, 20) | (0, 0.5), (0, 0.5) | (0, 0.5) | #FFFFFFFF |
Value | Image | (0, 0, 0) | (200, 20) | (0, 0.5), (0, 0.5) | (0, 0.5) | #3CB8F6FF |
Rate | Text | (5, 0, 0) | (60, 30) | (0, 0.5), (0, 0.5) | (0, 0.5) | —— |
Description | Text | (0, 0, 0) | (50, 20) | (0, 0.5), (0, 0.5) | (0, 0.5) | —— |
补充:Value 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal,Fill Origin 设置为 Left。
4. Stick RectTransform 组件参数
Name | Type | Pos | Width/Height | Anchors | Pivot | Sprite |
Stick | Empty | (75, 70, 0) | (0, 0) | (0, 0), (0, 0) | (0.5, 0.5) | —— |
Background | Image | (0, 0, 0) | (100, 100) | (0.5, 0.5), (0.5, 0.5) | (0.5, 0.5) | stick_bg |
Ball | Image | (0, 0, 0) | (40, 40) | (0.5, 0.5), (0.5, 0.5) | (0.5, 0.5) | stick_ball |
5. 敌人 Blood RectTransform 组件参数
Name | Type | Pos | Width/Height | Color/Texture |
Blood | Canvas | (0, 0.85, 0) | (2, 0.2) | —— |
Background | Image | (0, 0, 0) | (2, 0.2) | #FFFFFFFF |
Value | Image | (0, 0, 0) | (2, 0.2) | #F63C3CFF |
补充: 敌人 Blood 的 Canvas 渲染模式是 World Space,Value 的 ImageType 设置为 Filled,Fill Method 设置为 Horizontal,Fill Origin 设置为 Right。
6. Plane、Bullet、MinimapCamera Transform 组件参数
Name | Type | Position | Rotation | Scale | Color/Texture |
Plane | Plane | (0, 0, 0) | (0, 0, 0) | (10, 10, 10) | GrassRockyAlbedo |
Bullet | Sphere | (0, 0.5, -5) | (0, 0, 0) | (0.3, 0.3, 0.3) | #228439FF |
MinimapCamera | Camera | (0, 12, 0) | (90, 0, 0) | (1, 1, 1) | —— |
补充:Bullet 作为预设体拖拽到 Assets/Resources/Prefabs 目录下,并且添加了刚体组件,己方坦克和敌方坦克使用的炮弹预设体都是 Bullet;MinimapCamera 是次相机,用于渲染小地图,其Viewport Rect 为 (0.8, 0.7, 0.2, 0.3)。
BaseCreater.cs
- using System;
- using UnityEngine;
-
- public class BaseCreater : MonoBehaviour {
- protected GameObject tankPrefab; // 坦克预设体
- protected Action dyingAction; // 死亡活动
-
- protected void LoadPrefab() { // 加载预设体
- tankPrefab = (GameObject) Resources.Load("Prefabs/Tank");
- }
-
- protected GameObject CreateTank(TankInfo info) { // 创建坦克
- GameObject tank = Instantiate(tankPrefab, info.tankInitPosition, Quaternion.Euler(info.tankInitRotation));
- tank.name = info.GetName();
- UpdateColor(tank, info.tankColor);
- return tank;
- }
-
- private void UpdateColor(GameObject tank, Color color) { // 更新坦克颜色
- ForAllChildren(tank, obj => {
- MeshRenderer renderer = obj.GetComponent
(); - if (renderer != null) {
- renderer.material.color = color;
- }
- });
- }
-
- private void ForAllChildren(GameObject obj, Action
action) { // 每个子孙对象(包含自己)执行委托动作 - if (obj == null) {
- return;
- }
- foreach(Transform child in obj.GetComponentsInChildren
()) { - action(child.gameObject);
- }
- }
- }
PlayerCreater.cs
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class PlayerCreater : BaseCreater {
- [Header("坦克信息")]
- public TankInfo tankInfo;
-
- private void Awake() {
- LoadPrefab();
- tankInfo = TankParamsManager.GetInstance().GetPlayerTankInfo();
- GameObject tank = CreateTank(tankInfo);
- dyingAction += () => {
- Camera.main.GetComponent
().PlayerDying(); // 玩家死亡, 相机重新跟随一个空对象 - };
- tank.AddComponent
() - .SetDiedAction(dyingAction)
- .SetTankInfo(tankInfo);
- }
- }
说明:PlayerCreater 脚本组件挂在 PlayerCreater 游戏对象上。
EnemyCreater.cs
- using System;
- using UnityEngine;
-
- public class EnemyCreater : BaseCreater {
- protected GameObject bloodPrefab; // 血条预设体
- public EnemiesInfo enemiesInfo = null;
-
- private Transform player; // 玩家
- private KillHelper killHelper; // 杀敌助手
- private float waitTime = 0; // 距离上次坦克生成已等待的时间
-
- private void Awake() {
- LoadPrefab();
- enemiesInfo = new EnemiesInfo();
- killHelper = new KillHelper(enemiesInfo.GetTotalNum());
- dyingAction += () => {
- enemiesInfo.CurrDes();
- killHelper.KillEnemy();
- };
- }
-
- private void Start() {
- player = GameObject.Find("Player/Top").transform;
- CreateInitEnemies();
- }
-
- private void Update() {
- if (waitTime > EnemiesInfo.ENTER_INTERVAL && enemiesInfo.GetAppeardNum() < EnemiesInfo.TOTAL_NUM) {
- CreateTank();
- waitTime = 0;
- }
- waitTime += Time.deltaTime;
- }
-
- protected new void LoadPrefab() { // 加载预设体
- base.LoadPrefab();
- bloodPrefab = (GameObject) Resources.Load("Prefabs/Blood");
- }
-
- private void CreateInitEnemies() {
- for (int i = 0; i < EnemiesInfo.INIT_NUM; i++) {
- CreateTank();
- }
- }
-
- private GameObject CreateTank() { // 创建坦克
- int level = enemiesInfo.GetRandomLevel();
- TankInfo tankInfo = TankParamsManager.GetInstance().GetEnemyTankInfo(level);
- Vector3 position = GetEnemyPosition();
- Vector3 rotation = GetEnemyRotation();
- tankInfo.tankInitPosition = position;
- tankInfo.tankInitRotation = rotation;
- GameObject tank = CreateTank(tankInfo);
- CreateHealth(tank);
- tank.AddComponent
() - .SetPlayer(player)
- .SetDiedAction(dyingAction)
- .SetTankInfo(tankInfo);
- enemiesInfo.CurrAdd();
- return tank;
- }
-
- private Vector3 GetEnemyPosition() { // 获取敌人随机位置
- Vector3 position = new Vector3(0f, 0.25f, 0f);
- do {
- position.x = UnityEngine.Random.Range(-49f, 49f);
- position.z = UnityEngine.Random.Range(-49f, 49f);
- } while (IsOccupied(position));
- return position;
- }
-
- private Vector3 GetEnemyRotation() { // 获取敌人随机方向
- int y = UnityEngine.Random.Range(0, 360);
- return new Vector3(0, y, 0);
- }
-
- private bool IsOccupied(Vector3 pos) { // 检测指定位置是否被占用
- Vector3 halfExtents = new Vector3(2, 0.1f, 2);
- return Physics.CheckBox(pos, halfExtents);
- }
-
- private void CreateHealth(GameObject tank) { // 创建血条
- Vector3 pos = tank.transform.position;
- Vector3 realPos = new Vector3(pos.x, pos.y + 1.5f, pos.z);
- GameObject blood = Instantiate(bloodPrefab, realPos, Quaternion.identity, tank.transform);
- blood.name = "Blood";
- }
- }
说明:EnemyCreater 脚本组件挂在 EnemyCreater 游戏对象上。
TankController.cs
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class TankController : MonoBehaviour {
- protected TankInfo tankInfo; // 坦克信息
- protected GameObject bulletPrefab; // 炮弹预设体
- protected Transform firePoint; // 开火点
- protected BloodHelper bloodHelper; // 血量助手
- protected float fireWaitTime = float.MaxValue; // 距离上次开火已等待的时间
- protected volatile bool isDying = false; // 死亡中
- protected Action diedAction; // 敌人死亡活动
-
- protected void LoadBullet() {
- bulletPrefab = (GameObject) Resources.Load("Prefabs/Bullet");
- firePoint = transform.Find("Top/Gun/FirePoint");
- }
-
- public TankController SetTankInfo(TankInfo info) {
- tankInfo = info;
- return this;
- }
-
- public TankController SetDiedAction(Action action) {
- diedAction = action;
- return this;
- }
-
- protected void Fire() { // 开炮
- if (fireWaitTime > tankInfo.bullet.bulletCoolTime) {
- BulletInfo info = tankInfo.bullet.Clone() as BulletInfo;
- info.SetFlyDir(transform.forward);
- GameObject bullet = Instantiate(bulletPrefab, firePoint.position, Quaternion.identity);
- bullet.AddComponent
().SetBulletInfo(info); - fireWaitTime = 0f;
- }
- }
-
- public void BuckleBlood(int damage) { // 扣血
- isDying = bloodHelper.BuckleBlood(damage);
- }
-
- public bool IsDying() {
- return isDying;
- }
-
- protected void Dying() { // 坦克死亡中, 渐变为透明
- ForAllChildren(gameObject, obj => {
- Renderer renderer = obj.GetComponent
(); - if (renderer != null) {
- Color color = renderer.material.color;
- // 材质球的 Rendering Mode 需要设置为 Fade 或 Transparent, 渐变才会生效
- renderer.material.color = new Color(color.r, color.g, color.b, color.a - Time.deltaTime / 3);
- }
- Image image = obj.GetComponent
(); - if (image != null) {
- Color color = image.color;
- image.color = new Color(color.r, color.g, color.b, color.a - Time.deltaTime / 3);
- }
- });
- }
-
- protected bool CheckFallDeath() { // 检验摔死
- if (!isDying && transform.position.y < -5) {
- isDying = true;
- Destroy(gameObject, 3);
- diedAction.Invoke();
- return true;
- }
- return false;
- }
-
- protected void ForAllChildren(GameObject obj, Action
action) { // 每个子孙对象(包含自己)执行委托动作 - if (obj == null) {
- return;
- }
- foreach(Transform child in obj.GetComponentsInChildren
()) { - action(child.gameObject);
- }
- }
- }
PlayerController.cs
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class PlayerController : TankController {
- private MoveHelper moveHelper; // 交互助手
- private StickController stick; // 摇杆控制器
-
- private void Awake() {
- LoadBullet();
- stick = GameObject.Find("UI/Stick/Ball").GetComponent
(); - moveHelper = new MoveHelper(transform);
- }
-
- private void Start() {
- diedAction += () => {
- stick.PlayerDying();
- };
- moveHelper.Init(tankInfo.tankMoveSpeed, tankInfo.tankRotateSpeed);
- LoadBlood();
- }
-
- private void Update() {
- if (isDying || CheckFallDeath()) {
- Dying();
- return;
- }
- fireWaitTime += Time.deltaTime;
- moveHelper.Move();
- moveHelper.Rotate();
- if (Input.GetMouseButtonDown(0) && !stick.IsMouseInStickArea()
- || Input.GetKeyDown(KeyCode.Space)) {
- Fire();
- }
- }
-
- private void LoadBlood() {
- Image bloodValueImg = GameObject.Find("UI/Blood/Progress/Value").GetComponent
(); - Text bloodRateTxt = GameObject.Find("UI/Blood/Progress/Rate").GetComponent
(); - bloodHelper = new BloodHelper(bloodValueImg, bloodRateTxt, tankInfo, diedAction);
- }
-
- public void Move(float hor, float ver) { // 坦克移动
- moveHelper.Move(hor, ver);
- }
- }
说明:PlayerController 脚本组件挂在 Player 游戏对象上。
EnemyController.cs
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class EnemyController : TankController {
- private Transform player; // 玩家
- private Transform top; // 炮头
- private Vector3 tempTarget; // 临时目标点,巡逻时使用
- private bool isFoundPlayer = false; // 是否发现了玩家
- private float findTargetTime = 0; // 巡逻时寻找目标花费的时间
-
- private void Awake() {
- LoadBullet();
- top = transform.Find("Top");
- Vector3 pos = top.position;
- tempTarget = new Vector3(pos.x, pos.y, pos.z);
- }
-
- private void Start(){
- LoadBlood();
- }
-
- private void Update() {
- if (isDying || CheckFallDeath()) {
- Dying();
- return;
- }
- bloodHelper.BloodLookAtCamera();
- float distance = GetDistance();
- if (distance < 1.5f * tankInfo.bullet.bulletFireRange) { // 发现了玩家
- if (distance < tankInfo.bullet.bulletFireRange / 2 || distance < 5) {
- Fire();
- } else if (distance < tankInfo.bullet.bulletFireRange) {
- MoveToTarget(player.position);
- Fire();
- } else {
- MoveToTarget(player.position);
- }
- isFoundPlayer = true;
- findTargetTime = 0;
- } else {
- Patrol();
- isFoundPlayer = false;
- }
- fireWaitTime += Time.deltaTime;
- }
-
- public EnemyController SetPlayer(Transform transform) {
- player = transform;
- return this;
- }
-
- protected new void Fire() { // 开炮
- if (LookAtTarget(player.position)) {
- base.Fire();
- }
- }
-
- private bool LookAtTarget(Vector3 target) { // 转向目标
- Vector3 dir = target - top.position;
- float angle = Vector3.Angle(dir, top.forward);
- if (angle > 5) {
- int axis = Vector3.Dot(Vector3.Cross(dir, top.forward), Vector3.up) > 0 ? -1 : 1;
- GetComponent
().angularVelocity = axis * Vector3.up * tankInfo.tankRotateSpeed; - return false;
- }
- GetComponent
().angularVelocity = Vector3.zero; - return true;
- }
-
- private void MoveToTarget(Vector3 target) { // 向目标移动
- if (LookAtTarget(target)) {
- Vector3 dir = (target - top.position).normalized;
- GetComponent
().velocity = tankInfo.tankMoveSpeed * dir; - findTargetTime += Time.deltaTime;
- }
- }
-
- private void Patrol() { // 巡逻
- GetNextPatrolTarget();
- MoveToTarget(tempTarget);
- }
-
- private float GetDistance() { // 获取坦克距离玩家的距离
- if (player == null) {
- return float.MaxValue;
- }
- return Vector3.Distance(player.position, top.position);
- }
-
- private void GetNextPatrolTarget() { // 获取下一个巡逻目标点
- if (isFoundPlayer || Vector3.Distance(tempTarget, top.position) < 0.1f
- || ForwardHasFriends() && findTargetTime > 1) {
- float angle = top.eulerAngles.y + UnityEngine.Random.Range(-120f, 120f);
- angle = angle * Mathf.PI / 180f;
- float radius = UnityEngine.Random.Range(10f, 30f);
- tempTarget.x = Mathf.Clamp(top.position.x + radius * Mathf.Cos(angle), -49, 49);
- tempTarget.z = Mathf.Clamp(top.position.z + radius * Mathf.Sin(angle), -49, 49);
- findTargetTime = 0;
- }
- }
-
- private bool ForwardHasFriends() { // 前方有友军
- return Physics.BoxCast(top.position, new Vector3(1, 0.5f, 1), top.forward, top.rotation, 5, ~(1 << 8));
- }
-
- private void LoadBlood() {
- Transform blood = transform.Find("Blood");
- Image bloodValueImg = blood.Find("Value").GetComponent
(); - bloodHelper = new BloodHelper(bloodValueImg, null, tankInfo, diedAction);
- bloodHelper.setTransform(blood);
- }
- }
说明:EnemyController 脚本组件挂在 Enemy 游戏对象上。
BulletController.cs
- using UnityEngine;
-
- public class BulletController : MonoBehaviour {
- private BulletInfo bulletInfo; // 炮弹信息
- private bool isDying = false;
-
- private void Start () {
- GetComponent
().material.color = bulletInfo.bulletColor; - float lifeTime = bulletInfo.bulletFireRange / bulletInfo.bulletSpeed; // 存活时间
- Destroy(gameObject, lifeTime);
- }
-
- private void Update () {
- transform.GetComponent
().velocity = bulletInfo.GetFlyDir() * bulletInfo.bulletSpeed; - }
-
- private void OnCollisionEnter(Collision other) {
- TankController tankController = other.gameObject.GetComponent
(); - if (isDying || tankController == null || tankController.IsDying()) {
- return;
- }
- if (isHitEnemy(bulletInfo.GetName(), other.gameObject.name)
- || isHitPlayer(bulletInfo.GetName(), other.gameObject.name)) {
- tankController.BuckleBlood(bulletInfo.bulletDamage);
- if (tankController.IsDying()) {
- Destroy(other.gameObject, 3f);
- }
- }
- isDying = true;
- Destroy(gameObject, 0.3f);
- }
-
- public void SetBulletInfo(BulletInfo info) {
- bulletInfo = info;
- }
-
- private bool isHitEnemy(string bulletName, string roleName) { // 击中敌军
- return "PlayerBullet".Equals(bulletName) && "Enemy".Equals(roleName);
- }
-
- private bool isHitPlayer(string bulletName, string roleName) { // 击中玩家
- return "EnemyBullet".Equals(bulletName) && "Player".Equals(roleName);
- }
- }
说明:BulletController 脚本组件挂在 Bullet 游戏对象上。
CameraController.cs
- using UnityEngine;
-
- public class CameraController : MonoBehaviour {
- protected Transform player; // 玩家
- protected Transform visitor; // 游客
- protected Vector3 relaPlayerPos; // 相机在玩家坐标系中的位置
-
- protected void InitPlayer() {
- GameObject obj = GameObject.Find("Player/Top");
- if (obj != null) {
- player = obj.transform;
- CompCameraPos(player);
- }
- }
-
- public void PlayerDying() { // 玩家死亡时, 游客替换玩家的位置, 使相机跟随游客
- GameObject visitorObj = new GameObject("Visitor");
- visitorObj.AddComponent
(); - visitor = visitorObj.transform;
- visitor.position = player.position;
- visitor.rotation = player.rotation;
- player = null;
- }
-
- protected Transform getVisitor() { // 给小地图相机使用
- GameObject visitorObj = GameObject.Find("Visitor");
- if (visitorObj != null) {
- return visitorObj.transform;
- }
- return visitor;
- }
-
- // 求以origin为原点, locX, locY, locZ 为坐标轴的本地坐标系中的向量 vec 在世界坐标系中对应的向量
- protected Vector3 transformVecter(Vector3 vec, Vector3 origin, Vector3 locX, Vector3 locY, Vector3 locZ) {
- return vec.x * locX + vec.y * locY + vec.z * locZ + origin;
- }
-
- protected void CompCameraPos(Transform target) { // 计算相机位置
- }
- }
MainCameraController.cs
- using UnityEngine;
-
- public class MainCameraController : CameraController {
- private float targetDistance = 30f; // 相机看向玩家前方的位置
-
- private void Start() {
- relaPlayerPos = new Vector3(0, 8, -12);
- InitPlayer();
- }
-
- private void LateUpdate() {
- if (player != null) {
- CompCameraPos(player);
- } else if (visitor == null) {
- visitor = getVisitor();
- } else {
- CompCameraPos(visitor);
- }
- }
-
- protected new void CompCameraPos(Transform target) { // 计算相机坐标
- transform.position = transformVecter(relaPlayerPos, target.position, target.right, target.up, target.forward);
- if (transform.position.y < 0) { // 避免坦克翻面时相机朝天
- transform.position = new Vector3(transform.position.x, -transform.position.y, transform.position.z);
- }
- Vector3 lookPos = target.position + target.forward * targetDistance;
- if (lookPos .y > 1) { // 避免坦克扬起时相机朝天
- lookPos = new Vector3(lookPos.x, 1, lookPos.z);
- }
- transform.rotation = Quaternion.LookRotation(lookPos - transform.position);
- }
- }
说明:MainCameraController 脚本组件挂在 MainCamera 游戏对象上。
MinimapCameraController.cs
- using UnityEngine;
-
- public class MinimapCameraController : CameraController {
- private CameraController mainCamera;
- private bool isFullscreen = false; // 小地图相机是否全屏
- private Rect minViewport; // 小地图视口位置和大小(相对值)
- private Rect fullViewport; // 全屏时视口位置和大小(相对值)
- private Rect targetViewport; // 目标视口大小, 用于动效
- private float switchRectInternal = 0.3f; // 切换小地图尺寸时间间隔
- private float switchWaitTime = float.MaxValue; // 切换小地图等待时间
- private bool isSwitching = false; // 切换中, 用于标记执行切换动效中
-
- private void Start() {
- mainCamera = Camera.main.GetComponent
(); - minViewport = GetComponent
().rect; - fullViewport = new Rect(0, 0, 1, 1);
- relaPlayerPos = new Vector3(0, 50, 0);
- InitPlayer();
- }
-
- private void Update() {
- switchWaitTime += Time.deltaTime;
- if (switchWaitTime > switchRectInternal && !isSwitching) {
- SwitchRect();
- }
- if (isSwitching) {
- SwitchAnimation();
- }
- }
-
- private void LateUpdate() {
- if (player != null) {
- CompCameraPos(player);
- } else if (visitor == null) {
- visitor = getVisitor();
- } else {
- CompCameraPos(visitor);
- }
- }
-
- private void SwitchRect() { // 切换小地图尺寸
- if (Input.GetMouseButtonDown(0) && IsClickMinimap()) {
- if (isFullscreen) { // 小地图缩小
- targetViewport = minViewport;
- } else { // 小地图放大
- targetViewport = fullViewport;
- }
- isFullscreen = !isFullscreen;
- isSwitching = true;
- switchWaitTime = 0;
- }
- }
-
- private void SwitchAnimation() { // 切换动效
- Rect rect = GetComponent
().rect; - rect.position = Vector2.Lerp(rect.position, targetViewport.position, 0.5f);
- rect.size = Vector2.Lerp(rect.size, targetViewport.size, 0.5f);
- GetComponent
().rect = rect; - if (Vector2.Distance(rect.position, targetViewport.position) < 0.01f) {
- GetComponent
().rect = targetViewport; - isSwitching = false;
- }
- }
-
- protected new void CompCameraPos(Transform target) { // 计算相机坐标
- transform.position = target.position + relaPlayerPos;
- }
-
- public bool IsClickMinimap() { // 是否单击到小地图区域
- Vector3 pos = Input.mousePosition;
- if (isFullscreen || isSwitching) {
- return true;
- }
- if (pos.x / Screen.width > minViewport.xMin && pos.y / Screen.height > minViewport.yMin) {
- return true;
- }
- return false;
- }
- }
说明:MinimapCameraController 脚本组件挂在 MinimapCamera 游戏对象上。
VisitorController.cs
- using UnityEngine;
-
- public class VisitorController : MonoBehaviour {
- private MoveHelper moveHelper; // 交互助手
-
- private void Awake() {
- moveHelper = new MoveHelper(transform);
- moveHelper.Init(6, 10);
- }
-
- private void Update() {
- moveHelper.Move();
- moveHelper.Rotate();
- }
- }
说明:VisitorController 脚本组件挂在 Visitor 游戏对象上。
StickController.cs
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- public class StickController : MonoBehaviour, IDragHandler, IEndDragHandler {
- private Vector3 originPos; // 鼠标开始拖拽时位置
- private Vector3 currPos; // 鼠标当前位置
- private float radius; // 遥杆半径
- private PlayerController player; // 玩家控制器
- private Vector3 dire = Vector3.zero; // 摇杆球的方位
-
- private void Start () {
- originPos = transform.position;
- radius = 50;
- player = GameObject.Find("Player").GetComponent
(); - }
-
- private void Update () {
- if (player != null && !Vector3.zero.Equals(dire)) {
- player.Move(dire.x, dire.y);
- }
- }
-
- public void OnDrag(PointerEventData eventData) {
- Vector3 vec = Input.mousePosition - originPos;
- dire = vec.normalized * Mathf.Min(vec.magnitude / radius, 1);
- UpdateStick(dire);
- }
-
- public void OnEndDrag(PointerEventData eventData) {
- transform.position = originPos;
- dire = Vector3.zero;
- }
-
- public void UpdateStick(Vector3 dire) { // 更新摇杆位置
- transform.position = originPos + dire * radius;
- }
-
- public void PlayerDying() {
- player = null;
- UpdateStick(Vector3.zero);
- }
-
- public bool IsMouseInStickArea() { // 鼠标在Stick区域
- Vector3 pos = Input.mousePosition;
- return pos.x < 150 && pos.y < 150;
- }
- }
说明:StickController 脚本组件挂在 Stick 游戏对象上。
BloodHelper.cs
-
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class BloodHelper {
- private Transform transform; // 血条Transform
- private Image bloodValueImg; // 血条Image
- private Text bloodRateTxt; // 血量比率Text
- private TankInfo tankInfo; // 坦克信息
- private Action diedAction; // 死亡活动
-
- public BloodHelper(Image bloodValueImg, Text bloodRateTxt, TankInfo tankInfo, Action diedAction) {
- this.bloodValueImg = bloodValueImg;
- this.bloodRateTxt = bloodRateTxt;
- this.tankInfo = tankInfo;
- this.diedAction = diedAction;
- bloodValueImg.fillAmount = 1;
- if (bloodRateTxt != null) {
- bloodRateTxt.text = "" + tankInfo.GetFullBlood() + " / " + tankInfo.GetFullBlood();
- }
- }
-
- public bool BuckleBlood(int damage) { // 扣血
- bloodValueImg.fillAmount = tankInfo.BuckleBlood(damage);
- if (bloodRateTxt != null) {
- bloodRateTxt.text = "" + tankInfo.GetCurrBlood() + " / " + tankInfo.GetFullBlood();
- }
- bool isDying = tankInfo.IsDying();
- if (isDying) {
- diedAction.Invoke();
- }
- return isDying;
- }
-
- public void setTransform(Transform transform) {
- this.transform = transform;
- }
-
- public void BloodLookAtCamera() { // 血条朝向相机
- Vector3 cameraPos = Camera.main.transform.position;
- Vector3 target = new Vector3(cameraPos.x, transform.position.y, cameraPos.z);
- transform.LookAt(target);
- }
- }
KillHelper.cs
- using UnityEngine;
- using UnityEngine.UI;
-
- public class KillHelper {
- private Image killValueImg; // 杀敌Image
- private Text killRateTxt; // 杀敌比率Text
- private int enemiesNum; // 敌人总数
- private int currKillEnemies; // 当前杀敌数
-
- public KillHelper(int enemiesNum) {
- this.enemiesNum = enemiesNum;
- currKillEnemies = 0;
- killValueImg = GameObject.Find("UI/Kill/Progress/Value").GetComponent
(); - killRateTxt = GameObject.Find("UI/Kill/Progress/Rate").GetComponent
(); - UpdateUI();
- }
-
- public void KillEnemy() { // 杀敌
- lock(this) {
- currKillEnemies++;
- UpdateUI();
- }
- }
-
- private void UpdateUI() {
- killValueImg.fillAmount = 1.0f * currKillEnemies / enemiesNum;
- killRateTxt.text = "" + currKillEnemies + " / " + enemiesNum;
- }
- }
MoveHelper.cs
- using UnityEngine;
-
- public class MoveHelper {
- private Transform transform; // 交互对象的变换组件
- protected StickController stick; // 摇杆控制器
- private Vector3 predownMousePoint; // 鼠标右键按下时的位置
- private Vector3 currMousePoint; // 鼠标右键滑动过程中的位置
- private float moveSpeed; // 移动速度
- private float rotateSpeed; // 旋转速度
-
- public MoveHelper(Transform transform) {
- this.transform = transform;
- stick = GameObject.Find("UI/Stick/Ball").GetComponent
(); - }
-
- public void Init(float moveSpeed, float rotateSpeed) {
- this.moveSpeed = moveSpeed;
- this.rotateSpeed = rotateSpeed;
- }
-
- public void Move() { // 移动
- float hor = Input.GetAxis("Horizontal");
- float ver = Input.GetAxis("Vertical");
- Move(hor, ver);
- if (Mathf.Abs(hor) > float.Epsilon || Mathf.Abs(ver) > float.Epsilon) {
- updateStick(hor, ver);
- }
- }
-
- public void Move(float hor, float ver) { // 移动
- if (Mathf.Abs(hor) > float.Epsilon || Mathf.Abs(ver) > float.Epsilon) {
- Rigidbody rigidbody = transform.GetComponent
(); - if (rigidbody != null) {
- Vector3 vec = transform.forward * ver + transform.right * hor;
- rigidbody.velocity = vec * moveSpeed;
- } else {
- transform.Translate(new Vector3(hor, 0, ver) * Time.deltaTime * moveSpeed);
- }
- RestrictBoundary();
- }
- }
-
- public void Rotate() { // 旋转
- if (Input.GetMouseButtonDown(1)) {
- predownMousePoint = Input.mousePosition;
- } else if (Input.GetMouseButton(1)) {
- currMousePoint = Input.mousePosition;
- Vector3 vec = currMousePoint - predownMousePoint;
- Rigidbody rigidbody = transform.GetComponent
(); - if (rigidbody != null) {
- rigidbody.angularVelocity = Vector3.up * rotateSpeed * vec.x;
- } else {
- transform.Rotate(Vector3.up * vec.x * Time.deltaTime * rotateSpeed);
- }
- predownMousePoint = currMousePoint;
- }
- }
-
- private void updateStick(float hor, float ver) { // 更新摇杆
- Vector3 dire = new Vector3(hor, ver, 0);
- dire = dire.normalized * Mathf.Min(dire.magnitude, 1);
- stick.UpdateStick(dire);
- }
-
- private void RestrictBoundary() { // 限制边界
- Vector3 pos = transform.position;
- if (Mathf.Abs(pos.x) > 49) {
- transform.position = new Vector3(Mathf.Sign(pos.x) * 49, pos.y, pos.z);
- } else if (Mathf.Abs(pos.z) > 49) {
- transform.position = new Vector3(pos.x, pos.y, Mathf.Sign(pos.z) * 49);
- }
- }
- }
TankInfo.cs
- using System;
- using UnityEngine;
-
- [Serializable]
- public class TankInfo : ICloneable {
- [Header("坦克满血量")]
- [Range(30, 100)]
- public int fullBlood = 30;
-
- [Header("坦克移动速度")]
- [Range(1, 5)]
- public float tankMoveSpeed = 3f;
-
- [Header("坦克旋转速度")]
- [Range(1, 4)]
- public float tankRotateSpeed = 2f;
-
- [Header("坦克颜色")]
- public Color tankColor = Color.green;
-
- [Header("坦克初始位置")]
- public Vector3 tankInitPosition = new Vector3(0f, 0.25f, 0f);
-
- [Header("坦克初始方位")]
- public Vector3 tankInitRotation = new Vector3(0, 0, 0);
-
- [Header("炮弹信息")]
- public BulletInfo bullet;
-
- private String name = "Enemy"; // 坦克角色名
- private int currBlood = 30; // 坦克当前血量
-
- public TankInfo(String name) {
- this.name = name;
- bullet = new BulletInfo(name + "Bullet");
- }
-
- public object Clone() { // 克隆坦克
- TankInfo info = new TankInfo(this.name);
- info.fullBlood = this.fullBlood;
- info.tankMoveSpeed = this.tankMoveSpeed;
- info.tankRotateSpeed = this.tankRotateSpeed;
- info.tankColor = this.tankColor;
- info.tankInitPosition = this.tankInitPosition;
- info.tankInitRotation = this.tankInitRotation;
- info.bullet = this.bullet.Clone() as BulletInfo;
- info.SetCurrBlood(this.currBlood);
- return info;
- }
-
- public void SetCurrBlood(int blood) { // 设置当前血量
- currBlood = blood;
- }
-
- public int GetCurrBlood() { // 获取当前血量
- return currBlood;
- }
-
- public int GetFullBlood() { // 获取满血量
- return fullBlood;
- }
-
- public float BuckleBlood(int damage) { // 扣血, 返回剩余血量比例
- currBlood = Math.Max(currBlood - damage, 0);
- return 1.0f * currBlood / fullBlood;
- }
-
- public bool IsDying() {
- return currBlood == 0;
- }
-
- public String GetName() {
- return name;
- }
- }
BulletInfo.cs
- using System;
- using UnityEngine;
-
- [Serializable]
- public class BulletInfo : ICloneable {
- [Header("炮弹伤害")]
- [Range(2, 10)]
- public int bulletDamage = 2;
-
- [Header("炮弹飞行速度")]
- [Range(5, 20)]
- public int bulletSpeed = 10;
-
- [Header("炮弹冷却时间")]
- [Range(0.1f, 1.5f)]
- public float bulletCoolTime = 0.3f;
-
- [Header("炮弹射程")]
- [Range(5, 15)]
- public float bulletFireRange = 10;
-
- [Header("炮弹颜色")]
- public Color bulletColor = Color.red;
-
- private String name = "EnemyBullet"; // 炮弹名
-
- private Vector3 flyDir; // 炮弹飞行方向
-
- public BulletInfo(String name) {
- this.name = name;
- }
-
- public void SetFlyDir(Vector3 flyDir) {
- this.flyDir = flyDir;
- }
-
- public Vector3 GetFlyDir() {
- return flyDir;
- }
-
- public String GetName() {
- return name;
- }
-
- public object Clone() { // 克隆炮弹
- BulletInfo info = new BulletInfo(this.name);
- info.bulletDamage = this.bulletDamage;
- info.bulletSpeed = this.bulletSpeed;
- info.bulletCoolTime = this.bulletCoolTime;
- info.bulletFireRange = this.bulletFireRange;
- info.bulletColor = this.bulletColor;
- return info;
- }
- }
EnemiesInfo.cs
- using UnityEngine;
-
- public class EnemiesInfo {
- public const int TOTAL_NUM = 50; // 敌人总数
- public const int INIT_NUM = 10; // 敌人初始入场个数
- public const int ENTER_INTERVAL = 2; // 敌人入场时间间隔
-
- public const int LEVEL_1_WEIGHT = 3; // 一级敌人个数权重
- public const int LEVEL_2_WEIGHT = 2; // 二级敌人个数权重
- public const int LEVEL_3_WEIGHT = 1; // 三级敌人个数权重
-
- private volatile int appeardNum = 0; // 已入场的敌人数
- private volatile int currentNum = 0; // 当前敌人数
- private int totalWeight; // 总权重
-
- public EnemiesInfo() {
- totalWeight = LEVEL_1_WEIGHT + LEVEL_2_WEIGHT + LEVEL_3_WEIGHT;
- }
-
- public void CurrAdd() {
- lock(this) {
- appeardNum ++;
- currentNum ++;
- }
- }
-
- public void CurrDes() {
- lock(this) {
- currentNum --;
- }
- }
-
- public int GetRandomLevel() {
- float random = Random.Range(0f, totalWeight);
- if (random < LEVEL_1_WEIGHT) {
- return 1;
- }
- if (random < LEVEL_1_WEIGHT + LEVEL_2_WEIGHT) {
- return 2;
- }
- return 3;
- }
-
- public int GetAppeardNum() {
- return appeardNum;
- }
-
- public int GetTotalNum() {
- return TOTAL_NUM;
- }
- }
TankParamsManager.cs
- using UnityEngine;
-
- public class TankParamsManager {
- private const int MIN_ENEMY_LEVEL = 1;
- private const int MAX_ENEMY_LEVEL = 3;
- private static TankParamsManager tankParamsManager;
- private TankInfo LEVEL_0 = new TankInfo("Player"); // 玩家
- private TankInfo LEVEL_1 = new TankInfo("Enemy"); // 敌军1级
- private TankInfo LEVEL_2 = new TankInfo("Enemy"); // 敌军2级
- private TankInfo LEVEL_3 = new TankInfo("Enemy"); // 敌军3级
-
- private TankParamsManager() {
- Level0Params();
- Level1Params();
- Level2Params();
- Level3Params();
- }
-
- public static TankParamsManager GetInstance() {
- if (tankParamsManager == null) {
- tankParamsManager = new TankParamsManager();
- }
- return tankParamsManager;
- }
-
- public TankInfo GetPlayerTankInfo() {
- return LEVEL_0.Clone() as TankInfo;
- }
-
- public TankInfo GetEnemyTankInfo(int level) {
- level = Camp(level, MIN_ENEMY_LEVEL, MAX_ENEMY_LEVEL);
- switch (level) {
- case 1:
- return LEVEL_1.Clone() as TankInfo;
- case 2:
- return LEVEL_2.Clone() as TankInfo;
- case 3:
- return LEVEL_3.Clone() as TankInfo;
- }
- return LEVEL_1;
- }
-
- private void Level0Params() {
- LEVEL_0.fullBlood = 500;
- // LEVEL_0.fullBlood = 2;
- LEVEL_0.tankColor = Color.green;
- LEVEL_0.tankMoveSpeed = 4;
- LEVEL_0.tankRotateSpeed = 2;
- LEVEL_0.SetCurrBlood(LEVEL_0.fullBlood);
- LEVEL_0.bullet.bulletDamage = 10;
- LEVEL_0.bullet.bulletColor = Color.red;
- LEVEL_0.bullet.bulletCoolTime = 0.15f;
- LEVEL_0.bullet.bulletFireRange = 15;
- LEVEL_0.bullet.bulletSpeed = 10;
- }
-
- private void Level1Params() {
- LEVEL_1.fullBlood = 30;
- LEVEL_1.tankColor = Color.gray;
- LEVEL_1.tankMoveSpeed = 1;
- LEVEL_1.tankRotateSpeed = 0.85f;
- LEVEL_1.SetCurrBlood(LEVEL_1.fullBlood);
- LEVEL_1.bullet.bulletDamage = 2;
- LEVEL_1.bullet.bulletColor = Color.gray;
- LEVEL_1.bullet.bulletCoolTime = 2f;
- LEVEL_1.bullet.bulletFireRange = 10;
- LEVEL_1.bullet.bulletSpeed = 5;
- }
-
- private void Level2Params() {
- LEVEL_2.fullBlood = 40;
- LEVEL_2.tankColor = Color.cyan;
- LEVEL_2.tankMoveSpeed = 1.3f;
- LEVEL_2.tankRotateSpeed = 0.9f;
- LEVEL_2.SetCurrBlood(LEVEL_2.fullBlood);
- LEVEL_2.bullet.bulletDamage = 3;
- LEVEL_2.bullet.bulletColor = Color.gray;
- LEVEL_2.bullet.bulletCoolTime = 1.7f;
- LEVEL_2.bullet.bulletFireRange = 11;
- LEVEL_2.bullet.bulletSpeed = 6;
- }
-
- private void Level3Params() {
- LEVEL_3.fullBlood = 50;
- LEVEL_3.tankColor = Color.yellow;
- LEVEL_3.tankMoveSpeed = 1.6f;
- LEVEL_3.tankRotateSpeed = 1f;
- LEVEL_3.SetCurrBlood(LEVEL_3.fullBlood);
- LEVEL_3.bullet.bulletDamage = 4;
- LEVEL_3.bullet.bulletColor = Color.yellow;
- LEVEL_3.bullet.bulletCoolTime = 1.4f;
- LEVEL_3.bullet.bulletFireRange = 12;
- LEVEL_3.bullet.bulletSpeed = 7;
- }
-
- private int Camp(int value, int min, int max) {
- if (value > max) {
- return max;
- }
- if (value < min) {
- return min;
- }
- return value;
- }
- }
WindowController.cs
- using UnityEngine;
-
- public class WindowController : MonoBehaviour {
- private bool fullscreen = true; // 全屏
-
- private void Update () {
- if (Input.GetKeyDown(KeyCode.Escape)) {
- fullscreen = !fullscreen;
- Screen.fullScreen = fullscreen;
- }
- if (Input.GetKeyDown(KeyCode.Q)) {
- Application.Quit();
- }
- }
- }
说明:WindowController 脚本组件挂在 Window 游戏对象上。