===================更新一下源工程链接:
链接:https://pan.baidu.com/s/15bxH-MPregp2ZIN92fK7XA 提取码:e7bp
===================(与本文相比有修改)

效果视频演示:
https://www.bilibili.com/video/av88249417
完整代码在最下面

最近练习Unity,想做一个第三人称射击游戏的Demo。首先来做一个武器瞄准效果,即让枪能指向目标。

查了很久不知道怎么实现,后来查到了IK这个概念,IK就是反向动力学,按我的理解是让骨骼中的下层带动上层运动,与FK(前向动力学)相反,比如伸手去触摸物体时带动整个身体前倾。所以武器的瞄准就可以用通过IK来做,让手和武器瞄准目标,带动身体旋转,这样就很自然。

如图:

Unity自带的IK实在是不好用,连这个功能都很难实现,于是我用了一个插件:Final IK,用里面一个叫AimIK的组件就可以解决了。
附上Final IK1.6的链接:
链接:https://pan.baidu.com/s/1zY4bluDzi8xSSWPtJBLGWQ
提取码:eovc
教程参考这篇博客:
https://blog.csdn.net/weixin_38239050/article/details/101831392
Final IK的使用不是本文的重点。

用代码来设置瞄准的思路是:从摄像机的位置向摄像机的forward方向发出一定距离的射线,如果射线打到物体就让把它设为瞄准目标,否则瞄准射线的终点。注意射线可能需要屏蔽玩家本身碰撞体的干扰
设置AimIK的target位置的代码为:

aimIK.solver.target.position = targetPos;

例如射线打到地面:

-------------------------------------------

然后是视角控制,虽然Unity有相应的插件,但是直接用就没意思了。本来以为比较简单,没想到还是搞了几天(太菜了)
实现的功能如下:
1.摄像机平滑跟随玩家
2.摄像机绕玩家旋转,并限制角度
3.往上看时随角度增大而拉近摄像机,往下看时随角度增大而拉远摄像机
4.瞄准时拉近摄像机,停止瞄准时回到默认位置
5.碰到墙壁遮挡时拉近摄像机

下面依次介绍,完整代码在最下面

1.摄像机平滑跟随

记录摄像机与人物的位置偏移向量

playerOffset = player.position - transform.position;

当摄像机旋转后需要更新playerOffset,再次计算上面这句代码。

更新playerOffset后需要在下一帧使用插值让摄像机移动到player.position - playerOffset这个位置

transform.position = Vector3.Lerp(transform.position, player.position - playerOffset, moveSpeed * Time.deltaTime);

2.摄像机绕玩家旋转,并限制角度

主要使用transform.RotateAround函数,让摄像机绕人物旋转。由于人物可以移动,而摄像机的位置是使用插值改变的,当人物移动时,playerOffset这个向量的长度和旋转角度会发生改变,人物走的越远,偏差会越大,不符合要求。

我的办法是当摄像机绕玩家旋转后,让playerOffset向量同步旋转相同的角度,更新playerOffset。旋转后playerOffset的长度不变,这样可保证player.position-playerOffset始终是摄像机的最终位置。

如下图示意:


RotateAround的用法为:

RotateAround(Vector3 point, Vector3 axis, float angle);

point:要围绕的点;
axis:要围绕的轴,如x,y,z
angel:旋转的角度

