개발자를 위한 퍼즐인 Purrfect Code를 개발한 방법

8월 01, 2024

Link to Youtube Video (visible only when JS is disabled)

'Purrfect Code'는 Flutter, Dart 및 Flame 게임 엔진으로 구동되는 새로운 상자 밀기 프로그래밍 퍼즐로, 개발자가 코드를 작성함으로써 퍼즐을 풀도록 고안된 게임입니다.


게임 개요

'Purrfect Code'에서 플레이어의 임무는 고양이를 실은 선적물이 잘못 도착한 Google의 새로운 우주정거장 본부에서 청소부 로봇의 프로그래밍을 업데이트하는 것입니다. 이 게임의 목표는 고양이가 들어 있는 상자들을 로봇이 안전하게 한곳에 잘 모아 텔레포터 플레이트로 밀어 올려 고양이가 무사히 집으로 돌아갈 수 있도록 하는 것입니다. 플레이어는 그리드 기반 퍼즐을 탐색하는 효율적인 해결책을 찾으려 노력하면서 로봇 움직임을 제어하는 JavaScript를 작성합니다.

이 게임을 통해 지능과 창의력을 활용해 재미있게 코딩을 탐구할 수 있습니다. 각 레벨은 프로그래밍 개념에 초점을 맞추고 있으며 5가지 레벨이 진행되는 동안 풀어야 할 과제가 서서히 복잡해집니다.

게임 루프는 다음과 같습니다.

  1. 플레이어가 로봇을 움직이는 JavaScript 코드를 작성함(상하좌우로 움직이도록 함)

2. 그런 다음 코드를 실행하여 로봇이 해당 레벨의 퍼즐을 풀려고 시도하는 모습을 지켜봄

3. 고양이가 들어 있는 상자를 전부 텔레포터 플레이트로 밀어 올리면 레벨이 완료됨

4. 플레이어는 이동한 공간의 수와 코드의 간결성을 포함한 문제 해결 방법의 효율성에 따라 점수를 받음

Flutter, Dart, Flame을 사용한 게임 개발

저희는 멀티 플랫폼 애플리케이션 및 게임을 만드는 데 있어 강력하고 유연한 프레임워크를 제공하는 Flutter와 Dart를 사용하여 'Purrfect Code'를 개발하기로 했습니다. Flutter의 위젯 시스템과 반응형 프로그래밍 모델을 통해 브라우저에서 다양한 화면 크기에 맞는 반응형 사용자 인터페이스를 만들 수 있었습니다. 강력하게 형식이 지정되고 객체 지향적인 Dart의 프로그래밍 기능 덕분에 코드를 손쉽게 구조화하고 코드베이스를 깔끔하게 유지할 수 있었습니다. Flutter를 기반으로 개발된 Flame 게임 엔진이 게임 개발에 필요한 기본 기능으로 구성된 훌륭한 토대를 제공한 덕분에, 게임플레이 로직과 게임의 고유한 측면에 오롯이 집중할 수 있었습니다. IDE에서 영감을 얻은 UI 애니메이션 스프라이트와 사운드를 갖춘 게임 뷰를 모두 구비한 고유한 게임/앱 하이브리드라는 Purrfect Code의 뚜렷한 특성을 고려했을 때, Flutter와 Flame은 이 프로젝트에 의심의 여지 없는 최고의 선택이었습니다.


Chrome과 JavaScript: 기본 제공 브라우저 지원 기능 활용

게임의 프로그래밍 개념을 정한 후에는 플레이어가 사용할 프로그래밍 언어를 선택해야 했습니다. 개발자들 사이에서 친숙하고 인기 있는 언어를 선택하고자 했습니다. 처음에는 Python을 게임 내 프로그래밍 언어로 사용할까 생각했습니다. 그러나 고민 끝에 Chrome에서 기본으로 제공하는 JavaScript 지원 기능을 활용할 수 있도록 JavaScript를 게임 내 언어로 결정했습니다. JavaScript를 활용하면 언어 인터프리터를 추가로 로드할 필요 없이 브라우저의 기본 기능을 활용할 수 있습니다. 이 결정 덕분에 개발 프로세스가 간소해졌을 뿐만 아니라 최소한의 종속성으로 게임을 빠르게 로드할 수 있어 플레이어에게 원활한 환경을 보장할 수 있었습니다.

