1 需求实现

1)需求实现

  • 鼠标拖拽摇杆球控制坦克移动;
  • 上下左右按键也可以控制坦克移动,并且摇杆球也同步移动;
  • 鼠标右键滑动,控制坦克转向;
  • 相机在玩家后上方的位置,始终跟随玩家,朝玩家正前方看;
  • 单击鼠标左键或按空格键控制坦克发射炮弹。

2)涉及技术栈

​ 本文代码资源见 → Unity3D 摇杆控制物体运动

2 游戏对象

1)游戏界面

2)游戏对象层级结构

3)Transform组件参数

​ 1. 玩家 Transform 组件参数

Name Type Position Rotation Scale Color/Texture
Player Empty (0, 0.25, -5) (0, 0, 0) (1, 1, 1) #228439FF
Botton Cube (0, 0, 0) (0, 0, 0) (2, 0.5, 2) #228439FF
Top Cube (0, 0.5, 0) (0, 0, 0) (1, 0.5, 1) #228439FF
Gun Cylinder (0, 0, 1.5) (90, 0, 0) (0.2, 1, 0.4) #228439FF
FirePoint Empty (0, 1.15, 0) (0, 0, 0) (1, 1, 1) ——

​ 补充:Player 游戏对象添加了刚体组件。

​ 2. 地面和炮弹 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

​ 补充:炮弹作为预设体拖拽到 Assets/Resources/Prefabs 目录下,并且添加了刚体组件。

​ 3. 摇杆 RectTransform 组件参数

Name Type Width/Height Pos Anchors
Stick Canvas —— —— ——
Background Image (100, 100) (75, 75, 0) (0, 0), (0, 0)
Ball Image (40, 40) (75, 75, 0) (0, 0), (0, 0)

3 脚本组件

1)CameraController

​ CameraController.cs

using UnityEngine;

public class CameraController : MonoBehaviour {
private Transform player; // 玩家
private Vector3 relaPlayerPos; // 相机在玩家坐标系中的位置
private float targetDistance = 15f; // 相机看向玩家前方的位置 private void Start() {
relaPlayerPos = new Vector3(0, 4, -8);
player = GameObject.Find("Player/Top").transform;
} private void LateUpdate() {
CompCameraPos();
} private void CompCameraPos() { // 计算相机坐标
Vector3 target = player.position + player.forward * targetDistance;
transform.position = transformVecter(relaPlayerPos, player.position, player.right, player.up, player.forward);
transform.rotation = Quaternion.LookRotation(target - transform.position);
} // 求以origin为原点, locX, locY, locZ 为坐标轴的本地坐标系中的向量 vec 在世界坐标系中对应的向量
private Vector3 transformVecter(Vector3 vec, Vector3 origin, Vector3 locX, Vector3 locY, Vector3 locZ) {
return vec.x * locX + vec.y * locY + vec.z * locZ + origin;
}
}

​ 说明: CameraController 脚本组件挂在 MainCamera 游戏对象上。

2)PlayerController

​ PlayerController.cs

using System;
using UnityEngine; public class PlayerController : MonoBehaviour {
private Transform firePoint; // 开火点
private GameObject bulletPrefab; // 炮弹预设体
private StickController stick; // 摇杆控制器
private float tankMoveSpeed = 4f; // 坦克移动速度
private float tankRotateSpeed = 2f; // 坦克转向速度
private Vector3 predownMousePoint; // 鼠标按下时的位置
private Vector3 currMousePoint; // 当前鼠标位置
private float fireWaitTime = float.MaxValue; // 距离上次开火已等待的时间
private float bulletCoolTime = 0.15f; // 炮弹冷却时间 private void Start() {
firePoint = transform.Find("Top/Gun/FirePoint");
bulletPrefab = (GameObject) Resources.Load("Prefabs/Bullet");
stick = GameObject.Find("Stick/Ball").GetComponent<StickController>();
} private void Update() {
Move();
Rotate();
Fire();
} private void Move() { // 坦克移动
float hor = Input.GetAxis("Horizontal");
float ver = Input.GetAxis("Vertical");
Move(hor, ver);
} public void Move(float hor, float ver) { // 坦克移动
if (Mathf.Abs(hor) > float.Epsilon || Mathf.Abs(ver) > float.Epsilon) {
Vector3 vec = transform.forward * ver + transform.right * hor;
GetComponent<Rigidbody>().velocity = vec * tankMoveSpeed;
// stick.UpdateStick(new Vector3(hor, 0, ver));
Vector3 dire = new Vector3(hor, ver, 0);
dire = dire.normalized * Mathf.Min(dire.magnitude, 1);
stick.UpdateStick(dire);
}
} private void Rotate() { // 坦克旋转
if (Input.GetMouseButtonDown(1)) {
predownMousePoint = Input.mousePosition;
} else if (Input.GetMouseButton(1)) {
currMousePoint = Input.mousePosition;
Vector3 vec = currMousePoint - predownMousePoint;
GetComponent<Rigidbody>().angularVelocity = Vector3.up * tankRotateSpeed * vec.x;
predownMousePoint = currMousePoint;
}
} private void Fire() { // 坦克开炮
fireWaitTime += Time.deltaTime;
if (Input.GetMouseButtonDown(0) && !IsMouseInUIArea() || Input.GetKeyDown(KeyCode.Space)) {
if (fireWaitTime > bulletCoolTime) {
BulletInfo bulletInfo = new BulletInfo("PlayerBullet", Color.red, transform.forward, 10f, 15f);
GameObject bullet = Instantiate(bulletPrefab, firePoint.position, Quaternion.identity);
bullet.AddComponent<BulletController>().SetBulletInfo(bulletInfo);
fireWaitTime = 0f;
}
}
} private bool IsMouseInUIArea() { // 鼠标在UI控件区域
Vector3 pos = Input.mousePosition;
return pos.x < 150 && pos.y < 150;
}
}

​ 说明: PlayerController 脚本组件挂在 Player 游戏对象上。

3)StickController

​ StickController.cs

using UnityEngine;
using UnityEngine.UI;
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<PlayerController>();
} private void Update () {
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;
}
}

​ 说明: StickController 脚本组件挂在 Ball 游戏对象上。

4)BulletController

​ BulletController.cs

using UnityEngine;
using UnityEngine.UI; public class BulletController : MonoBehaviour {
private BulletInfo bulletInfo; // 炮弹信息 private void Start () {
gameObject.name = bulletInfo.name;
GetComponent<MeshRenderer>().material.color = bulletInfo.color;
float lifeTime = bulletInfo.fireRange / bulletInfo.speed; // 存活时间
Destroy(gameObject, lifeTime);
} private void Update () {
transform.GetComponent<Rigidbody>().velocity = bulletInfo.flyDir * bulletInfo.speed;
} public void SetBulletInfo(BulletInfo bulletInfo) {
this.bulletInfo = bulletInfo;
}
}

​ 说明: BulletController 脚本组件挂在 Bullet 游戏对象上(代码里动态添加)。

5)BulletInfo

​ BulletInfo.cs

using UnityEngine;

public class BulletInfo {
public string name; // 炮弹名
public Color color; // 炮弹颜色
public Vector3 flyDir; // 炮弹飞出方向
public float speed; // 炮弹飞行速度
public float fireRange; // 炮弹射程 public BulletInfo(string name, Color color, Vector3 flyDir, float speed, float fireRange) {
this.name = name;
this.color = color;
this.flyDir = flyDir;
this.speed = speed;
this.fireRange = fireRange;
}
}

4 运行效果

​ 声明:本文转自【Unity3D】摇杆

