https://blog.csdn.net/wfenglinxu/article/details/46732147 遊戲中的數學與物理(一)
1.1讓物體沿水平方向運動
瞭解勻速直線運動(最簡單的運動),若左邊爲x,速度爲v,則:x+=v,v=-v。
注意: 注意物體的中心點,不同的遊戲引擎,可能設計的中心點不同,而中心點不同,邊界也就不同。
1.2通過鍵盤控制物體的運動
主要用到小學學的勾股定理,原理很簡單,而且很實用。
PS: 在模擬運動時,要控制個方向的速度。
隨機噴射:
正態分佈:
可以根據均勻分佈的隨機數生成滿足正態分佈的隨機數的算法。
Box-Muller 算法隱含的原理非常深奧,但結果卻是相當簡單。它一般是要得到服從正態分佈的隨機數,基本思想是先得到服從均勻分佈的隨機數後再將服從均勻分佈的隨機數轉變爲服從正態分佈。
偏態分佈:
第三章 碰撞檢測
德摩根定律:對全體條件的否定可以分解爲對所有單個條件的否定。
矩形之間的碰撞檢測:分別對兩個矩形的上座標和下座標都進行判定。
應用:
用於對2D物體的判斷,使用屏幕空間的座標
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 任意形狀,任意長寬的物體相交時彈開
/// 在相交時,沿着向量方向移動,可以是任意現狀的物體相交,任意大小的物體相交,UI等
/// </summary>
public class OpenDrawPlane : MonoBehaviour
{
public List<Transform> listTrans = new List<Transform>();
public List<Info> listScreenPos= new List<Info>();
public float prinfWidth = 150;
public float prinfHeight = 160;
/// <summary>
/// 因爲這個畫板的中心點還需要加上地下畫筆的高度
/// </summary>
[Range(-40, 40)]
public float heightScreen=20;
/// <summary>
/// 調整偏移的比率
/// </summary>
[Range(-20, 20)]
public float offsetX =0;
[Range(-40, 40)]
public float offsetY = 0;
Vector3 drawSheepPanelFar = new Vector3(0, -100, -870);
void Update()
{
listScreenPos.Clear();
//適應不同分辨率的畫板長寬
prinfWidth = Screen.width / (Screen.width / prinfWidth);
prinfHeight = Screen.height / (Screen.height / prinfHeight);
heightScreen = Screen.height / (Screen.height / heightScreen);
//for (int row = 0; row < listTrans.Count; row++)
//{
// Vector3 screenPos =
// Camera.main.WorldToScreenPoint(listTrans[row].transform.position);
// Info info = new Info();
// info.trans = listTrans[row].transform;
// info.screenPos = screenPos;
// info.width = 100;
// info.height = 100;
// listScreenPos.Add(info);
//}
Transform drawBoardPar = transform;
for (int row = 0; row < drawBoardPar.GetChildCount(); row++)
{
Transform trans = drawBoardPar.GetChild(row);
if (trans.localPosition != drawSheepPanelFar)
{
Vector3 screenPos = Camera.main.WorldToScreenPoint(trans.position);
Info info = new Info();
info.trans = trans;
info.screenPos = screenPos;
//此處可以是不同的長寬度物體,或者直接獲取物件相在屏幕空間下的長寬
info.width = prinfWidth;
info.height = prinfHeight;
listScreenPos.Add(info);
}
}
for (int row = 0; row < listScreenPos.Count; row++)
{
for (int cow = 0; cow < listScreenPos.Count; cow++)
{
//畫板和畫板的檢測
if (listScreenPos[row].trans != listScreenPos[cow].trans)
{
//在相交時,沿着向量方向移動,可以是任意現狀的物體相交,任意大小的物體相交
//兩個物體的位置的x位置和兩物體的y的位置 x<width*2 y<height*2
float centerX = Mathf.Abs(listScreenPos[row].screenPos.x - listScreenPos[cow].screenPos.x);
float centerY = Mathf.Abs(listScreenPos[row].screenPos.y - listScreenPos[cow].screenPos.y);
if (centerX < (listScreenPos[row].width / 2 + listScreenPos[cow].width / 2) &&
centerY < (listScreenPos[row].height / 2 + listScreenPos[cow].height / 2))
{
//Debug.Log(listScreenPos[row].trans.gameObject.name + " 和 " + listScreenPos[cow].trans.gameObject.name + " 想交");
/////對於中心點完全相同的,則dir =0,則需要減去一個位置偏移-new Vec(0.2,0.2f,0.2))
Vector3 dir = listScreenPos[row].trans.localPosition - listScreenPos[cow].trans.localPosition;
//設置在屏幕以內運動
Vector3 screenPosRow = Camera.main.WorldToScreenPoint(listScreenPos[row].trans.position);
if ((screenPosRow.x + listScreenPos[row].width / 2) < Screen.width && (screenPosRow.x - listScreenPos[row].width / 2) > 0 &&
(screenPosRow.y + listScreenPos[row].height / 2) < Screen.height && (screenPosRow.y - listScreenPos[row].height / 2) > 0 + heightScreen)
{
listScreenPos[row].trans.Translate(dir.normalized * Time.deltaTime);
}
}
}
else
{
//畫板和屏幕的檢測
Vector3 screenPosRow = Camera.main.WorldToScreenPoint(listScreenPos[row].trans.position);
if ((screenPosRow.y + listScreenPos[row].height / 2) > Screen.height)
{
listScreenPos[row].trans.Translate(-listScreenPos[row].trans.up * Time.deltaTime);
}
else if ((screenPosRow.y - listScreenPos[row].height / 2) < 0 + heightScreen)
{
listScreenPos[row].trans.Translate(listScreenPos[row].trans.up * Time.deltaTime);
}
if ((screenPosRow.x + listScreenPos[row].width / 2) > Screen.width)
{
listScreenPos[row].trans.Translate(-listScreenPos[row].trans.right * Time.deltaTime);
}
else if ((screenPosRow.x - listScreenPos[row].width / 2) < 0)
{
listScreenPos[row].trans.Translate(listScreenPos[row].trans.right * Time.deltaTime);
}
}
}
}
}
public class Info
{
public Transform trans;
public Vector3 screenPos;
public float width = 150;
public float height = 160;
}
}
用於對3D物體的判斷,加入z向量,使用世界空間的座標
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
public List<Transform> listTrans = new List<Transform>();
public List<Info> listScreenPos = new List<Info>();
void Update()
{
listScreenPos.Clear();
for (int row = 0; row < listTrans.Count; row++)
{
Info info = new Info();
info.trans = listTrans[row].transform;
info.screenPos = listTrans[row].transform.position;
info.width = 1.2f; //單位爲1的cube
info.height = 1.2f;
info.back = 1.2f;
listScreenPos.Add(info);
}
for (int row = 0; row < listScreenPos.Count; row++)
{
for (int cow = 0; cow < listScreenPos.Count; cow++)
{
//畫板和畫板的檢測
if (listScreenPos[row].trans != listScreenPos[cow].trans)
{
//在相交時,沿着向量方向移動,可以是任意現狀的物體相交,任意大小的物體相交
//兩個物體的位置的x位置和兩物體的y的位置 x<width*2 y<height*2
float centerX = Mathf.Abs(listScreenPos[row].screenPos.x - listScreenPos[cow].screenPos.x);
float centerY = Mathf.Abs(listScreenPos[row].screenPos.y - listScreenPos[cow].screenPos.y);
float centerZ = Mathf.Abs(listScreenPos[row].screenPos.z - listScreenPos[cow].screenPos.z);
if (centerX < (listScreenPos[row].width / 2 + listScreenPos[cow].width / 2) &&
centerY < (listScreenPos[row].height / 2 + listScreenPos[cow].height / 2)&&
centerZ < (listScreenPos[row].back / 2 + listScreenPos[cow].back / 2))
{
Vector3 dir = listScreenPos[row].trans.localPosition - listScreenPos[cow].trans.localPosition;
listScreenPos[row].trans.Translate(dir.normalized * Time.deltaTime*0.2F);
}
}
}
}
}
public class Info
{
public Transform trans;
public Vector3 screenPos;
public float width = 150;
public float height = 160;
public float back = 160;
}
}
矩形攻擊或 對於判斷前方是否觸發了NPC的判斷:
角色和NPC之間的向量爲DirVec
<1. 判斷Vector.Forword和DirVec的點乘,大於0,在前方。
<2. 滿足第一條後,在判斷DirVec在Vector.Forword方向的投影,長度是否是player的可視範圍。
扇形攻擊:扇形攻擊角度60度,半徑R, |A|=|NPC->player|,但是這樣檢測的截面是個平面,不是弧形。
<1. 算夾角<角度/2【30】
<2. |A|<R
圓和圓的碰撞檢測:對此向量求模長,後再和兩者半徑之和做比較
矩形和圓形物體的碰撞檢測:
思路:
<1. 先把矩形長寬擴張長度r. 擴張後新的矩形包含了圓心座標,再進行第二步
<2. 假設圓心在擴張後的四個角處,圓內有沒有包含長方形最近的頂點【擴張前矩形的某個頂點】,則圓和矩形沒有碰撞
細長形物體【激光\劍】與圓形物體的碰撞檢測:
滿足Lmin<r1+r2 ,則碰撞。
即求處Lmin的距離,把問題轉換爲點到線段的距離
而這個公式,是求點到一條無限長度的直線的距離,不可取。
向量表示直線上的位置向量p 【遊戲編程長用向量表示直線】:
扇形物體的碰撞檢測:
揮劍,受傷範圍
【定比分公式】
【圓與線段的交點判斷】
滿足上邊任意一條,則證明發生碰撞,在劍的傷害範圍內。但是一般優先檢測兩個不可能碰撞的條件
【即(圓心到扇心的距離) > (圓半徑+扇半徑)】
應用:
用向量點乘法計算是否在區域內
扇形攻擊:扇形攻擊角度60度,半徑R, |A|=|NPC->player|
<1. 算夾角<角度/2【30】
<2. |A|<R
矩形攻擊區域和扇形的攻擊區域怎麼判斷是否有交叉?【把面 的交叉轉換爲點的交叉】。
<1. 判斷矩形的中心點是否在扇形區域內,矩形的兩個頂點是否也在區域內
可視域應用:
轉一個案例: https://blog.csdn.net/u014528558/article/details/85106563
public class ConeSightTest : MonoBehaviour
{
public GameObject srcPos;
public GameObject endPos;
public float Dis;
public float angle;
public Transform[] pHead;
public Transform[] pFoot;
private void Start()
{
angle = Vector3.Angle(srcPos.transform.forward, endPos.transform.position - srcPos.transform.position);
Dis = Vector3.Distance(srcPos.transform.position, endPos.transform.position);
}
void Update()
{
for (int i = 0; i < pHead.Length; i++)
{
if (IsTargetBodyInSectorRange(srcPos.transform.position, srcPos.transform.forward,
angle, Dis, pHead[i].position, pFoot[i].position))
{
Debug.DrawLine(pHead[i].position, pFoot[i].position, Color.red);
}
else
Debug.DrawLine(pHead[i].position, pFoot[i].position, Color.green);
}
}
public static bool IsTargetInSectorRange(Vector3 srcPos, Vector3 srcDir, float srcAngle, float srcDist,
Vector3 tarPos)
{
Vector3 toTarVec = tarPos - srcPos;
float deltaAngle = Vector3.Angle(srcDir, toTarVec);
if (deltaAngle < srcAngle)
{
float dist = Vector3.Distance(srcPos, tarPos);
if (dist < srcDist)
{
return true;
}
}
return false;
}
public static bool IsTargetBodyInSectorRange(Vector3 srcPos, Vector3 srcDir, float srcAngle, float srcDist,
Vector3 tarHeadPos, Vector3 tarFootPos)
{
if (IsTargetInSectorRange(srcPos, srcDir, srcAngle, srcDist, tarHeadPos))
return true;
if (IsTargetInSectorRange(srcPos, srcDir, srcAngle, srcDist, tarFootPos))
return true;
if (tarFootPos.y <= srcPos.y && srcPos.y <= tarHeadPos.y &&
IsTargetInSectorRange(srcPos, srcDir, srcAngle, srcDist, new Vector3(tarFootPos.x, srcPos.y, tarFootPos.z)))
return true;
return false;
}
}
注意:
<1. 這個工程視野界面是平行的,和unity中的相機一樣,而且Dis應該還要計算一下在srcPos.transform.forward方向的投影才能作爲檢測距離。分別計算底部和頂部到在camera方向的投影的夾角是否<Camera-angle/2
<2. 這種方法不能檢測,障礙物遮擋障礙物的情況。應該使用LOS
https://www.cnblogs.com/yangrouchuan/p/6366629.html
<3. 只檢測了高度方向上的兩個點的。沒有檢測寬度方向上的兩個點