올해 Google I/O에서 선보인 Flutter 3.22 버전에서는 게임에서 성능이 매우 중요한 역할을 하는 부분을 최적화할 수 있는 WASM(WebAssembly)을 위한 안정적인 지원을 도입했습니다. 특정 게임 로직을 WASM으로 컴파일함으로써 'Purrfect Code'가 브라우저에서 효율적으로 실행되어 성능 저하 없이 원활하고 반응이 빠른 게임 경험을 제공할 수 있도록 했습니다.

var dir = [moveEast,moveNorth,moveWest,moveSouth];
for(i=0;i<4;i++){
    for(j=0;j<5;j++)dir[i]();
}

Flame 게임 엔진: 모듈식의 효율적인 게임 개발

'Purrfect Code'를 실현하기 위해서, 게임 개발에 일반적으로 필요한 많은 기능을 제공하는 Flutter를 기반으로 개발된 오픈소스 모듈식 게임 엔진인 Flame Game Engine을 활용했습니다. Flame은 Flutter의 강력한 인프라를 활용하는 동시에 프로젝트 개발에 필요한 코드를 단순화합니다. 간단하면서도 효과적인 게임 루프 구현과 오디오 재생, 스프라이트 관리, 애니메이션 기능, 충돌, FCS(Flame Component System) 등의 폭넓고 다양한 필수 기능을 제공합니다. 엔진의 구성요소 기반 아키텍처, 스프라이트 렌더링, 애니메이션 지원을 통해 시간 낭비 없이 시각적으로 매력적인 그래픽, 매끄러운 애니메이션, 대화형 게임플레이 요소를 만들 수 있었습니다. Flame을 활용하면 필수 기능을 바로 사용할 수 있으므로 개발 프로세스의 효율성이 더욱 높아져 플레이어를 위해 매력적인 게임 환경을 만드는 데 집중할 수 있었습니다.


Flame을 사용한 게임 기능 구현

Flame은 간단하면서도 효과적인 게임 루프 구현과 오디오 재생, 스프라이트 관리, 애니메이션 기능, 충돌, FCS(Flame Component System) 등의 폭넓고 다양한 필수 기능을 제공합니다.

Flame의 스프라이트 렌더링 및 애니메이션 시스템 덕분에 그래픽 코드를 작성하지 않고도 게임의 캐릭터와 환경에 생명을 불어넣을 수 있었습니다. 스프라이트 시트를 만들고, 애니메이션 시퀀스를 정의하고, 캐릭터의 움직임과 특수 효과를 매끄럽게 애니메이션으로 표현할 수 있었습니다. Flame의 우선순위 시스템을 사용하여 '하향식' 게임 관점을 위한 시각적 정렬 시스템을 작성했습니다. Google의 아티스트는 스프라이트로 깊이감을 향상시키고 게임 뷰가 덜 '그리드같이' 보이도록 많은 기능이 중첩된 레벨을 만들었습니다. 로봇이 그 뒤에서 움직일 때 제대로 가려지도록 해야 했습니다. Flame의 우선순위 시스템 덕분에 다양한 시각적 요소에 우선순위를 할당하여 올바른 순서로 그려지고 적절히 겹치도록 할 수 있었습니다. 이 시스템은 그림자 시스템을 포함시킬 수 있을 정도로 매우 유연했습니다. 이 그림자 시스템에서는 객체 동작을 반영하고 장면을 더 생동감 있고 시각적으로 이해하기 쉽게 만들어주는 깊이감을 그림에 부여하는 애니메이션 그림자를 개별 구성요소가 가질 수도 있습니다.

