본문 바로가기

code/Unity

[유니티] 심전도 그래프 그리기 - 1. 점 찍기

팀 프로젝트에서 심전도 그래프 그리는 기술이 필요하다.
파이썬으로도 실시간 그래프를 그릴 수 있지만, 메타버스 환경 화면에서 그래프 화면을 바로 띄우고 싶어 유니티로 구현을 시도해봤다.
 
1. 라즈베리파이에서 실시간으로 txt파일에 심전도 데이터를 기록
2. 그 txt파일을 실시간으로 pc(또는 서버)에 전송
3. pc 또는 서버에 있는 심전도 txt파일을 유니티에서 읽어, 실시간으로 그래프 그림 <<3번 과정의 내용이다.
 
3-1. https://dhshin94.tistory.com/m/160
참고해서 그래프 기본 틀 만들기
3-2. https://coderzero.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%86%8C%EC%8A%A4-%ED%85%8D%EC%8A%A4%ED%8A%B8txt-%ED%8C%8C%EC%9D%BC-%EC%9D%BD%EA%B3%A0-%EC%93%B0%EA%B8%B0
참고해서 txt 파일에서 값을 불러와 점 찍기 
3-3. 점이 그래프 가로 길이 넘어서까지 추가되면 초기화한 뒤 다시 그리는 기능 추가

이렇게 구상하고 들어갔는데, 실제로 코드 짜다보니 바뀐 게 좀 있다. 챗지피티 도움도 많이 받았다...

 

기본 세팅

계층 구조 / 프리팹 인스펙터 / GraphArea에 스크립트 걸고 설정

using UnityEngine;
using UnityEngine.UI;
using System;

public class GraphMakerChatGPT : MonoBehaviour
{
    public GameObject DotPrefab;    // 그래프 점 프리팹
    public Transform DotGroup;      // 생성한 그래프 점을 자식으로 가질 부모 오브젝트
    public RectTransform GraphArea; // 그래프 영역의RectTransform

    private float graph_Width;
    private float graph_Height;                            // 그래프 영역의 길이, 높이 저장할 변수
    private const int ArraySize = 100;                     // 가로 점 갯수
    private int[] HeartBeatValue = new int[ArraySize];     // 심전도값 저장할 배열 ArraySize개 만들기 > 값 0으로 통일
    private GameObject[] dots = new GameObject[ArraySize]; // 생성된 점들을 저장할 배열

    private int currentIndex = 0;
    private float timePassed = 0f;          // 경과한 시간을 추적
    private const float updateTime = 0.1f;  // 그래프를 업데이트할 시간 간격(0.1초)
    //const : 1. 반드시 선언과 동시에 값 초기화 2. 한번 값이 할당되면 이후 변경 불가능 3.자동으로 static

    private const int MaxValue = 1000;    //그래프 최댓값

    void Start() //시작할때 실행하는 함수
    {
        graph_Width = GraphArea.rect.width;
        graph_Height = GraphArea.rect.height;
    }

    void Update() //프레임마다 실행하는 함수
    {
        timePassed += Time.deltaTime; // Unity 엔진에서 프레임 간 경과 시간을 나타내는 변수
                                      // 각 프레임 사이의 시간 간격

        if (timePassed >= updateTime)
        {
            timePassed = 0f;

            var rand = new System.Random();
            int HeartBeat = rand.Next(0, MaxValue); // 심전도 값 랜덤 부여 (본편때는 텍스트에서 불러온값으로 변경하기)

            HeartBeatValue[currentIndex] = HeartBeat;
            DrawGraph(HeartBeatValue[currentIndex], currentIndex);

            if (currentIndex + 1 == ArraySize){     // 가로 다채우면 모든 값 0으로 바꾸기
                for (int i = 0; i < ArraySize; i++) HeartBeatValue[i] = MaxValue / 2;
                for (int i = 0; i < ArraySize; i++) DrawGraph(HeartBeatValue[i], i);
            }
            
            currentIndex = (currentIndex + 1) % ArraySize; // 다음 인덱스로 이동
        }
    }

    private void DrawGraph(int value, int index)
    {
        float startPosition = -graph_Width / 2;     // 그래프 영역의 길이 / 2 에 -를 붙이면 시작위치
        float maxYPosition = graph_Height * 2/3;      // 그래프 영역의 높이 * 2/3 => 점을 찍을 최대 높이

        if (dots[index] == null){    // 이전에 생성된 점이 없는 경우 점 오브젝트 생성 및 부모 설정
            dots[index] = Instantiate(DotPrefab, DotGroup, true);
        }

        //각 컴포넌트 가져오기
        RectTransform dotRT = dots[index].GetComponent<RectTransform>();
        Image dotImage = dots[index].GetComponent<Image>();

        float yPosOffset = value / (float)MaxValue; // 그래프의 최댓값으로 나눠, 값을 0과 1 사이로 정규화

        dotRT.anchoredPosition = new Vector2(startPosition + (graph_Width / (ArraySize - 1) * index), maxYPosition * yPosOffset - graph_Height/3);
    }
}

 

 

 

C#과 유니티가 이번이 처음이라 많이 헤맸다.