文章目录

  • 一、前言
  • 二、实现方案
    • 1、无主之地,第一人称视角
    • 2、我之前做的摇杆控制
    • 3、第一人称视角 + 摇杆控制
  • 三、开始实战
    • 1、资源获取:Unity AssetStore
    • 2、Low Poly FPS Pack资源运行效果
    • 3、制作UI界面
      • 3.1、UI素材获取
      • 3.2、创建UI摄像机:UICamera
      • 3.3、创建UI画布:Canvas
      • 3.4、创建Panel:GamePanel
      • 3.5、制作摇杆
      • 3.6、制作操作按钮
    • 4、摇杆控制脚本:JointedArm.cs
      • 4.1、JointedArm.cs脚本代码
      • 4.2、挂摇杆脚本,设置成员对象
    • 5、关联UI交互事件
      • 5.1、定义UI成员:GamePanel.cs
      • 5.2、设置UI对象
      • 5.3、设置摇杆委托
    • 6、事件管理:订阅、注销、抛出
      • 6.1、封装事件管理器:EventDispatcher.cs
      • 6.2、定义事件名:EventNameDef.cs
      • 6.3、抛出事件
      • 6.4、订阅事件和注销事件
    • 7、移动控制
      • 7.1、流程
      • 7.2、代码实现
      • 7.3、运行效果
    • 8、旋转控制
      • 8.1、流程
      • 8.2、代码实现
      • 8.3、运行效果
    • 9、开枪控制
      • 9.1、流程
      • 9.2、封装EventTrigger,监听长按事件
      • 9.3、开枪按钮,长按与抬起事件
      • 9.4、响应FIRE事件
      • 9.5、运行效果
    • 10、丢手雷、跳跃、装子弹
      • 10.1、丢手雷
      • 10.2、跳跃
      • 10.3、装子弹
    • 11、加个彩蛋,同学你上电视了
  • 四、工程源码
  • 五、完毕

一、前言

嗨,大家好,我是新发。
有同学私信我,问我能不能写一篇Unity手游第一人称视角控制的教程,

那么,今天就来做个Demo吧~

注:Demo工程源码见文章末尾

最终效果如下:


二、实现方案

1、无主之地,第一人称视角

第一人称视角的游戏大家应该不陌生,比如《无主之地》,

不过它是PC平台的,使用WASD控制移动,使用鼠标来控制镜头角度,单击鼠标左键开枪。注:你也可以接手柄来操作~

那么,如果我们想做移动端(手机端)的第一人称视角,如何做角色控制呢?

2、我之前做的摇杆控制

手机端比较常见的就是摇杆控制了,我之前在几篇博客中都有做过摇杆控制,
《【游戏开发创新】用Unity等比例制作广州地铁,广州加油,早日战胜疫情(Unity | 地铁地图 | 第三人称视角)》

《【游戏开发创新】上班通勤时间太长,做一个任意门,告别地铁与塞车(Unity | 建模 | ShaderGraph | 摇杆 | 角色控制)》

《【游戏开发实战】新发教你做游戏(六):教你2个步骤实现摇杆功能》

3、第一人称视角 + 摇杆控制

我上面做的都是第三人称视角的摇杆控制,我们改成第一人称视角即可,也就是第一人称视角+摇杆控制,像这样子,(图片说明:下图是我在《无主之地》游戏截图中P了摇杆的UI

三、开始实战

1、资源获取:Unity AssetStore

我没有《无主之地》的资源,没关系,我们去UnityAssetStore上找一下FPS射击游戏的资源,

注:Unity AssetStore地址:https://assetstore.unity.com/
关于资源的搜索,我之前写过一篇文章:《Unity游戏开发——新发教你做游戏(二):60个Unity免费资源获取网站》

搜索关键字FPS Pack,马上就搜到了一个免费的资源Low Poly FPS Pack


我们点击添加至我的资源(注意需要先登录你的Unity账号),

然后回到Unity编辑器中,点击菜单Windows / Package Manager,打开PackageManager窗口,就可以看到我们刚刚在AssetStore中添加的资源啦,我们把资源包下载并导入我们的工程即可。

注:你得先创建一个空工程,然后再导入资源包。我之前写过《学Unity的猫》系列教程,其中第三章有讲创建工程的步骤,
《【学Unity的猫】——第三章:第一个Unity工程,你好喵星人》)

