在家里閑着沒事,在網上看到一個好玩的需求,在亮點之間畫一條直線。
聽起來很簡單,unity就提供了很多的API,不過大部分是以屏幕畫一條線類似的方式做的。如果我們需要讓部隊等 一個集群排列成一條斜線呢?
其實這也和屏幕渲染一條直線的道理是一樣的。
屏幕要畫一條直線的話,其實也是在屏幕的像素坐標系里面x,y進行賦值,把連續數轉換成離散數,放大看的時候,就會看到一條直線其實是一條梯子狀的線。
在實際的場景中可以把我們的地圖當成一個屏幕,地圖最小格子單位當成一個屏幕的像素點,這樣就相當於構建了一套屏幕坐標系了
在網上找了很多的資料,但是都說的特別復雜,我找到一篇說的比較簡練清楚的。
cnblogs.com/feiquan/archive/2018/03/04/8506283.html
(此圖來源於網絡) 
圖中格子即為最小像素單位,設一條直線從p1到達p2 , p1的坐標為(0,0),作一個以p2,p1為頂點的直角三角形,可得tan ∠p1 = (p2.y - p1.y) / (p2.x - p1.x)
可算得 float value = tan ∠p1
通過∠p1的斜率可得出直線上某一個點的y值為是多少
因為格子已經是最小單位了,而y的高度可能為小數,所以需要做離散化處理
定義一個值當做校准指標,這里我們按0.5來算,每個點在經過像素單位的時候,將y小於0.5的按0來計算,並存儲,抹除掉的這個值我們統計起來。
float slope = 0
每計算一次點的坐標 slope = y + slope
當slope > 0.5的時候,y的坐標向上移一格,並清零。進行下一次的統計
直到遍歷完成
注意,這里需要考慮2種情況,這條直線在某個象限里面,角度小於45°的時候是以是y軸作為偏差值處理,也就是 0< tan ∠p1 <= 1的情況,在大於45°的情況,以此類推,就要把x當做偏差值處理了,不明白的小伙伴可以想象成,如果這個角度大於45°的話,把坐標系反轉一下,就是一個豎着的小於45°的角了然后直接照搬上述方式代入計算。
代碼只處理了0-90度情況,同理可以推導出 2/3/4象限的排列坐標,根據象限將x或者y取絕對值即可。
效果如圖
<45°的效果

>45°的情況

接下來上代碼
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bresenham : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
List<Vector2> mList = GetPointList(new Vector2(0,0),new Vector2(10,128));
for (int i = 0; i < mList.Count; i++)
{
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
Vector2 pos = mList[i];
cube.transform.position = new Vector3(pos.x,pos.y,0);
}
}
public List<Vector2> GetPointList(Vector2 startPos,Vector2 endPos)
{
//構建直角三角形
//distance_y為對邊
//distance_x為直角邊
float distance_x = endPos.x - startPos.x ;
float distance_y = endPos.y - startPos.y ;
float slope_x = distance_y / distance_x ; //tan 求斜率
float slope_y = distance_x/distance_y ;//當slope_x > 1
Vector2 pos = startPos;
float y = startPos.y;
float x = startPos.x ;
int num = 0 ;
float sumValue = 0; //累計值
List<Vector2> posList = new List<Vector2>();
posList.Add(startPos);
//45度內
if (slope_x > 0 && slope_x <= 1)
{
for (int i = 0; i < distance_x; i++)
{
y = posList[num].y;
x = x + 1 ;
sumValue = sumValue + slope_x;
if (sumValue > 0.5f)
{
sumValue = 0;
y += 1;
}
num += 1;
posList.Add(new Vector2(x,y));
}
}else if(slope_x > 1 )
{
for (int i = 0; i < distance_y; i++)
{
y = y + 1;
x = posList[num].x ;
sumValue = sumValue + slope_y;
if (sumValue > 0.5f)
{
sumValue = 0;
x += 1;
}
num += 1;
posList.Add(new Vector2(x,y));
}
}
return posList;
}
}