所以摄像机水平和垂直绕玩家旋转为:(注意旋转的轴不同

transform.RotateAround(player.position, Vector3.up, axisX);
transform.RotateAround(player.position, transform.right, -axisY);

其中axisX和axisY为对应鼠标的偏移量xTime.deltatimex旋转速度:

float axisX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
float axisY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;

而让playerOffset向量绕一个点旋转则要先获取水平和垂直旋转的四元数:(同样注意绕的轴

Quaternion rotX = Quaternion.AngleAxis(axisX, Vector3.up);
Quaternion rotY = Quaternion.AngleAxis(-axisY, transform.right);

然后让这两个四元素与向量相乘就可以旋转向量而长度不变:(注意这里相乘不具有交换性,不要改变顺序或是简写

playerOffset = rotX * rotY * playerOffset;

这里获取向量旋转看不懂可以参考文章:
https://gameinstitute.qq.com/community/detail/127450

要限制角度,我们要先让它旋转,然后获取旋转后垂直方向的欧拉角:

float x = (transform.rotation).eulerAngles.x;

但是欧拉角的范围是0-360度循环的,不利于判断,要转换范围成-180度-180度,向上为负,向下为正。然后判断它是否在我们给定的范围内如果超出范围则还原摄像机在垂直方向的旋转,并且让playerOffset只进行水平旋转;否则让playerOffset进行水平和垂直的旋转。

//欧拉角范围为0~360,这里要转为-180~180方便判断
if (x > 180) x -= 360;if (x < minAngle || x > maxAngle)//超出角度
{//还原位置和旋转transform.position = posPre;transform.rotation = rotPre;//更新offset向量,offset与本物体同步旋转//我们需要通过这offset去计算本物体(包括摄像机)应该平滑移向的位置//如果仅仅使用RotateAround函数,当人物在移动时会出现误差playerOffset = rotX*playerOffset;
}
else//垂直视角符合范围的情况
{//更新offset向量,offset与本物体同步旋转playerOffset = rotX * rotY * playerOffset;
}

最高视角:(根据minAngle,根据需要设定,我设为-40)

最低视角:(根据maxAngle,根据需要设定,我设为50)

3.往上看时随角度增大而拉近摄像机,往下看时随角度增大而拉远摄像机

摄像机与人物的距离需要时可变的,比如在瞄准时应该将摄像机拉近人物,但是如果直接改变摄像机的位置又会破坏跟随玩家和自由视角的功能。

为了使摄像机在能够根据需要偏移的同时又不影响平滑跟随玩家,我的办法是把上面的控制代码挂在一个空物体上,将摄像机作为这个空物体的子物体,这样空物体跟随玩家时,摄像机也会做相同的位移。而让摄像机的位置产生偏移只需要改变它的localPosition,也就是它与父物体的相对位置。

如图:TPSCameraParent为空物体

摄像机偏移是改变TPSCamera的localPosition.z,让TPSCamera相对于TPSCameraParent前后移动。定义一个总的偏移量:

float localOffset = 0;

这个偏移量的影响因素有三个:
1.垂直视角角度
2.是否瞄准
3.是否有遮挡

下面来看垂直视角角度的影响:

上面我们获取到了垂直方向旋转欧拉角float x,就可以根据x与我们给定的最大角度的比值来设定摄像机的前后偏移:

//更据角度设置摄像机位置偏移if (x < 0)//往上角度为负{//往上看时距离拉近localOffsetAngle = (x / minAngle) * localOffsetAngleUp;}else{//往下看时距离拉远localOffsetAngle = -(x / maxAngle) * localOffsetAngleDown;}

其中localOffsetAngle为根据角度计算的偏移量,localOffsetAngleUp和localOffsetAngleDown分别为向上看和向下看时这个偏移量的最大值。当x=0时即摄像机平视前方时,这个偏移量=0。

那怎么让摄像机能够前后偏移呢?让总偏移量加上它:

localOffset+=localOffsetAngleMax;

在最后使摄像机平滑移动到偏移位置:

Vector3 offsetPos = new Vector3(0, 0, localOffset);//这是相机应该移向的位置
//使相机平滑移动到这个位置
cam.transform.localPosition = Vector3.Lerp(cam.transform.localPosition, offsetPos, localOffsetSpeed * Time.deltaTime);

俯视时拉远摄像机:

仰视时拉近摄像机:

4.瞄准时拉近摄像机,停止瞄准时回到默认位置

规定当鼠标右键按住时瞄准,松开时停止瞄准。

再定义一个偏移量localOffsetAim和一个bool值isAiming

public float localOffsetAim = 2;//根据是否瞄准而产生的偏移量,表示瞄准时摄像机应该前进多远距离,根据需要设值
private bool isAiming = false;//是否正在瞄准

然后每帧判断鼠标事件:

if (Input.GetMouseButtonDown(1))//鼠标右键按下为瞄准{isAiming = true;}
if (Input.GetMouseButtonUp(1))//鼠标右键松开停止瞄准
{isAiming = false;
}

接着根据isAiming来决定是否让localOffset加上这个偏移量:

//根据是否瞄准而调整
if (isAiming)
{localOffset += localOffsetAim;
}

瞄准时拉近摄像机:

正常距离:

5.碰到墙壁遮挡时拉近摄像机

当人物身后有墙壁或是其他物体靠近时,会遮挡视线:

这时候需要将摄像机拉近到合适距离,所以再定义一个偏移量:

float localOffsetCollider = 0;

然后在一帧中逐渐增加这个偏移量去试探有没有遮挡,试探的方法还是利用射线检测,看是否能打到除玩家外的碰撞体,我这里玩家身上挂的是CapsuleCollider:

private bool CheckView(Vector3 checkPos){//发出射线来检测碰撞RaycastHit hit;//射线终点为玩家物体的中间位置Vector3 endPos = player.position + player.up * player.GetComponent<CapsuleCollider>().height * 0.5f;Debug.DrawLine(checkPos,endPos, Color.blue);//从checkPos发射一条长度为起点到终点距离的射线if (Physics.Raycast(checkPos,endPos-checkPos,out hit,(endPos-checkPos).magnitude)){if (hit.transform == player)//如果射线打到玩家说明没有遮挡return true;else//如果射线打击到其他物体说明有遮挡return false;}return true;//如果射线没有打到任何物体也说明没有遮挡}

根据是否有遮挡而调整localOffsetCollider

        Vector3 checkPos = transform.position + cam.transform.forward * localOffset;//这是没有调整前相机应该移向的位置for(localOffsetCollider=0; !CheckView(checkPos);localOffsetCollider+=0.2f)//让localOffset递增直至没有遮挡{//更新checkPos为我们想要移动到的位置,再去试探checkPos = transform.position + cam.transform.forward * (localOffset+localOffsetCollider);}

再让localOffset加上这个试探出的localOffsetCollider。

效果:

完整代码及使用

分为两个脚本:
1.TPSCamera.cs

using UnityEngine;public class TPSCamera : MonoBehaviour
{public static TPSCamera _instance;//用作单例模式public Camera cam;//摄像机,是本物体下的子物体public Transform player;//玩家物体的Transformpublic Vector3 playerOffset;//本物体与玩家位置的偏移向量public float rotateSpeed;//控制旋转速度public float moveSpeed;//控制跟随的平滑度public float minAngle;//垂直视角的最小角度值public float maxAngle;//垂直视角的最大角度值public float localOffsetSpeed = 8;//控制相机与父物体偏移时的平滑度public float localOffsetAim = 2;//根据是否瞄准而产生的偏移量,表示瞄准时摄像机应该前进多远距离,根据需要设值private float localOffsetAngle = 0;//根据垂直视角角度而产生的偏移量public float localOffsetAngleUp = 1.5f;//根据向上的角度而产生的偏移量的最大值public float localOffsetAngleDown = 1.5f;//根据向下的角度而产生的偏移量的最大值private float localOffsetCollider = 0;//根据玩家与摄像机间是否有遮挡而产生的偏移量private bool isAiming = false;//是否正在瞄准private void Awake(){_instance = this;player = GameObject.Find("Player").transform;//根据名字找到玩家物体playerOffset = player.position - transform.position;//初始化playerOffsetcam = transform.GetComponentInChildren<Camera>();//获取子物体的Camera组件}private void Update(){if (Input.GetMouseButtonDown(1))//鼠标右键按下为瞄准{isAiming = true;}if (Input.GetMouseButtonUp(1))//鼠标右键松开停止瞄准{isAiming = false;}SetPosAndRot();//设置视角旋转后的位置和朝向Cursor.visible = false;//隐藏鼠标}/// <summary>/// 上下移动鼠标时,相机围绕玩家旋转,并且限制旋转角度/// </summary>public void SetPosAndRot(){//更新本物体的position,相机会和本物体做相同的位移,使相机平滑跟随玩家transform.position = Vector3.Lerp(transform.position, player.position - playerOffset, moveSpeed * Time.deltaTime);//获取鼠标移动量float axisX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;float axisY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;//计算水平和垂直的旋转角Quaternion rotX = Quaternion.AngleAxis(axisX, Vector3.up);Quaternion rotY = Quaternion.AngleAxis(-axisY, transform.right);//摄像机在水平方向绕玩家旋转transform.RotateAround(player.position, Vector3.up, axisX);//保存未旋转垂直视角前的position和rotationVector3 posPre = transform.position;Quaternion rotPre = transform.rotation;//先垂直绕玩家旋转,注意这里旋转的轴为transform.righttransform.RotateAround(player.position, transform.right, -axisY);//判断垂直角度是否符合范围float x = (transform.rotation).eulerAngles.x;//欧拉角范围为0~360,这里要转为-180~180方便判断if (x > 180) x -= 360;if (x < minAngle || x > maxAngle)//超出角度{//还原位置和旋转transform.position = posPre;transform.rotation = rotPre;//更新offset向量,offset与本物体同步旋转//我们需要通过这offset去计算本物体(包括摄像机)应该平滑移向的位置//如果仅仅使用RotateAround函数,当人物在移动时会出现误差playerOffset = rotX*playerOffset;   }else//垂直视角符合范围的情况{//更新offset向量,offset与本物体同步旋转playerOffset = rotX * rotY * playerOffset;//更据角度设置摄像机位置偏移if (x < 0)//往上角度为负{//往上看时距离拉近localOffsetAngle = (x / minAngle) * localOffsetAngleUp;}else{//往下看时距离拉远localOffsetAngle = -(x / maxAngle) * localOffsetAngleDown;}}//设置摄像机与父物体的偏移,三个影响因素SetLocalOffset(); }/// <summary>/// 根据是否瞄准、垂直视角和是否有遮挡来调整摄像机与父物体的偏移/// </summary>public void SetLocalOffset(){float localOffset = 0;//摄像机与父物体(即本脚本所在的空物体)的偏移//根据垂直视角调整localOffset += localOffsetAngle;//根据是否瞄准而调整if (isAiming){localOffset += localOffsetAim;}//根据是否有遮挡而调整Vector3 checkPos = transform.position + cam.transform.forward * localOffset;//这是没有调整前相机应该移向的位置for(localOffsetCollider=0; !CheckView(checkPos);localOffsetCollider+=0.2f)//让localOffset递增直至没有遮挡{//更新checkPos为我们想要移动到的位置,再去试探checkPos = transform.position + cam.transform.forward * (localOffset+localOffsetCollider);}localOffset += localOffsetCollider;//加上这个试探出的偏移量Vector3 offsetPos = new Vector3(0, 0, localOffset);//这是调整后相机应该移向的位置//使相机平滑移动到这个位置cam.transform.localPosition = Vector3.Lerp(cam.transform.localPosition, offsetPos, localOffsetSpeed * Time.deltaTime);}/// <summary>/// 检查玩家与摄像机之间是否有碰撞体遮挡/// </summary>/// <param name="checkPos">假设相机的位置</param>/// <returns></returns>private bool CheckView(Vector3 checkPos){//发出射线来检测碰撞RaycastHit hit;//射线终点为玩家物体的中间位置Vector3 endPos = player.position + player.up * player.GetComponent<CapsuleCollider>().height * 0.5f;Debug.DrawLine(checkPos,endPos, Color.blue);//从checkPos发射一条长度为起点到终点距离的射线if (Physics.Raycast(checkPos,endPos-checkPos,out hit,(endPos-checkPos).magnitude)){if (hit.transform == player)//如果射线打到玩家说明没有遮挡return true;else//如果射线打击到其他物体说明有遮挡return false;}return true;//如果射线没有打到任何物体也说明没有遮挡}}

这个脚本挂在TPSCameraParent上,即摄像机的父物体上
相关参数根据需要设定,我的如下,供参考:

2.ShootControl.cs

using RootMotion.FinalIK;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ShootControl : MonoBehaviour
{public TPSCamera tpsCamera;//控制相机视角的脚本public Camera cam;//摄像机public float range;//射线距离private float offsetDis;//摄像机与玩家的距离public Vector3 targetPos;//目标位置private AimIK aimIK;//对应的final ik组件public float speed;//移动速度public float rotateSpeed;//旋转速度private void Awake(){tpsCamera = GameObject.Find("TPSCameraParent").GetComponent<TPSCamera>();//获取相机的父物体cam = tpsCamera.GetComponentInChildren<Camera>();//相机为tpsCamera的子物体aimIK = GetComponent<AimIK>();//获取AimIk组件offsetDis = Vector3.Distance(transform.position, cam.transform.position);//初始化offsetDis}private void Update(){SetTarget();//设置瞄准的目标位置OnKeyEvent();//处理按键响应}/// <summary>/// 设置瞄准的目标/// 从摄像机位置向摄像机正方向发射射线(即从屏幕视口中心发出)/// 射线的长度=range,可以近似设为子弹的射程/// 若射线打到非玩家的物体则将该物体设为目标/// 若射线没有打到物体则将目标设为射线的终点/// </summary>public void SetTarget(){//从摄像机位置向摄像机正方向发射射线(即从屏幕视口中心发出)RaycastHit hit;if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, range)){//若射线打到非玩家的物体则将该物体设为目标//我这里并没有进行判断该物体是否是玩家,因为我设置的玩家位于屏幕的偏左下位置,射线不会穿过玩家//需要的话,可以给玩家设定layer,然后让射线屏蔽这个layertargetPos = hit.point;}else{//若射线没有打到物体则将目标设为射线的终点targetPos = cam.transform.position + (cam.transform.forward * range);}//画出射线便于观察(不会显示在game中)Debug.DrawRay(cam.transform.position, cam.transform.forward * range, Color.green);//按下鼠标右键时开启AimIK,进入瞄准状态if (Input.GetMouseButtonDown(1)){aimIK.enabled = true;}//按住鼠标右键时为瞄准状态,人物身体始终朝向摄像机的前方if (Input.GetMouseButton(1)){RotateBodyToTarget();}else//松开右键时为自由视角状态,关闭AimIK,不进行瞄准{//注意这里使用Disale(),不要直接enabled=false,原因不清楚aimIK.Disable();}}/// <summary>/// 旋转玩家身体,使玩家朝向摄像机的水平前方/// </summary>private void RotateBodyToTarget(){Vector3 rotEulerAngles = cam.transform.eulerAngles;//获取摄像机的旋转的欧拉角rotEulerAngles.x = 0;//垂直方向不进行旋转//使用插值让玩家平滑转向transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(rotEulerAngles), rotateSpeed * Time.deltaTime);SetAimIKTarget();//更新AimIK的target的位置}/// <summary>/// 更新AimIK的target的位置/// </summary>private void SetAimIKTarget(){//将AimIK的target位置设为之前射线检测到的位置aimIK.solver.target.position = targetPos;}/// <summary>/// 管理键盘的响应,这里只用来控制玩家移动,不重要,可以忽略/// </summary>private void OnKeyEvent(){//Horizontal和Vertical的默认按键为ad←→和ws↑↓float h = Input.GetAxis("Horizontal");float v = Input.GetAxis("Vertical");if (h != 0 || v != 0){Vector3 moveDir = new Vector3(h, 0, v);transform.Translate(moveDir * speed * Time.deltaTime);RotateBodyToTarget();}}
}

挂在玩家身上,玩家名为“Player”,参数参考:

玩家身上还需挂载的组件:

AimIK参数:(建议先看一下AimIK的使用,如果不需要瞄准功能的话可以不用ShootControl和AimIK组件)

其中Target为一个任意的空物体,拖进去,FirePos为武器的空子物体,位于枪口位置。
如图:

初始时将需要跟随的人物放在摄像机视线的左下角,否则需要在ShootControl.cs中的射线检测那里屏蔽掉玩家所在的层。

另外准星绘制参考这个博客:
https://blog.csdn.net/xboxbin/article/details/88069638

Unity 第三人称射击游戏视角控制与武器瞄准相关推荐

  1. unity第三人称射击游戏_在游戏上第3部分完美的信息游戏

    unity第三人称射击游戏 Previous article 上一篇文章 The economics literature distinguishes the quality of a game's ...

  2. Unity第三人称射击游戏的相机控制

    (关于其他几种角色移动的控制在我之前的博客有写到) 首先我们需要先理解一下第三人称相机控制的原理: 我们要实现的效果就是:获取鼠标的移动输入,转化成角色以及相机的旋转,通过鼠标输入Input.GetA ...

  3. unity 第三人称射击游戏中如何防止跟随摄像机穿墙?

    在制作3d射击类游戏中,会遇到跟随角色的摄像机会穿透墙壁导致视野不佳情况,下面,介绍一下具体的解决方法. 我们需要用到的原理就是unity中射击线函数.具体的原理是,从相机的跟随点向相机的方向发射一条 ...

  4. Unity制作第三人称射击游戏-成为创新游戏开发者学习教程

    用Unity游戏引擎学习和制作第三人称射击游戏-成为创新游戏开发者- TPS战地克隆 你会学到什么 Unity 3D游戏开发 如何打造TPP第三人称射击游戏 第三人控制者 第三人称动画 第三人运动控制 ...

  5. 【Unity】第三人称射击游戏开发过程之瞄准状态设计(TPS.S.P1)

    [Unity]第三人称射击游戏开发过程之瞄准状态设计(TPS.S.P1) 设计整体的结构与模式 瞄准状态的设计 瞄准相机 瞄准状态 瞄准时的鼠标移动速度限制 瞄准点的处理 角色在瞄准状态下的旋转 瞄准 ...

  6. 【Unity】第三人称射击游戏开发过程之开火设计(TPS.S.P2)

    [Unity]第三人称射击游戏开发过程之开火设计(TPS.S.P2) 枪械的开火 开火流程 开火前的准备 实体子弹的准备 开火逻辑 这一章我们来设计基础的枪械功能. 枪械的开火 我现在选择的武器是41 ...

  7. 视频教程-Unity3D实战入门之第三人称射击游戏(TPS)-Unity3D

    Unity3D实战入门之第三人称射击游戏(TPS) 6年程序开发经验,精通C/C++/C#编程. 曾担任过Unity3d游戏开发主程和Unity3d游戏开发讲师,熟悉Unity3d的UI系统.物理引擎 ...

  8. Unity3D实战入门之第三人称射击游戏(TPS)-伍晓波-专题视频课程

    Unity3D实战入门之第三人称射击游戏(TPS)-327人已学习 课程介绍         这是一套第三人称射击游戏开发的入门基础课程. 本课程以一款小型的第三人称射击游戏为案例,手把手教你如何搭建 ...

  9. YGG 购买了 AAA 级第三人称射击游戏《Nyan Heroes》的 Genesis NFT

    Yield Guild Games(YGG)已经购买了<Nyan Heroes>的Genesis NFT,<Nyan Heroes>是一款建立在 Solana 区块链上的第三人 ...

最新文章

  1. 开发日记-20190829 关键词 读书笔记《Unix环境高级编程(第二版)》DAY 5
  2. 全套CRC校验的算法
  3. C++函数模板(二)引用
  4. 一体台式计算机名称,【一体台式电脑】一体台式电脑品牌推荐,台式一体机电脑哪款好_什么值得买...
  5. respondsToSelector的相关使用
  6. word 远程过程调用失败。 (异常来自 HRESULT:0x800706BE) 解决方法
  7. 论存储芯片对国家发展的重要性
  8. mysql 2008 教程_sql 2008 视频教程数据库从入门到精通自学视频教程_IT教程网
  9. n986原生android,【极光ROM】-【三星NOTE20U(国行/港版/台版/韩版/美版) N986X-高通865P】-【V4.0 Android-R-UA3】...
  10. CAN笔记(4) 协议基本概念
  11. 使用screw一键生成数据库文档
  12. BootCDN和npm
  13. RGMII_PHY测试笔记1 基于开发板MiS603-X25
  14. 卸载红蜘蛛多媒体网络教室
  15. python3GUI--翻译器By:PyQt5(附源码)
  16. 表单验证的相关事件和辅助特效
  17. 数模学习(四)---拟合算法
  18. 铸博皇御:现货黄金指数要如何去看
  19. 使用scrapy框架爬取豆瓣影评
  20. 中南大学计算机085403,多空位缺陷和硼氮杂质对锯齿型石墨烯纳米带电子结构-中南大学学报.PDF...

热门文章

  1. 软件测试专业应届生应如何提高职场竞争力
  2. 跟我一起玩《linux内核设计的艺术》第1章(二)——linux内存加载和16位实模式使命的终结
  3. 1 99所有奇数之和java_计算1~N之间所有奇数之和(Java)
  4. 智能微电网研究(PythonMatlab代码实现)
  5. Eigen矩阵运算库快速上手
  6. CDN识别和真实IP获取(信息收集篇)
  7. 非主流自然语言处理——遗忘算法系列(二):大规模语料词库生成
  8. 浅谈当下10种最流行的编程语言
  9. 游戏场景中的光影设计
  10. sql中两个字段进行拼接用concat()函数