코드베이스의 BoxShadow 클래스는 이에 대한 적합한 예시로서, 게임에서 움직이는 상자 객체에 대한 다이내믹하고 인터랙티브한 그림자를 만든 방법을 보여줍니다. SpriteAnimationComponent를 확장하고 GridElement 및 HasVisibility 믹스인을 구현함으로써 상자 그림자 및 상자 텔레포트 애니메이션에 대한 스프라이트 시트를 로드하고, 열림, 닫힘, 유휴 상태, 텔레포트 상태에 대한 여러 애니메이션을 정의하고, 이를 그리드 기반 레이아웃에 통합할 수 있었습니다. onLoad 메서드는 애니메이션을 로드하고 그리드 위치를 기준으로 구성요소의 초기 위치와 우선순위를 설정하는 반면, update 메서드는 상자가 그 상자를 가리는 객체 앞이나 뒤로 움직이는 경우 구성요소의 우선순위가 동적으로 업데이트되도록 합니다. Flame의 우선순위 시스템 및 애니메이션 시스템을 이러한 방식으로 사용하여 항상 사용자가 가상 공간을 시각적으로 이해하고, 이를 보다 현실감 있게 만들고, 보다 통합된 시각적 프레젠테이션으로 이어지는 그림자 효과를 만들 수 있었습니다.

box_shadow.dart에서 발췌, 자세히 알아보려면 GitHub의 전체 클래스를 확인해 보세요.

@override
  Future<void> onLoad() async {
    await _loadAnimations().then((_) => {animation = _boxClosed});
 
 
    position.add(Vector2(
        ((gridPosition.x * gridPixelDimensions.x) + gridPixelOffset.x),
        ((gridPosition.y * gridPixelDimensions.y) + gridPixelOffset.y)));
    priority = getLayeredGridValue();
  }
  @override
  void update(double dt) async {
    super.update(dt);
 
 
    if (getLayeredGridValue() != priority) {
      priority = getLayeredGridValue();
    }
  }

Google 개발자 프로그램 및 배지

게임의 범위를 작게 유지하고 단순한 웹페이지로 배포할 수 있기를 원했으므로 게임의 백엔드 설정을 피하고 싶었습니다. 하지만 인기 있는 게임 플랫폼의 업적 시스템처럼 개발자들이 진행에 대한 보상을 받을 수 있는 방법이 있으면 했습니다. 플레이어의 진행 상황과 업적을 추적하기 위한 별도의 백엔드 시스템을 개발하는 대신, 플레이어가 레벨을 완료한 후 링크를 클릭하고 프로필에 배지를 수집할 수 있도록 함으로써 Google 개발자 프로그램과 통합했고 이를 통해 개발자 커뮤니티 내에서 성취감과 인정받는 느낌을 선사합니다.

Purrfect Code Google Developer Program profile badges

Project IDX: 간소화된 개발 환경

Purrfect Code"를 개발하는 동안 우리는 클라우드에서 풀 스택, 멀티 플랫폼 앱 개발을 위한 AI 지원 작업 공간인 Google의 Project IDX를 활용했습니다. 우리는 이미 VS Code 작업에 익숙했기 때문에 Project IDX는 게임 코딩, 디버깅, 테스트를 위한 친숙한 환경을 제공했고 빠르게 시작하고 실행할 수 있도록 해주었습니다. Flutter와 Dart가 이미 설정되어 브라우저에 들어갈 준비가 되었기 때문에 번거로운 로컬 환경 구성 없이 바로 개발에 착수할 수 있었습니다. Project IDX가 제공하는 지능형 코드 완성, 실시간 오류 확인 및 통합 디버깅 도구는 생산성을 높게 유지하는 데 도움이 되었습니다. 궁금하다면 Project IDX는 Purrfect Code를 빠르게 시험해 보고 브라우저에서 직접 코드를 탐색할 수 있는 좋은 방법입니다. IDX에서 직접 프로젝트를 열고 프로젝트를 직접 실행하려면 이 링크를 클릭하세요. Flutter 앱인지 묻는 상자를 선택하세요.