【Unity3D】摇杆的更多相关文章

  1. Unity3d 摇杆奖励

    单个单元: publicclass RockerSingle : MonoBehaviour { // 枚举.类别 RockerType  rockerType; //是否有效,最上面的为无效,即为f ...

  2. [Unity3D]Unity3D游戏开发之使用EasyTouch虚拟摇杆控制人物移动

    大家好,欢迎大家关注我的博客,我是秦元培,我的博客地址是blog.csdn.net/qinyuanpei.今天呢,我们来一起学习在Unity3D中使用EasyTouch虚拟摇杆来控制人物移动.虽然Un ...

  3. Unity3D学习(三):利用NGUI实现一个简单的左右摇杆

    前言 小游戏Konster在测试的时候有热心玩家反馈左右移动手感不是很好,最主要的问题是:手指一旦按在手机屏幕的一个方向按钮上,向反方向滑动到另一个方向按钮上是不会改变玩家移动方向的. 具体如下图: ...

  4. Unity3d项目入门之虚拟摇杆

    Unity本身不提供摇杆的组件,开发者可以使用牛逼的EasyTouch插件或者应用NGUI实现相关的需求,下面本文通过Unity自身的UGUI属性,实现虚拟摇杆的功能. 主参考 <Unity:使 ...

  5. 【转载】Unity3D研究院之IOS自定义游戏摇杆与飞机平滑的移动

    移动开发游戏中使用到的触摸游戏摇杆在iPhone上是非常普遍的,毕竟是全触摸屏手机,今天MOMO 通过一个小例子和大家讨论Unity3D 中如何自定义一个漂亮的全触摸游戏摇杆.        值得高兴 ...

  6. Unity3D 摄像机的Transform通过摇杆输出的方向

    要解决的问题是:摄像机的方向不固定,当摇杆向前(0,1)推时,主角要往摄像机的朝向(忽略Y方向)走,当摇杆往右(1,0)推的时,主角朝摄像机的右方向 /// <summary> /// 摄 ...

  7. Unity3D学习笔记(二十三):事件接口、虚拟摇杆、层级管理和背包系统

    事件接口 IDragHandler(常用):鼠标按下拖动时执行(只要鼠标在拖动就一直执行) IDropHandler:对象拖动结束时,如果鼠标在物体的范围内,执行一次(依赖于IDragHandler存 ...

  8. unity3d easytouch计算摇杆旋转角度以及摇杆八方向控制角色

    在写第三人称控制的时候,一开始在电脑测试是用WASD控制角色 后来需要发布到手机上,于是就加了一个摇杆 键盘控制角色的代码已经写好了,角色八方向移动 如果按照传统的大众思路来控制的话,是达不到我想要的 ...

  9. 【转】Unity3D学习日记(二)使用UGUI制作虚拟摇杆控制摄像机

    http://blog.csdn.net/begonia__z/article/details/51178907 前天撸了一个简单的UGUI虚拟摇杆,今天我就利用前天做的虚拟摇杆做了一个简单的摄像机控 ...

  10. 【转】Unity3D学习日记(一)使用UGUI制作虚拟摇杆

    http://blog.csdn.net/begonia__z/article/details/51170059 如今手机游戏玩法多种多样,尤其使用虚拟摇杆进行格斗类游戏开发或者是MMORPG成为了主 ...

随机推荐

  1. Metastability 亚稳态问题

    亚稳态问题 各种跨时钟域的问题都会归结于亚稳态的问题,IP设计时钟域不超过两个,对于CDC设计要求不高;对于SoC设计来说,CDC处理十分重要 1.什么是亚稳态? transition time 是可 ...

  2. Go-单元测试-Test

    单元测试 文件名以 _test.go 结尾 函数名以 Test 开头 函数参数固定 t *testing.T 运行单元测试 go test Demo 源文件 package unit import & ...

  3. ONVIF网络摄像头(IPC)客户端开发—ONVIF介绍

    ​ 1.前言: 网上已经有很多关于ONVIF开发的资料,这里概括介绍一下ONVIF协议以及介绍一下我自己在开发ONVIF网络摄像头的一些流程和经验,做个开发记录和经验总结,以备将来查看,也可供他人参考 ...

  4. [转帖]如何修改Bash Shell的提示符的格式和配色

    https://zhuanlan.zhihu.com/p/348416919 我们大多数使用的shell提示符,显示用户名.主机名和当前所在目录.在本文将会介绍如何定制一个自己喜欢的Bash. 了解B ...

  5. [转帖]SQL Server高级进阶之索引碎片维护

    https://www.cnblogs.com/atomy/p/15268589.html 一.产生原因及影响 索引是数据库引擎中针对表(有时候也针对视图)建立的特别数据结构,用来帮助查找和整理数据, ...

  6. [转帖]Region is unavailable的排查总结

    https://tidb.net/blog/07c99ed0#4%C2%A0%20%E4%B8%80%E4%BA%9B%E5%BB%BA%E8%AE%AE 1 region访问基本流程 tidb在访问 ...

  7. [转帖]Python基础之文件处理(二)

    https://www.jianshu.com/p/7dd08066f499 Python基础文件处理 python系列文档都是基于python3 一.字符编码 在python2默认编码是ASCII, ...

  8. [转帖]总结:记一次K8S容器OOM案例

    一.背景 最近遇到个现象,hubble-api-open组件过段时间会内容占满,从而被K8S强制重启. 让我困惑的是,已经设置了-XX:MaxRAMPercentage=75.0,我觉得留有了一定的空 ...

  9. [转帖]Strace + pstack发现耗时点

    https://www.jianshu.com/p/10ea6fff562c 如何使用strace+pstack利器分析程序性能 本文摘抄自如何使用strace+pstack利器分析程序性能 程序说明 ...

  10. [转帖] Linux命令拾遗-剖析工具

    https://www.cnblogs.com/codelogs/p/16060472.html 简介# 这是Linux命令拾遗系列的第五篇,本篇主要介绍Linux中常用的线程与内存剖析工具,以及更高 ...