2、Low Poly FPS Pack资源运行效果

Low Poly FPS Pack资源包中已经帮我们做好了一个简单的第一人称FPS游戏Demo,我们打开Assault_Rifle_01_Demo场景,如下

运行,测试效果如下

如你所见,经典的PC平台FPS射击游戏玩法,使用WASD控制移动,使用鼠标来控制镜头角度,单击鼠标左键开枪。
接下来,我们要给它做下手术,改成 摇杆按钮 控制。

3、制作UI界面

3.1、UI素材获取

摇杆图片简单处理,用一个圆就可以了,然后我们还需要一些按钮图标,比如开枪、丢手雷、跳跃、装子弹等,这里推荐我平时经常用的一个查找图标资源的网站,阿里图标库:https://www.iconfont.cn/
比如我搜关键字:枪,就可以看到枪的图标啦~

可以直接免费下载,而且还可以事先修改图片颜色,建议改成白色,这样方便在Unity中设置其他颜色,

根据你自身的需要下载一些图标资源,我下载的图标如下,

注意,因为我们要在UGUI中显示这些图标,需要将它们的Texture Type设置为Sprite (2D and UI),如下

3.2、创建UI摄像机:UICamera

建议UI的显示使用一个单独的摄像机来渲染,我们在场景中创建一个Camera,重命名为UICamera

注:创建摄像机的操作步骤:在Hierarchy视图中鼠标右键,然后点击菜单Camera即可。


设置摄像机的Clear FlagsDepth only,设置Culling Mask只渲染UI层,设置ProjectionOrthographic(正交模式),设置Depth1(确保UI摄像机的比3D摄像机后渲染),

3.3、创建UI画布:Canvas

接下来,我们在Hierarchy视图中鼠标右键,点击菜单UI / Canvas,创建一个Canvas
设置一下参数,如下,目的是让UICamera来渲染Canvas的内容,并设置分辨率适配规则,

3.4、创建Panel:GamePanel

我们在Canvas子节点下创建一个Panel,重命名为GamePanel,并把Image组件禁用,

下面我们再在GamePanel下去创建UI对象。

3.5、制作摇杆

我们先做移动控制的摇杆,在GamePanel子节点下创建一个Image,重命名为moveJointedArm

设置左下角对齐,并调整坐标和尺寸,

像这样,它就是我们摇杆的检测区域,

我们把它的Image组件的颜色的Alpha通道设置为0,这样我们就看不见它了,

我们在moveJointedArm子节点下再创建两个Image,分别命名为bgcenter

分别设置一下尺寸,图片,颜色,如下

效果

同理,做一下右摇杆,

效果

3.6、制作操作按钮

除了移动和旋转,我们还有开枪、丢手雷、跳跃、装子弹的操作,配套需要制作对应的按钮。安排上,

效果

到这里,我们的UI界面就基本做好啦,下面就是写代码的环节了~

4、摇杆控制脚本:JointedArm.cs

摇杆的逻辑实现,我之前写过一篇文章讲过原理:《Unity使用ScrollRect制作摇杆(UGUI)》,这里我就不过对赘述,直接说下操作流程。

4.1、JointedArm.cs脚本代码