빠른 보안 호스팅을 위한 Firebase

저희는 Purrfect Code의 안전하고 효율적인 글로벌 전송을 보장하기 위해 Firebase Hosting을 선택했습니다. 플랫폼의 제로 구성 SSL은 콘텐츠가 HTTPS를 통해 제공되도록 보장하여 보안을 강화합니다. 또한 GitHub 저장소에서 최신 웹 프레임워크 및 자동화된 빌드를 지원하여 업데이트를 신속하게 배포할 수 있었습니다. Firebase CLI, 로컬 에뮬레이션, 미리보기 URL은 테스트 및 협업 프로세스를 간소화했습니다. AI 통합을 위해 Gemini 샘플 템플릿을 활용한 향후 게임 발전의 가능성과 더불어 이러한 기능 덕분에 Firebase Hosting은 게임 출시를 위한 이상적인 선택이었습니다.


WASM을 사용한 Firebase 구성

Purrfect Code는 배포 중에 몇 가지 추가 단계가 필요한 Web Assembly를 사용합니다. firebase.json 구성에서 웹 빌드를 WASM으로 개발할 수 있는 사전 배포 명령을 추가합니다. '--no-strip-wasm' 인수는 오류를 읽고 디버깅하기 더 어렵게 만드는 마지막 최소화 단계를 코드가 거치지 않도록 합니다. 또한 WASM에서는 멀티 스레딩과 메모리 공유를 위해 크로스 오리진 오프너 정책과 크로스 오리진 임베더 정책도 필요합니다.

"hosting": {
      "predeploy": "flutter build web --wasm",
      "public": "build/web",
      "ignore": [
        "firebase.json",
        "**/.*"
      ],
      "headers": [
        {
          "source": "**/*",
          "headers": [
            {
              "key": "cross-origin-opener-policy",
              "value": "same-origin"
            },
            {
              "key": "cross-origin-embedder-policy",
              "value": "require-corp"
            }
          ]
        }
      ]
    }

학습 및 리소스

'Purrfect Code'를 개발하는 내내 저희는 다양한 리소스를 사용하고 기존 프로젝트에서 영감을 받았습니다. 이 프로젝트도 영감을 주는 리소스로 추가될 수 있기를 바랍니다. 몇 가지 유용한 주요 학습 자료와 참고 자료는 다음과 같습니다.


참조 프로젝트

Super DashI/O Flip 게임을 참조하여 권장사항 및 구현 아이디어를 얻었습니다. 두 프로젝트 모두 Flutter 게임 구조화, 게임 상태 처리, 게임 메커니즘 구현에 대한 귀중하고 유용한 정보를 얻는 데 도움이 되었습니다. Super Dash는 저희가 만든 게임처럼 간단하고 백엔드 서비스가 필요하지 않았으므로 직접적인 관련이 있었습니다. I/O Flip은 크기가 더 컸으며 백엔드뿐 아니라 생성형 AI 기능도 지원하므로 이러한 기능이 필요한 게임을 개발하는 개발자가 관심을 가질 만했습니다. Flutter로 게임을 만드는 데 관심이 있다면 두 가지 모두 귀중한 리소스입니다.


결론

완벽한 코드"가 즐거운 게임 경험을 제공할 뿐만 아니라 Flutter 및 Flame을 사용한 게임 개발에 관심이 있는 개발자에게 학습 리소스가 되기를 바랍니다. Flutter, FlameChrome의 조합이 매우 적합하다는 것이 입증되었습니다. 게임/앱 하이브리드를 위해 UI 개발, 그래픽 렌더링, 사운드 관리 등을 위한 견고한 기반을 제공합니다. 게임의 소스 코드를 탐색하고 추가 확장을 실험해 보시기 바랍니다. 새로운 기능, 레벨, 게임플레이 메커니즘을 추가할 수 있는 가능성은 무궁무진합니다. Project IDX의 코드베이스로 이동하여 Flutter 앱인지 묻는 상자를 선택하고 창의력을 마음껏 발휘해 보세요!