Unity3D_(游戏)双人3D坦克_简易版

双人3D坦克实现

  

  player1: WSAD控制上下左右   空格键发射炮弹

  player2: IKJL可控制上下左右  B键发射炮弹 

  每个坦克只有100hp,子弹击中1次扣30hp,hp时时显示在坦克上

    当一辆坦克hp低于0时,游戏结束

  Main Camera聚焦两辆坦克中心点   

  游戏项目已托管到github上(里面有个32bit可执行文件)  传送门

    (官方demo 素材包有点大。。)

游戏界面

     (觉得子弹射程短,可以适当提高游戏子弹速度)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class FollowCamera : MonoBehaviour {

    public GameObject tank1;
    public GameObject tank2;
    public float size= 0.58f;

    Vector3 p;

    // Use this for initialization
    void Start () {
        Vector3 target=(tank1.transform.position + tank2.transform.position) / 2;
        p = target - transform.position;
     }
    
    // Update is called once per frame
    void Update () {
        if (tank2 != null&&tank1!=null)
        {
            //计算出两个坦克之间的距离
            transform.position = (tank1.transform.position + tank2.transform.position) / 2 - p;

            //找到两个坦克的中点
            //让摄像机对准中心点
            //根据两点之间的距离,调整摄像机的尺寸
            float distance = Vector3.Distance(tank1.transform.position, tank2.transform.position);
            GetComponent<Camera>().orthographicSize = distance * size + 2f;
        }

        if(tank2 == null || tank1 == null)
        {
            SceneManager.LoadScene("SampleScene");
        }

    }
}
FollowCamera.cs 初始化游戏脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TankHealth : MonoBehaviour {

    public int hp = 100;
    public GameObject ex;
    public Slider slider;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }

    public void TakeDamage()
    {
        hp -= 30;
        if (hp < 0)
        {
            Destroy(gameObject);
            GameObject go = Instantiate(ex, transform.position, transform.rotation);
        }
        slider.value = hp;

    }

}
TankHealth.cs 坦克血量脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DestroyForTime : MonoBehaviour {

    // Use this for initialization
    void Start () {
        Destroy(gameObject,2);
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}
DestroyForTime.cs 粒子动画销毁脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shell : MonoBehaviour {

    public GameObject ex;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }

    private void OnCollisionEnter(Collision collision)
    {
        Destroy(gameObject);
        GameObject go = Instantiate(ex,transform.position,transform.rotation);
        //判断是否打中坦克
        if(collision.gameObject.tag == "Tank")
        {
            collision.gameObject.GetComponent<TankHealth>().TakeDamage();
        }
        //扣除坦克的血量

    }
}
Shell.cs 判断是否打中坦克脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shoot : MonoBehaviour {

    public GameObject shell;
    Transform pos;

    public KeyCode key = KeyCode.Space;

    public float speed = 180;

    // Use this for initialization
    void Start () {
        //找到子对象
        pos = transform.Find("FirstPosition");
    }
    
    // Update is called once per frame
    void Update () {
        //按下一个按键
        if (Input.GetKeyDown(key))
        {
            GameObject go = Instantiate(shell,pos.position,pos.rotation);
            go.GetComponent<Rigidbody>().velocity = go.transform.forward * speed;
            //go.GetComponent<Rigidbody>().velocity = Vector3.forward * speed;
        }
    }
}
Shoot.cs 子弹轨迹脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement : MonoBehaviour {

    public float speed = 10;
    public float angularSpeed = 5;

    public string player = "1";

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        //获得玩家的键盘输入
        float v = Input.GetAxis("Vertical"+player);
        float h = Input.GetAxis("Horizontal"+ player);
       
        //让坦克前后移动
        GetComponent<Rigidbody>().velocity = transform.forward * v * speed;
        GetComponent<Rigidbody>().angularVelocity = transform.up * h * angularSpeed;

    }
}
Movement.cs 控制坦克方向脚本

实现过程

  

创建场景

  导入坦克资源场景

  

  

    Lightmapping光照贴图技术是一种增强静态场景光照效果的技术,其优点是可以通过较少的性能消耗使静态场景看上去更加真实,丰富,更加具有立体感;缺点是不能用来实时地处理动态光照。当游戏场景包含了大量的多边形时,实时光源和阴影对游戏的性能的影响会很大。这时使用Lightmapping技术,将光线效果预渲染成贴图使用到多边形上模拟光影效果。
