双人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) / ;
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) / - 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 = ;
public GameObject ex;
public Slider slider; // Use this for initialization
void Start () { } // Update is called once per frame
void Update () { } public void TakeDamage()
{
hp -= ;
if (hp < )
{
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,);
} // 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 = ; // 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 = ;
public float angularSpeed = ; public string player = ""; // 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 = ; // 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 = ;

  获得玩家的键盘输入

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 = ;
public float angularSpeed = ; // 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 = ;

  获得玩家的键盘输入

 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 = "";

        //获得玩家的键盘输入
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 = ;

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

        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 = ;
public GameObject ex; // Use this for initialization
void Start () { } // Update is called once per frame
void Update () { } public void TakeDamage()
{
hp -= ;
if (hp < )
{
Destroy(gameObject);
GameObject go = Instantiate(ex, transform.position, transform.rotation);
}
} }

  初始化血量hp=100

 public int hp = ;

  设置坦克爆炸粒子效果

  public GameObject ex;

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

    public void TakeDamage()
{
hp -= ;
if (hp < )
{
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) / ;
p = target - transform.position;

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

 transform .position= (tank1.transform.position + tank2.transform.position) /  - 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) / ;
p = target - transform.position;
} // Update is called once per frame
void Update () {
//计算出两个坦克之间的距离
transform .position= (tank1.transform.position + tank2.transform.position) / - 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 = ;
public GameObject ex;
public Slider slider; // Use this for initialization
void Start () { } // Update is called once per frame
void Update () { } public void TakeDamage()
{
hp -= ;
if (hp < )
{
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 -= ;
if (hp < )
{
Destroy(gameObject);
GameObject go = Instantiate(ex, transform.position, transform.rotation);
}
slider.value = hp; }

完结!

Unity3D_(游戏)双人3D坦克_简易版的更多相关文章

  1. Unity3D_(游戏)2D坦克大战 像素版

    2D坦克大战    像素版 游戏规则: 玩家通过上.下.左.右移动坦克,空格键发射子弹 敌人AI出身时朝向己方大本营(未防止游戏快速结束,心脏上方三个单位障碍物设为刚体) 当玩家被击杀次数>=3 ...

  2. 3D坦克大战游戏源码

    3D坦克大战游戏源码,该游戏是基于xcode 4.3,ios sdk 5.1开发.在xcode4.3.3上完美无报错.兼容ios4.3-ios6.0 ,一款ios平台上难得的3D坦克大战游戏源码,有2 ...

  3. html5 canvas简易版捕鱼达人游戏源码

    插件描述:html5利用canvas写的一个js版本的捕鱼,有积分统计,鱼可以全方位移动,炮会跟着鼠标移动,第一次打开需要鼠标移出背景图,再移入的时候就可以控制炮的转动,因为是用的mouseover触 ...

  4. 3D坦克大战游戏iOS源码

    3D坦克大战游戏源码,该游戏是基于xcode 4.3,ios sdk 5.1开发.在xcode4.3.3上完美无报错.兼容ios4.3-ios6.0 ,一款ios平台上难得的3D坦克大战游戏源码,有2 ...

  5. 自定义View4-塔防小游戏第一篇:一个防御塔+多个野怪(简易版)*

    塔防小游戏 第一篇:一个防御塔+多个野怪(简易版)    1.canvas画防御塔,妖怪大道,妖怪行走路线    2.防御塔攻击范围是按照妖怪与防御塔中心距离计算的,大于防御塔半径则不攻击,小于则攻击 ...

  6. Unity破窗游戏制作(简易版)

    Unity破窗游戏制作(简易版) 参考:"对不起,我选择摸鱼"-<扫雷>小游戏开发实战,算法.源代码,基于Unity3D开发 - 掘金 (juejin.cn) 到&qu ...

  7. C+命令行+方向键=简易版扫雷

    前言: 想起来做这个是因为那时候某天知道了原来黑框框里面的光标是可以控制的,而且又经常听人说起这个,就锻炼一下好了. 之前就完成了那1.0的版本,现在想放上来分享却发现有蛮多问题的,而且最重要的是没什 ...

  8. Android学习之路——简易版微信为例(一)

    这是“Android学习之路”系列文章的开篇,可能会让大家有些失望——这篇文章中我们不介绍简易版微信的实现(不过不是标题党哦,我会在后续博文中一步步实现这个应用程序的).这里主要是和广大园友们聊聊一个 ...

  9. DI 原理解析 并实现一个简易版 DI 容器

    本文基于自身理解进行输出,目的在于交流学习,如有不对,还望各位看官指出. DI DI-Dependency Injection,即"依赖注入":对象之间依赖关系由容器在运行期决定, ...

随机推荐

  1. CentOS 7 yum安装LAMP,LNMP并搭建WordPress个人博客网站

    本次实验要进行的是在CentOS7.2,内核版本3.10.0-327.el7.x86_64的环境下搭建LAMP和LNMP,并在此之上做一个WordPress博客网站. [root@Shining ~] ...

  2. idea 修改pom文件jdk版本回退问题解决

    在Java开发是我们大多都使用集成开发环境,像idea和eclipse用的都比较多,在使用idea maven构建项目时,在修改pom.xml文件时,我们的项目jdk版本都会回退,还得每次去设置中修改 ...

  3. EBS自动行号,行金额自动汇总到头,金额根据币种编号总结

    一.自动行号实现 1.方法一: 只需要将“序号”定义成公式,并将公式设置为:get_block_property('block_name',current_record)就可以实现了,或者把这行语句放 ...

  4. 无线传输模块HC-12

    无线传输模块HC-12使用 因为实验室的无人机需要使用一款无线传输模块进行遥控控制,我们讨论的中测试了HC-12,并对HC-12传输距离进行了简单测试.在此做下使用记录. 模块概述 HC-12 无线串 ...

  5. host文件介绍

    默认位置为%SystemRoot%\system32\drivers\etc\,但也可以改变. 动态目录由注册表键\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSe ...

  6. Can you answer these queries? HDU - 4027 (线段树,区间开平方,区间求和)

    A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use ...

  7. .htaccess防盗链方法(文件、图片)

    http标准协议中有专门的字段记录referer,一来可以追溯上一个入站地址是什么,二来对于资源文件,可以跟踪到包含显示他的网页地址是什么. 因此所有防盗链方法都是基于这个Referer字段两种方法: ...

  8. kotlin高阶函数实战&DSL入门

    传统函数演示: 这里以电视节目“非诚勿扰”为例,男人去从一大堆美女当中挑选出自己中意的对象,比如台上有24位妹子,其档案如下: 接下来第一个男嘉宾出场啦,如下: 下面用代码来实现一下,比较简单: 先定 ...

  9. 【hdu 6067】Big Integer

    题意 给你一个 \((k-1)\times (n+1)\) 的 \(01\) 矩阵 \(g\),求满足下列条件的 \(k(k\le 10)\) 进制整数的数量: 1. 不超过 \(n\) 位且数的最高 ...

  10. Codeforces 837E Vasya's Function 数论 找规律

    题意:定义F(a,0) = 0,F(a,b) = 1 + F(a,b - GCD(a,b).给定 x 和 y (<=1e12)求F(x,y). 题解:a=A*GCD(a,b) b=B*GCD(a ...