创建一个C#脚本,重命名为JointedArm.cs,代码如下:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System;// 摇杆逻辑
public class JointedArm : ScrollRect, IPointerDownHandler
{public Action<Vector2> onDragCb;public Action onStopCb;protected float mRadius = 0f;private Transform trans;private RectTransform bgTrans;private Camera uiCam;private Vector3 originalPos;protected override void Awake(){base.Awake();trans = transform;bgTrans = trans.Find("bg") as RectTransform;uiCam = GameObject.Find("UICamera").GetComponent<Camera>();originalPos = trans.localPosition;}void Update(){if (Input.GetMouseButtonUp(0)){//松手时,摇杆复位trans.localPosition = originalPos;this.content.localPosition = Vector3.zero;}}protected override void Start(){base.Start();//计算摇杆块的半径mRadius = bgTrans.sizeDelta.x * 0.5f;}public override void OnDrag(PointerEventData eventData){base.OnDrag(eventData);var contentPostion = this.content.anchoredPosition;if (contentPostion.magnitude > mRadius){contentPostion = contentPostion.normalized * mRadius;SetContentAnchoredPosition(contentPostion);}//Debug.Log("摇杆滑动,方向:" + contentPostion);if(null != onDragCb)onDragCb(contentPostion);}public override void OnEndDrag(PointerEventData eventData){base.OnEndDrag(eventData);//Debug.Log("摇杆拖动结束");if (null != onStopCb)onStopCb();}public void OnPointerDown(PointerEventData eventData){//点击到摇杆的区域,摇杆移动到点击的位置trans.position = uiCam.ScreenToWorldPoint(eventData.position);trans.localPosition = new Vector3(trans.localPosition.x, trans.localPosition.y, 0);}
}
4.2、挂摇杆脚本,设置成员对象

moveJointedArm节点挂JointedArm脚本,并设置Contentcenter节点,如下,

同理设置右摇杆rotateJointedArm。到此,我们的摇杆就有交互效果了,如下

5、关联UI交互事件

5.1、定义UI成员:GamePanel.cs

我们创建一个GamePanel.cs脚本,声明UI对象,如下

using UnityEngine;public class GamePanel : MonoBehaviour
{/// <summary>/// 移动摇杆/// </summary>public JointedArm moveJointedArm;/// <summary>/// 旋转摇杆/// </summary>public JointedArm rotateJointedArm;/// <summary>/// 开枪按钮/// </summary>public GameObject fireBtn;/// <summary>/// 丢手雷按钮/// </summary>public GameObject bombBtn;/// <summary>/// 跳跃按钮/// </summary>public GameObject jumpBtn;/// <summary>/// 装子弹按钮/// </summary>public GameObject bulletBtn;void Start(){// TODO 关联UI交互事件}
}
5.2、设置UI对象

把它挂到GamePanel节点上,并设置变量对象,如下

5.3、设置摇杆委托

Start函数中添加摇杆的委托,如下

// GamePanel.csvoid Start()
{// 移动控制摇杆moveJointedArm.onDragCb = (direction) =>{// TODO 抛出事件};moveJointedArm.onStopCb = () =>{// TODO 抛出事件};// 旋转控制摇杆rotateJointedArm.onDragCb = (direction) =>{// TODO 抛出事件};rotateJointedArm.onStopCb = () =>{// TODO 抛出事件};// ...
}

我们要抛出一些事件,这里要封装一个事件管理器。

6、事件管理:订阅、注销、抛出

6.1、封装事件管理器:EventDispatcher.cs

我在之前的多篇文章中都有到和用到事件管理器,欢迎阅读我之前写的这些文章,里面都有用到事件管理器,
《【游戏开发框架】自制Unity通用游戏框架UnityXFramework,详细教程(Unity3D技能树 | tolua | 框架 | 热更新)》
《【游戏开发创新】用Unity等比例制作广州地铁,广州加油,早日战胜疫情(Unity | 地铁地图 | 第三人称视角)》
《【游戏开发实战】使用Unity 2019制作仿微信小游戏飞机大战(二):搭建基础游戏框架》
《【游戏开发实战】使用Unity制作水果消消乐游戏教程(三):水果拖动与交换逻辑》
《【游戏开发实战】使用Unity制作像天天酷跑一样的跑酷游戏——第七篇:游戏界面的基础UI》
《【学Unity的猫】第十二章:使用Unity制作背包,皮皮的梦想背包》
EventDispatcher脚本代码:

using UnityEngine;
using System.Collections.Generic;public delegate void MyEventHandler(params object[] objs);/// <summary>
/// 游戏事件管理器
/// </summary>
public class EventDispatcher
{/// <summary>/// 注册事件/// </summary>/// <param name="evt">事件名</param>/// <param name="handler">响应函数</param>public void Regist(string evt, MyEventHandler handler){if (handler == null)return;if (listeners.ContainsKey(evt)){//这里涉及到Dispath过程中反注册问题,必须使用listeners[type]+=..listeners[evt] += handler;}else{listeners.Add(evt, handler);}}/// <summary>/// 注销事件/// </summary>/// <param name="evt">事件名</param>/// <param name="handler">响应函数</param>public void UnRegist(string evt, MyEventHandler handler){if (handler == null)return;if (listeners.ContainsKey(evt)){//这里涉及到Dispath过程中反注册问题,必须使用listeners[type]-=..listeners[evt] -= handler;if (listeners[evt] == null){//已经没有监听者了,移除.listeners.Remove(evt);}}}/// <summary>/// 抛出事件/// </summary>/// <param name="evt">事件名</param>/// <param name="objs">参数</param>public void DispatchEvent(string evt, params object[] objs){try{if (listeners.ContainsKey(evt)){MyEventHandler handler = listeners[evt];if (handler != null)handler(objs);}}catch (System.Exception ex){Debug.LogErrorFormat(szErrorMessage, evt, ex.Message, ex.StackTrace);}}public void ClearEvents(string key){if (listeners.ContainsKey(key)){listeners.Remove(key);}}private Dictionary<string, MyEventHandler> listeners = new Dictionary<string, MyEventHandler>();private readonly string szErrorMessage = "DispatchEvent Error, Event:{0}, Error:{1}, {2}";private static EventDispatcher s_instance;public static EventDispatcher instance{get{if (null == s_instance)s_instance = new EventDispatcher();return s_instance;}}
}
6.2、定义事件名:EventNameDef.cs

我们再创建一个EventNameDef.cs脚本,用于定义事件名,如下

/// <summary>
/// 事件名定义
/// </summary>
public class EventNameDef
{/// <summary>/// 移动/// </summary>public const string MOVE = "MOVE";/// <summary>/// 旋转/// </summary>public const string ROTATE = "ROTATE";/// <summary>/// 开枪/// </summary>public const string FIRE = "FIRE";/// <summary>/// 丢手榴弹/// </summary>public const string BOMB = "BOMB";/// <summary>/// 跳跃/// </summary>public const string JUMP = "JUMP";/// <summary>/// 装子弹/// </summary>public const string BULLET = "BULLET";
}
6.3、抛出事件

我们回到GamePanel.cs脚本,在摇杆的委托中抛出事件,

// GamePanel.csvoid Start()
{// 移动控制摇杆moveJointedArm.onDragCb = (direction) =>{EventDispatcher.instance.DispatchEvent(EventNameDef.MOVE, new Vector3(direction.x, 0, direction.y).normalized, true);};moveJointedArm.onStopCb = () =>{EventDispatcher.instance.DispatchEvent(EventNameDef.MOVE, Vector3.zero, false);};// 旋转控制摇杆rotateJointedArm.onDragCb = (direction) =>{EventDispatcher.instance.DispatchEvent(EventNameDef.ROTATE, new Vector3(direction.x, 0, direction.y).normalized);};rotateJointedArm.onStopCb = () =>{EventDispatcher.instance.DispatchEvent(EventNameDef.ROTATE, Vector3.zero);};// ...
}
6.4、订阅事件和注销事件

摇杆抛出的事件,最终的响应逻辑就是角色移动和旋转,那么我们就要在原来控制角色移动和旋转的脚本中添加事件订阅。
逻辑在哪里呢?逻辑在FPSControllerLPFP.cs脚本和AutomaticGunScriptLPFP.cs脚本中。
画个图,方便大家理解,

我们分别在FPSControllerLPFP.cs脚本和AutomaticGunScriptLPFP.cs脚本中添加事件订阅和注销,如下

// FPSControllerLPFP.csprivate void Start()
{// ...// 订阅事件EventDispatcher.instance.Regist(EventNameDef.MOVE, OnEventMove);EventDispatcher.instance.Regist(EventNameDef.ROTATE, OnEventRotate);// ...
}private void OnDestroy()
{// 注销事件EventDispatcher.instance.UnRegist(EventNameDef.MOVE, OnEventMove);EventDispatcher.instance.UnRegist(EventNameDef.ROTATE, OnEventRotate);// ...
}
// AutomaticGunScriptLPFP.csprivate void Start()
{// ...// 订阅事件EventDispatcher.instance.Regist(EventNameDef.MOVE, OnEventMove);// ...
}private void OnDestroy()
{// 注销事件EventDispatcher.instance.UnRegist(EventNameDef.MOVE, OnEventMove);// ...
}

7、移动控制

7.1、流程

流程如下,

7.2、代码实现

摇杆通过MOVE事件传递了移动方向过来,我们在FPSControllerLPFP.cs脚本中把它缓存到m_moveDirection变量中,如下

// FPSControllerLPFP.csVector3 _moveDirection;
private void OnEventMove(params object[] args)
{_moveDirection = (Vector3)args[0];
}

FixedUpdate函数中执行MoveCharacter方法,在MoveCharacter方法中根据m_moveDirection去计算移动,逻辑如下,(部分函数此处没有列出,可下载工程源码进行查看)

// FPSControllerLPFP.cs /// <summary>
/// 移动角色
/// </summary>
private void MoveCharacter()
{// 转为世界坐标系下的方向var worldDirection = transform.TransformDirection(_moveDirection);// 移动速度var velocity = worldDirection * (input.Run ? runningSpeed : walkingSpeed);// 检查碰撞,以便角色在跳墙时不会卡住var intersectsWall = CheckCollisionsWithWalls(velocity);if (intersectsWall){_velocityX.Current = _velocityZ.Current = 0f;return;}// 平滑运算var smoothX = _velocityX.Update(velocity.x, movementSmoothness);var smoothZ = _velocityZ.Update(velocity.z, movementSmoothness);// 获取当前刚体速度var rigidbodyVelocity = _rigidbody.velocity;// 计算速度差var force = new Vector3(smoothX - rigidbodyVelocity.x, 0f, smoothZ - rigidbodyVelocity.z);// 给刚体施加一个力_rigidbody.AddForce(force, ForceMode.VelocityChange);
}

移动的同时,还需要播放走路动画,逻辑在AutomaticGunScriptLPFP.cs脚本中,

// AutomaticGunScriptLPFP.csprivate Animator anim;
private bool isWalking;private void OnEventMove(params object[] args)
{isWalking = (bool)args[1];
}private void Update()
{// ...if (isWalking && !isRunning){anim.SetBool("Walk", true);}else{anim.SetBool("Walk", false);}// ...
}
7.3、运行效果

此时效果

8、旋转控制

8.1、流程

同理,旋转控制也是通过事件的响应函数来触发,流程如下,

8.2、代码实现
// FpsControllerLPFP.cs/// <summary>
/// 旋转角色
/// </summary>
private void RotateCameraAndCharacter()
{// 平滑运算var rotationX = _rotationX.Update(RotationXRaw, rotationSmoothness);var rotationY = _rotationY.Update(RotationYRaw, rotationSmoothness);// 限制竖直方向的旋转角度:var clampedY = RestrictVerticalRotation(rotationY);_rotationY.Current = clampedY;// 将世界坐标系下的up方向转为相对手臂的局部坐标系下的方向var worldUp = arms.InverseTransformDirection(Vector3.up);// 计算最终角度(四元数)var rotation = arms.rotation *Quaternion.AngleAxis(rotationX, worldUp) *Quaternion.AngleAxis(clampedY, Vector3.left);// 父节点只沿着y轴旋转,容易漏掉此步,如果没有此步,计算移动的时候会出问题transform.eulerAngles = new Vector3(0f, rotation.eulerAngles.y, 0f);// 手臂自由旋转arms.rotation = rotation;
}
8.3、运行效果

此时效果

9、开枪控制

9.1、流程

9.2、封装EventTrigger,监听长按事件

因为开枪是一个连续过程,我们要检测是否长按了开枪按钮,而UGUIButtononClick只能监听点击事件,所以我们需要另外实现长按事件的监听。
UnityEngine.EventSystems命名空间下有个EventTrigger类,它基本提供了所有UI事件,

我们封装一个EventTriggerListener.cs,继承EventTrigger,如下,

using UnityEngine;
using UnityEngine.EventSystems;/// <summary>
/// UI事件触发器
/// </summary>
public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{public delegate void VoidDelegate(GameObject go);public delegate void BoolDelegate(GameObject go, bool state);public delegate void FloatDelegate(GameObject go, float delta);public delegate void VectorDelegate(GameObject go, Vector2 delta);public delegate void ObjectDelegate(GameObject go, GameObject obj);public delegate void KeyCodeDelegate(GameObject go, KeyCode key);public VoidDelegate onClick;public VoidDelegate onDown;public VoidDelegate onEnter;public VoidDelegate onExit;public VoidDelegate onUp;public VoidDelegate onSelect;public VoidDelegate onUpdateSelect;static public EventTriggerListener Get(GameObject go){EventTriggerListener listener = go.GetComponent<EventTriggerListener>();if (listener == null) listener = go.AddComponent<EventTriggerListener>();return listener;}static public EventTriggerListener Get(Transform transform){EventTriggerListener listener = transform.GetComponent<EventTriggerListener>();if (listener == null) listener = transform.gameObject.AddComponent<EventTriggerListener>();return listener;}public override void OnPointerClick(PointerEventData eventData){if (onClick != null) onClick(gameObject);}public override void OnPointerDown(PointerEventData eventData){if (onDown != null) onDown(gameObject);}public override void OnPointerEnter(PointerEventData eventData){if (onEnter != null) onEnter(gameObject);}public override void OnPointerExit(PointerEventData eventData){if (onExit != null) onExit(gameObject);}public override void OnPointerUp(PointerEventData eventData){if (onUp != null) onUp(gameObject);}public override void OnSelect(BaseEventData eventData){if (onSelect != null) onSelect(gameObject);}public override void OnUpdateSelected(BaseEventData eventData){if (onUpdateSelect != null) onUpdateSelect(gameObject);}
}
9.3、开枪按钮,长按与抬起事件

GamePanel.cs中添加按钮长按onDown和按钮抬起onUp的监听并抛出FIRE事件,如下

// GamePanel.cs// 开炮
void Start()
{// ...EventTriggerListener.Get(fireBtn).onDown += (btn) =>{EventDispatcher.instance.DispatchEvent(EventNameDef.FIRE, true);};EventTriggerListener.Get(fireBtn).onUp += (btn) =>{EventDispatcher.instance.DispatchEvent(EventNameDef.FIRE, false);};// ...
}
9.4、响应FIRE事件

开枪的逻辑在AutomaticGunScriptLPFP.cs脚本中,流程如下

// AutomaticGunScriptLPFP.csbool _fire;
private void OnEventFire(params object[] args)
{_fire = (bool)args[0];
}private void Update()
{// ...if (_fire && !outOfAmmo && !isReloading && !isInspecting && !isRunning){if (Time.time - lastFired > 1 / fireRate){lastFired = Time.time;// 执行开枪DoFire();}}// ...
}void DoFire()
{// 以下具体代码见工程代码,此处不展开了// 播放开枪音效// 播放开炮动画// 播放枪口粒子// 实例化子弹并给子弹一个力// 实例化弹壳
}
9.5、运行效果

此时效果,

10、丢手雷、跳跃、装子弹

同理,通过事件订阅触发丢手雷、跳跃、装子弹等逻辑。

10.1、丢手雷

10.2、跳跃

10.3、装子弹

11、加个彩蛋,同学你上电视了

给这位提问的同学一次上电视的机会,我把他贴到墙上,

初始的时候图片半透明,角色靠近的时候图片完全不透明,用到的是触发器,

关于触发器的教程,我之前写过一些文章,《【学Unity的猫】第十章:Unity的物理碰撞,流浪喵星计划》
这里的检测逻辑如下,

using UnityEngine;
using UnityEngine.UI;public class TipsBoard : MonoBehaviour
{public Image board;private void Start() {board.color = new Color(1, 1, 1, 0.3f);}private void OnTriggerEnter(Collider other){if ("Player" != other.tag) return;board.color = new Color(1, 1, 1, 1);}private void OnTriggerExit(Collider other){if ("Player" != other.tag) return;board.color = new Color(1, 1, 1, 0.3f);}
}

四、工程源码

本文工程源码我已上传到CODE CHINA,感兴趣的同学可自行下载学习,
地址:https://codechina.csdn.net/linxinfa/FirstPersonGame
注:我使用的Unity版本是2021.1.7f1c1,如果你使用的版本与我的不同,可能会有一些兼容问题。

五、完毕

好啦,就到这里吧~
我是林新发:https://blog.csdn.net/linxinfa
原创不易,若转载请注明出处,感谢大家~
喜欢我的可以点赞、关注、收藏,如果有什么技术上的疑问,欢迎留言或私信~

【游戏开发实战】Unity手游第一人称视角,双摇杆控制,FPS射击游戏Demo(教程 | 含Demo工程源码)相关推荐

  1. 《cocos2d-x手机游戏开发实战》直播课程第一期介绍

    史上最牛的cocos2d-x课程 <cocos2d-x手机游戏开发实战>直播课程第一期 史上最牛的优惠活动: 报名关东升老师iOS会员送cocos2d-x直播课程,而且终身会员价格只要19 ...

  2. 基于Python+百度语音的智能语音ChatGPT聊天机器人(机器学习+深度学习+语义识别)含全部工程源码 适合个人二次开发

    目录 前言 总体设计 系统整体结构图 系统流程图 运行环境 Python 环境 Pycharm 环境 ChatterBot 环境 模块实现 1. 模型构建 2. 服务器端 3. 客户端 4. 语音录入 ...

  3. unity实现坦克第一人称视角移动 鼠标发射,位置改变

    Holle 好久没更新了,实在想不到更新啥了,就更新下最近痴迷的unity吧. 分为四个板块,实现第三人称视角,上下左右移动,鼠标进行发射炮弹,鼠标改变移动方向 我们的需要准备的工作有:unity 自 ...

  4. 对金玺曾版《Unity3D手机游戏开发》第三章“第一人称射击游戏”修改,使支持僵尸连续攻击

    我个人觉得这本书写的至少很和我口味,而且他的光盘资料也很详尽,比如,一个实例,不仅有一个完整的实现工程,还有一份供作练习的工程(该工程中没有要练习的部分,而资源啥的都有),让人感觉很好. 这本书下载电 ...

  5. iOS游戏开发之使用 Spritekit 框架和 Swift 的 iOS 2D 太空射击游戏(教程含源码)

    实战需求 使用 Spritekit 框架和 Swift 的 iOS 2D 太空射击游戏 本文价值与收获 看完本文后,您将能够作出下面的界面 实战代码 1.主界面 import SpriteKit im ...

  6. 【Unity游戏开发笔记】手游-涂鸦弹跳开发分析

    涂鸦弹跳游戏截图 游戏类型:2D跳跃类 游戏风格:简朴 游戏技术分析: 1.实现玩家弹跳功能 利用2D刚体直接添加一个向上的Impluse冲击力即可,加力之前将刚体velocity速度设置为0 2.游 ...

  7. 《Unity 5.x游戏开发实战》一1.9 添加一个水平面

    本节书摘来异步社区<Unity 5.x游戏开发实战>一书中的第1章,第1.9节,作者: Alan Thorn 译者: 李华峰 责编: 胡俊英,更多章节内容可以访问云栖社区"异步社 ...

  8. 【游戏开发实战】教你在Unity中实现模型消融化为灰烬飘散的效果(ShaderGraph | 消融 | 粒子系统 | 特效)

    文章目录 一.前言 二.ShaderGraph环境准备 三.模型准备:原神角色模型 四.实现思路 1.效果一的实现思路 2.效果二的实现思路 五.ShaderGraph具体实现 1.效果一 1.1.创 ...

  9. 【Unity】第一人称视角开发

    需求 我的需求是在Unity构建一个第一人称视角,实现移动跳跃功能. 主要参考的是这篇博文提供的方案,不过该方案为了只允许一次跳跃,单独在人物底部构建了一个空对象,我无需此限制,因此对其进行了简化. ...

最新文章

  1. 第二阶段 铁大Facebook——十天冲刺(七)
  2. python爬虫原理-Python爬虫原理
  3. 前端学习(2044)vue之电商管理系统电商系统之优化configwebpack和chainwebpack
  4. 爸爸的素质决定孩子飞多高,爸爸们请反复看!!!
  5. 数据结构之二叉搜索树
  6. vba ado返回集合_利用ADO,实现同一文件夹下多个EXCEL工作表的数据汇总
  7. 用户名 不在 sudoers文件中,此事将被报告。
  8. python linkedlist,LinkedList在python中的实现
  9. sql基础教程和mysql基础教程_SQL基础教程第2版 ([日]MICK 著) 中文pdf高清版[22MB]
  10. Epic Games Launcher 无效驱动器E
  11. TOPSIS法 —— matlab
  12. 白纸不够白,签名照片还需要ps去除背景?Python大法半完美解决电子签名背景问题(20行代码去除签名背景)
  13. [分享解决]你的支付授权失败。请核对你的信息并重试,或尝试其他支付方式。请联系你的银行了解更多信息
  14. 什么输入法对计算机英语,电脑怎么把英文输入法设置为默认输入法
  15. gitLab数据备份和恢复
  16. 带宽、速率(波特率、比特率)和码元宽度简述
  17. 思科路由器配置GRE隧道
  18. 408-数据结构-树的应用-哈夫曼树并查集
  19. Java培训完能不能就业?
  20. 如何让旧电脑运行更快:升级笔记本组件和操作系统

热门文章

  1. 2020移动apn接入点哪个快_为什么别人的4g网总比你快? 手机这个设置没开启, 难怪网络...
  2. python查找文字在图片中的位置_使用Python识别图片中的中/英文字
  3. Android高级工程师面试题-字节跳动,含BATJM大厂
  4. Linux系统下查找最近修改过的文件
  5. python显示图片不连续_python实现连续图文识别
  6. 集创北方IPO被终止:曾拟募资60亿 小米华为vivo是股东
  7. 假如宋钦宗赵桓是一代明君,处理奸佞叛贼,开除主降派力排众议,文武并举。
  8. Excel中IF函数的使用
  9. msfvenom手册
  10. java poi导出Excel表,合并单元格