Fluter로 매칭 게임을 만들었다면

개시하다


개인이 개발한 borber라는 응용 프로그램이 발표되었다.내용에 관해서는 상점을 열람해 주십시오. 그러니 제가 사랑을 끊는 것을 허락해 주십시오.친구랑 꼭 놀아요.(다행히도 호평을 받았다.)
iOS
https://apps.apple.com/jp/app/borber/id1559548637
Android
https://play.google.com/store/apps/details?id=app.borber
그리고× 웹소켓 구성이라 행동이 어떤지, 조사 목적도 전혀 상관없으니 꼭 한번 놀아보세요.
플루터제의 매칭 대전 게임 사례를 들어본 적이 없어 기사 제목에'플루터 최초'를 노래했다.(만약 선례가 있다면 나에게 알려주시오🙇‍♂️)
전례를 알려주셨기 때문에 제목을 수정하겠습니다.🙇‍♂️

작문 목적


플랫터로 매칭 게임을 만들고 싶은 사람을 조금만 참고해 주시면 좋을 것 같아요.
그리고 개인 개발에 관한 팁 등을 공유할 수 있었으면 좋겠어요.
※ 이 앱은 격렬한 UI 그리기가 없습니다.

기술을 사용하다

  • Flutter(riverpod, state_notifier, freezed, flutter_hooks)
  • Fluter for Web(규약 및 개인 정보 보호 정책을 위해 사용)
  • Node(typescript, socket.io)
  • Redis
  • Firebase(firestore, storage, functions, remoteConfig, hosting)
  • Github Actions
  • 일치 대전의 실현 방법


    이번에 채택한 기술은 이런 유명한 웹소켓이다.
    간단하게 말하면 이것은 서버를 통해 고객 간의 양방향 통신을 실현할 수 있는 기술이다.

    서버


    노드 상.io를 통합하여 WebSocket 서버를 만드는 중입니다.
    친구 대결처럼 특정 이용자만 들어갈 수 있는 방도 간단히 가능하다.
    https://socket.io/

    데이터베이스


    대기 중인 사용자와 일치하는 상태를 유지하기 위해 사용합니다.이번에 리디스를 채택했습니다.
    간단한 데이터 구조를 실현하고 대기 중인 사용자가 먼저 들어오고 먼저 나가게 하는 대기열을 만들고 싶다는 이유(아래 그림 참조).

    리디스는 lpush와 rpop의 방법이 있는데 이런 방법을 사용하면 클럽을 쉽게 만들 수 있다.
    http://redis.shibu.jp/commandreference/lists.html

    클라이언트


    socket.Flutter를 대상으로 IO 고객을 만드는 프로그램 라이브러리가 있기 때문에 그것을 사용합니다.
    https://pub.dev/packages/socket_io_client
    설치 절차는 문서와 같이 내가 사랑을 끊는 것을 허락해 주십시오.
    주의점은 프로그램 라이브러리의 오류입니까?issue에서는 말하지만, socket을 만들 때 서버에 자동으로 연결하는 기능이 있습니다. (기본값은 ON입니다.)다만, 이 기능은 발동이 불안정해 스스로 명확하게 연결하는 것이 안전하다.아래와 같이 자동 연결 기능 (autoConnect 매개 변수) 을 닫고connect만 실행합니다.
    const url = 'socketサーバのURL';
    final socket = IO.io(url, <String, dynamic>{
        'transports': ['websocket'],
        'autoConnect': false,
    });
    
    socket.connect();
    

    견본


    on 방법으로 서버에서 호출하고 emit 방법으로 서버에 요청합니다.이 일의 한 예.실제 코드는 아니지만 실장한 인상을 주기 쉽다.
    겸사겸사 말씀드리지만, 저는 flutter입니다.훅스의useEffect(초기화 처리와 한 번만 실행하고 싶을 때 활성화)를 이용하여 실현한다.간단하게 초기화 처리를 할 수 있기 때문에 추천합니다.
    // socket変数は、socket.ioクライアントのインスタンス
    
    useEffect(() {
    
        // サーバ接続時に呼ばれる
        socket.onConnect((dynamic data) {
            // ランダム対戦の場合
            if (isRandomMatching) {
    	    // サーバ側でマッチング成功したらここが呼ばれる。第二引数に、レスポンスが入る。
    	    socket.on('successful_matching', (dynamic data)) {
    	        // TODO
    	    }
    	    
    	    // ランダム対戦のリクエストをサーバへ送信。第二引数に、必要なパラメータを渡す。
    	    socket.emit('random/match', randomMatchingInfo);
    	    return;
    	}
    	
    	// フレンド対戦の場合
    	// サーバ側でマッチング成功したらここが呼ばれる。第二引数に、レスポンスが入る。
    	socket.on('successful_matching', (dynamic data)) {
    	    // TODO
    	}
    	
    	// 入室しようとした部屋が満員であればここが呼ばれる。第二引数に、レスポンスが入る。
    	socket.on('error_room_is_full', (dynamic data)) {
    	    // TODO
    	}
    	
    	// フレンド対戦のリクエストをサーバへ送信。第二引数に、必要なパラメータを渡す。
            socket.emit('friend/match', friendMatchingInfo);
        });
        
        return null;
    }, const []);
    
    ※ 원래는 가독성을 높이기 위해 코드를 분열시켰지만, 샘플을 위해 네모난 테두리로 표현했습니다."successful_matching 및 errorroom_is_풀로 쓰여 있지만 가장 적합한 명명 규칙을 파악하지 못했다.

    Firestore의 rule


    사용자 정보를 저장하는 DB로서 Firestore를 사용하지만 보안을 위해 보안 규칙을 적용해야 합니다.하지만 이번에는 인증 기능을 사용하지 않아 제대로 제한할 수 없었다.
    이 경우 CloudFunction을 사용하여 DB 작업을 Admin으로 제한합니다.그리고 이 방법들을 응용 프로그램에서 실행에 옮겨라.
    https://firebase.google.com/docs/functions/callable?hl=ja
    이로써 관리자 이외의 모든 조작을 받아들이지 않는 최강의 안전 규칙이 완성되었다.
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /{document=**} {
          allow read, write: if false;
        }
      }
    }
    

    CI/CD


    개인 개발이라면 자신 이외의 사람에게 개발 중인 앱을 펼치지 않기 때문에 게시할 때 가져오는 것도 일석이조로 효율적이다(포장을 자동으로 상점에 업로드하기 위해 조립하면 바로 게시할 수 있다).사실 나는 그 일정에 따라 진행했다.
    기본적으로, Flutter× GiithubActions의 CI/CD는 아래의 보도만으로도 완성되었다(매우 참고 가치가 있다).
    https://zenn.dev/pressedkonbu/articles/254ca2fc3cd1ab
    https://zenn.dev/pressedkonbu/articles/github-actions-for-android
    만약main지점이 공약에 가입하면 iOS/Android의 포장은 각각 상점에 업로드되어 업데이트 작업이 수월해집니다.

    최후


    Flutter에서 앱을 개발한 것은 이번이 세 번째지만 개발 체험이 매우 좋다.

    좋은 웹페이지 즐겨찾기