Unity實現任意兩點之間畫一條直線——bresenham算法(直線的處理)


    在家里閑着沒事,在網上看到一個好玩的需求,在亮點之間畫一條直線。

 聽起來很簡單,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; } }

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM