[Flutter] 양들의 언덕

Noah·2024년 3월 5일
0

Flutter

목록 보기
1/11
post-thumbnail

양들의 언덕
https://hill-of-sheep.web.app/

프로젝트 개요

  • 데이터를 받아서 보여주는 단순 프론트엔드 개발은 누구나 할 수 있다는 생각이 들었다.
  • 애니메이션이 들어가고, 상호작용이 있는 작업을 하며 성장하고 싶었다.

프로젝트 목표

  • 움직이는 언덕과 양을 표현
  • 이글거리는 태양 표현
  • 문제 해결 능력 키우기

기능 소개

  • 곡선으로 언덕 그리기
  • 뎁스에 따라 속도가 다른 연출
  • FPS 개념을 코드에 추가
  • 곡선 위의 좌표와 각도 찾기
  • 선이 지글지글 거리는 스케치 효과
  • 스크린 사이즈에 따라 달라지는 언덕과 양의 속도
  • 계속해서 생성되는 요소를 지니는 리스트의 관리

문제 사항

1. 언덕을 어떻게 그릴까?

  • CustomClipper의 path.quadraticBezierTo()를 이용해 점과 점 사이를 잇는다.
final double cx = (pre.x + cur.x) / 2;
final double cy = (pre.y + cur.y) / 2;
      
// 곡선 그리기
path.quadraticBezierTo(pre.x, pre.y, cx, cy);

2. 언덕 위에 움직이는 양의 y좌표를 어떻게 구할까?

  • 언덕의 곡선을 잘게 나누고 각 영역의 x, y좌표를 구한다. (2차 베지어 수식 사용)
  • 양의 현재 x좌표와 가장 근접한 x좌표의 y좌표를 양의 y좌표로 한다.
// 2차 베지어 곡선 수식 (곡선)
double getQuadValue(double p0, double p1, double p2, double t) {
  return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2;
}

3. 양의 기울기는 어떻게 표현할까?

  • 언덕의 곡선을 잘게 나누고 각 영역의 x, y좌표를 구한다. (2차 베지어 수식 사용)
  • 아크탄젠트를 이용해서 각도를 구한다.
  • Transform.rotate로 기울기를 표현한다.
// 2차 베지어 곡선 수식 (직선)
double quadTangent(double a, double b, double c, double t) {
  return 2 * (1 - t) * (b - a) + 2 * (c - b) * t;
}
// 각도 구하기
final tx = quadTangent(x1, x2, x3, t);
final ty = quadTangent(y1, y2, y3, t);
final double rotation = atan2(ty, tx);

4. 태양의 이글거리는 모습은 어떻게 표현할까?

  • 원을 그리는 좌표를 2개의 리스트에 담는다. (Sine, Cosine 이용)
// 원 좌표 가져오기
Point getCirclePoint({required double t}) {
  final double theta = pi * 2 * t;

  return Point(cos(theta) * radius, sin(theta) * radius);
}
const double gap = 1 / total;

// 포인트 세팅
for (int i = 0; i < total; i++) {
  final Point point = getCirclePoint(t: gap * i);
  originPoints.add(point);
}
    
// element 얕은 복사를 위해
points = originPoints.map((e) => Point(e.x, e.y)).toList();

  • 보여주는 리스트의 좌표를 원조 리스트의 좌표를 참고하여 랜덤으로 변경한다.
// 포인트 랜덤 변경
List<Point> updatePoints() {
  for (int i = 1; i < total; i++) {
    final Point p = originPoints[i];

    points[i].x = p.x + Random().nextInt(sunVariable);
    points[i].y = p.y + Random().nextInt(sunVariable);
  }

  return points;
}

5. FPS개념을 어떻게 도입할까?

  • Timer.periodic을 이용해 초당 30번 랜더링한다.
Timer.periodic(
  $style.times.ms33, // 30fps
  (_) {
    updatePoints();
    update();
  },
);

성과

  • CustomClipper의 활용법
  • 2차 베지어 곡선의 활용법
  • 아크탄젠트의 활용법
  • Sine, Cosine을 이용해 원의 좌표를 얻는 방법
  • FPS 개념 도입 경험

소스 코드
https://github.com/jsk9106/hill_of_sheep

회고

그동안 개발 자체보다는 비즈니스에 중점을 뒀다. 개발은 문제를 해결하기 위한 수단이라 생각해 쉽고 빠르게 프로덕트를 만들어내는 것에 집중했다.

하지만 여러 서비스를 만들며 느낀 점 "기술 없이 나오는 서비스는 큰 밸류를 만들어내기 어렵다."과 무서운 속도로 발전하는 AI는 특별한 성장 방법을 찾게 만들었다.

그러던 중 Interactive 개발자의 영상을 접했다. 컴퓨터 기술로 표현하고자 하는 것을 멋지게 해내는 것이 내겐 신선한 충격이었다. "나도 저렇게 할 수 있을까?"라는 도전의식을 불태우게 되는 계기가 되었다.

그래서 시작한 프로젝트가 "양들의 언덕"이다. Interactive 개발자가 javascript로 만든 영상을 보며 Flutter로 만들었다. 핵심 기능과 개념이 소개가 되어있어서 크게 어렵지 않게 만들 수 있었다. 라고 하고 싶지만, 꼬박 5일 동안 작업을 했다.

방법이 나와있는 데 오래 걸린 이유는 모든 코드와 수식을 이해하고 싶었기 때문이다.

  • 움직이는 언덕을 어떻게 만드는지
  • 배열에 좌표를 계속 추가한다면, length 관리는 어떤 식으로 하는지
  • 30fps로 화면을 빌드하면 성능에 무리가 없는지
  • 베지어 곡선, 아크탄젠트는 무엇이고 어떤 상황에 쓰이는지
  • Stateful 위젯과 GetBuilder를 사용한 것중 어떤 것이 더 효과적인지
  • 지글거리는 태양의 랜덤 좌표는 왜 -가 아닌 +로 했는지

등 많은 궁금증이 있었다. 성장하기 위해 스스로 질문하고 답을 찾아가는 과정이었다. 단순히 클론 코딩이 아니라 문제를 찾아 해결했다. (상태관리, 스크린 사이즈에 따라 속도가 달라지는 기능 등)

이번 프로젝트를 통해 얻은 게 몇 가지 있다.

  • 수학을 통해 불가능해 보이는 것들을 해낼 수 있다.
    (수식 자체를 이해하지 못해도 쓰임새를 알면 충분히 활용 가능하다.)
  • 모든 복잡해 보이는 코드는 하나의 점에서부터 시작된다.
    ex) 움직이는 언덕을 만들기 위해 가장 먼저 점을 찍는 것처럼
  • 개발은 문제를 해결하기 위한 수단이지만, 실력이 있어야 문제를 해결할 수 있다.
  • 가진 실력을 멋지게 풀어내려면 비즈니스에 대한 이해기획 능력이 필요하다.

당분간은 Interactive 개발 공부를 할 생각이다. Flutter 스페셜리스트가 되려면 상상 가능한 모든 UI를 그릴 수 있어야 한다.

해당 프로젝트는 Interactive Developer님의 영상을 참고했습니다.
https://www.youtube.com/watch?v=hCHL7sydzn0&t=233s

profile
Flutter Specialist

0개의 댓글