光照贴图

  加载光照贴图有时候会造成场景卡顿

    Auto Generate  :设置成不自动生成

    Generate Lighting  :生成一次场景光照

坦克的前后移动

  添加坦克预设体进入游戏场景,DustTrail粒子特效预设体放到坦克上

  (GameObject ->Align  With View 将Game视图对准当前Scene视图)

  给坦克添加碰撞器和刚体

  (碰撞器慢慢移,拖动数值调整到刚好包围完坦克)

  添加移动坦克脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement : MonoBehaviour {

    public float speed = 5;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {

        //获得玩家的键盘输入
        float v = Input.GetAxis("Vertical");
        //让坦克前后移动
        GetComponent<Rigidbody>().velocity = transform.forward * v * speed;


    }
}
Movement.cs

  设置坦克移动速度

  public float speed = 5;

  获得玩家的键盘输入

float v = Input.GetAxis("Vertical");

  让坦克前后移动

GetComponent<Rigidbody>().velocity = transform.forward * v * speed;

  (将相机放到坦克里面,实现相机和坦克一起移动)

坦克的旋转

  查看Unity输入按键值

  水平移动:Vertical

  左右移动:Horizontal

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement : MonoBehaviour {

    public float speed = 10;
    public float angularSpeed = 5;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        //获得玩家的键盘输入
        float v = Input.GetAxis("Vertical");
        float h = Input.GetAxis("Horizontal");
       
        //让坦克前后移动
        GetComponent<Rigidbody>().velocity = transform.forward * v * speed;
        GetComponent<Rigidbody>().angularVelocity = transform.up * h * angularSpeed;

    }
}
Movement.cs

  设置坦克移动转动角速度

  public float angularSpeed = 5;

  获得玩家的键盘输入

 float h = Input.GetAxis("Horizontal");

  让坦克前后移动

GetComponent<Rigidbody>().angularVelocity = transform.up * h * angularSpeed;

  为实现双人坦克效果,提高按键灵活性,在InputManager管理器中添加两个Axes

  修改Axes值Horizontal1、Horizontal2、Vertical1、Vertical2

    

我把玩家二上下左右WSAD按键修改为IKJL,实现双人笑游戏效果

  默认角色是1号玩家

       public string player = "1";

        //获得玩家的键盘输入
        float v = Input.GetAxis("Vertical"+player);
        float h = Input.GetAxis("Horizontal"+ player);
           

  新建双人坦克修改Player值

坦克子弹

  给子弹添加刚体和碰撞器

  (将子弹设置为预设体,保存到Gary文件夹中)

  给坦克添加一个空物体,每次坦克都是从这个点动态生成子弹发射出去的

  添加Shoot脚本,挂载到坦克物体上

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shoot : MonoBehaviour {

    public GameObject shell;
    Transform pos;

    // Use this for initialization
    void Start () {
        //找到子对象
        pos = transform.Find("FirstPosition");
    }
    
    // Update is called once per frame
    void Update () {
        //按下一个按键
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //发射子弹 实例化
            Instantiate(shell,pos.position,pos.rotation);
        }
     

    }
}
Shoot.cs

  引用子弹实例化

 public GameObject shell;

  找到子弹发射的位置

 pos = transform.Find("FirstPosition");

  按下一个按键,,将子弹实例化

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Instantiate(shell,pos.position,pos.rotation);
        }

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shoot : MonoBehaviour {

    public GameObject shell;
    Transform pos;

    public KeyCode key = KeyCode.Space;

    // Use this for initialization
    void Start () {
        //找到子对象
        pos = transform.Find("FirstPosition");
    }
    
    // Update is called once per frame
    void Update () {
        //按下一个按键
        if (Input.GetKeyDown(key))
        {
            Instantiate(shell,pos.position,pos.rotation);
        }

    }
}
Shoot.cs

  在外添加一个key,按任意键可以射出子弹

     public KeyCode key = KeyCode.Space;

        //按下一个按键
        if (Input.GetKeyDown(key))
        {
            Instantiate(shell,pos.position,pos.rotation);
        }    

  定义子弹发射速度

 public float speed = 180;

  按下一个按键,子弹发射出去

        if (Input.GetKeyDown(key))
        {
            GameObject go = Instantiate(shell,pos.position,pos.rotation);
            go.GetComponent<Rigidbody>().velocity = go.transform.forward * speed;
            go.GetComponent<Rigidbody>().velocity = Vector3.forward * speed;
        }

