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) / ;
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坦克_简易版的更多相关文章
- Unity3D_(游戏)2D坦克大战 像素版
2D坦克大战 像素版 游戏规则: 玩家通过上.下.左.右移动坦克,空格键发射子弹 敌人AI出身时朝向己方大本营(未防止游戏快速结束,心脏上方三个单位障碍物设为刚体) 当玩家被击杀次数>=3 ...
- 3D坦克大战游戏源码
3D坦克大战游戏源码,该游戏是基于xcode 4.3,ios sdk 5.1开发.在xcode4.3.3上完美无报错.兼容ios4.3-ios6.0 ,一款ios平台上难得的3D坦克大战游戏源码,有2 ...
- html5 canvas简易版捕鱼达人游戏源码
插件描述:html5利用canvas写的一个js版本的捕鱼,有积分统计,鱼可以全方位移动,炮会跟着鼠标移动,第一次打开需要鼠标移出背景图,再移入的时候就可以控制炮的转动,因为是用的mouseover触 ...
- 3D坦克大战游戏iOS源码
3D坦克大战游戏源码,该游戏是基于xcode 4.3,ios sdk 5.1开发.在xcode4.3.3上完美无报错.兼容ios4.3-ios6.0 ,一款ios平台上难得的3D坦克大战游戏源码,有2 ...
- 自定义View4-塔防小游戏第一篇:一个防御塔+多个野怪(简易版)*
塔防小游戏 第一篇:一个防御塔+多个野怪(简易版) 1.canvas画防御塔,妖怪大道,妖怪行走路线 2.防御塔攻击范围是按照妖怪与防御塔中心距离计算的,大于防御塔半径则不攻击,小于则攻击 ...
- Unity破窗游戏制作(简易版)
Unity破窗游戏制作(简易版) 参考:"对不起,我选择摸鱼"-<扫雷>小游戏开发实战,算法.源代码,基于Unity3D开发 - 掘金 (juejin.cn) 到&qu ...
- C+命令行+方向键=简易版扫雷
前言: 想起来做这个是因为那时候某天知道了原来黑框框里面的光标是可以控制的,而且又经常听人说起这个,就锻炼一下好了. 之前就完成了那1.0的版本,现在想放上来分享却发现有蛮多问题的,而且最重要的是没什 ...
- Android学习之路——简易版微信为例(一)
这是“Android学习之路”系列文章的开篇,可能会让大家有些失望——这篇文章中我们不介绍简易版微信的实现(不过不是标题党哦,我会在后续博文中一步步实现这个应用程序的).这里主要是和广大园友们聊聊一个 ...
- DI 原理解析 并实现一个简易版 DI 容器
本文基于自身理解进行输出,目的在于交流学习,如有不对,还望各位看官指出. DI DI-Dependency Injection,即"依赖注入":对象之间依赖关系由容器在运行期决定, ...
随机推荐
- # 数字签名&数字证书
目录 数字签名&数字证书 数字签名 数字证书 数字证书的实例(https协议) 数字签名&数字证书 参考资料: 数字签名是什么?-阮一峰的网络日志 数字签名和数字证书究竟是什么?知乎- ...
- 从入门到自闭之Python内置函数
内置函数一 eval:执行字符串类型的代码 exac:执行字符串社类型的代码 eval与exac 禁止使用 hash()作用就是区分可变数据类型与不可变数据类型 # print(hash(" ...
- python并发编程-进程间通信-Queue队列使用-生产者消费者模型-线程理论-创建及对象属性方法-线程互斥锁-守护线程-02
目录 进程补充 进程通信前言 Queue队列的基本使用 通过Queue队列实现进程间通信(IPC机制) 生产者消费者模型 以做包子买包子为例实现当包子卖完了停止消费行为 线程 什么是线程 为什么要有线 ...
- MySQL中的SQL的常见优化策略
MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 1 避免全表扫描对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索 ...
- maven引用本地jar,并打包部署
由于项目需要的一个jar在maven仓库里没有,又不想把jar手动导入仓库.然而百度的几个处理方式都是一样的方法,我却没有一个成功的.于是就请教了大神,大神也是各种测试,终于成功实现了,实现如下: 新 ...
- Charles学习(二)之使用Map local代理本地静态资源以及配置网页代理在Mac浏览器上调试移动端
前言 我们在开发的过程肯定是一边写代码,一边查看自己的代码写的是否存在问题,那么问题来了,有两种情况 情况一:我们可以本地起服务,那么我们就可以在本地检查自己的代码,查看运行结果 情况二:本地无法起服 ...
- snappy-java两种压缩方式的区别
1.Snappy-java项目地址 https://github.com/xerial/snappy-java 2.Snappy-java两种压缩方式 使用Snappy.compress进行压缩 St ...
- HTML5的新变化
1.新的html5文件类型,仅需申明在html的第一行,即 <!DOCTYPE html> 2.图形元素 figure ,将<figure>与<figcaption> ...
- html基础知识(总结自www.runoob.com)
HTML属性 属性 描述 class 为html元素定义一个或多个类名(classname)(类名从样式文件引入) id 定义元素的唯一id style 规定元素的行内样式(inline style) ...
- 用SVM处理XSS时,数据清洗打标数据标准化处理的方法和意义
def get_len(url): return len(url) def get_url_count(url): if re.search('(http://)|(https://)', url, ...