子弹爆炸动画

  添加脚本shell,挂载到子弹物体对象上

    private void OnCollisionEnter(Collision collision)
    {
        Destroy(gameObject);
    }

  当子弹碰到刚体时销毁自己

  添加子弹碰到物体触发爆炸效果

  引用粒子特效

public GameObject ex;
   private void OnCollisionEnter(Collision collision)
    {
        Destroy(gameObject);
        GameObject go = Instantiate(ex,transform.position,transform.rotation);
    }

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shell : MonoBehaviour {

    public GameObject ex;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }

    private void OnCollisionEnter(Collision collision)
    {
        Destroy(gameObject);
        GameObject go = Instantiate(ex,transform.position,transform.rotation);
    }
}
Shell.cs

子弹血量的减少

  给坦克添加标签

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TankHealth : MonoBehaviour {

    public int hp = 100;
    public GameObject ex;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }

     public void TakeDamage()
    {
        hp -= 30;
        if (hp < 0)
        {
            Destroy(gameObject);
            GameObject go = Instantiate(ex, transform.position, transform.rotation);
        }
    }

}
View Code

  初始化血量hp=100

 public int hp = 100;

  设置坦克爆炸粒子效果

  public GameObject ex;

  当血量低于0时,坦克销毁,爆炸粒子效果出现

    public void TakeDamage()
    {
        hp -= 30;
        if (hp < 0)
        {
            Destroy(gameObject);
            GameObject go = Instantiate(ex, transform.position, transform.rotation);
        }
    }

相机跟随

  将照相机改为正交

  在摄像机中添加并挂载FollowCameral脚本

  两个坦克的引用

    public GameObject tank1;
    public GameObject tank2;

  两个坦克之间的中点

    Vector3 p;

   Vector3 target=(tank1.transform.position + tank2.transform.position) / 2;
    p = target - transform.position;

  计算出两个坦克之间的距离

 transform .position= (tank1.transform.position + tank2.transform.position) / 2 - p;

  找到两个坦克的中点并让摄像机对准中心点,根据两点之间的距离,调整摄像机的尺寸

        float distance = Vector3.Distance(tank1.transform.position,tank2.transform.position);
        GetComponent<Camera>().orthographicSize = distance * size+ 2f;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowCamera : MonoBehaviour {

    public GameObject tank1;
    public GameObject tank2;
    public float size= 0.58f;

    Vector3 p;

    // Use this for initialization
    void Start () {
        Vector3 target=(tank1.transform.position + tank2.transform.position) / 2;
        p = target - transform.position;
     }
    
    // Update is called once per frame
    void Update () {
        //计算出两个坦克之间的距离
        transform .position= (tank1.transform.position + tank2.transform.position) / 2 - p;

        //找到两个坦克的中点
        //让摄像机对准中心点
        //根据两点之间的距离,调整摄像机的尺寸
        float distance = Vector3.Distance(tank1.transform.position,tank2.transform.position);
        GetComponent<Camera>().orthographicSize = distance * size+ 2f;


    }
}
FollowCamera.cs

添加音效

  在Main Camera上绑定Audio Source音乐播放器

血条

  创建一个Slider,把Canvas移动到坦克上

  设置Slider控件的 PosX=0 PosX=0 PosZ=0

  参数下如下配置

 

  设置完成后效果如下

  设置成垂直

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TankHealth : MonoBehaviour {

    public int hp = 100;
    public GameObject ex;
    public Slider slider;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }

    public void TakeDamage()
    {
        hp -= 30;
        if (hp < 0)
        {
            Destroy(gameObject);
            GameObject go = Instantiate(ex, transform.position, transform.rotation);
        }
        slider.value = hp;

    }

}
TankHealth.cs

  添加Slider控件

 public Slider slider;

  坦克攻击时,时时刷新slider.value值

    public void TakeDamage()
    {
        hp -= 30;
        if (hp < 0)
        {
            Destroy(gameObject);
            GameObject go = Instantiate(ex, transform.position, transform.rotation);
        }
        slider.value = hp;

    }

完结!

(如需转载学习,请标明出处)
原文地址:https://www.cnblogs.com/1138720556Gary/p/9541955.html