구민

구민님의 아티클

구민

구민

그라운드 플립이 초기 사용자 1000명을 모은 방법

스크린샷 2024-09-29 오전 5.12.22.png

최근에 너무 고맙게도 그라운드 플립의 누적 사용자수가 1000명을 돌파했다!! 1000명을 돌파하리라고는 예상도 못했는데 설치해주신 분들께 너무 감사하다.

그래서 1000명을 돌파한 기념으로 어떻게 유저 1000 명을 모을 수 있었는지에 대해 글을 써보려고 한다. 실제 사용자들을 모으는 것이 목표인 분들께 도움이 되면 좋겠다.

그라운드 플립이란?

zxc.png

우선 그라운드 플립은 어떤 서비스이길래 1000명이나 설치 했을까? 그라운드 플립을 한마디로 소개하자면 땅따먹기 만보기 서비스이다. 단순히 걷는 것에서 끝나지 않고, 걸은 길을 점령할 수 있는 시스템을 제공한다. 내가 걷는 경로가 내 땅이 되고, 다른 사람들이 점령한 영역도 뺏을 수도 있다.

걸으면 걸을수록 점령한 영역이 지도에 표시되고, 다른 사용자와 경쟁하는 재미를 느낄 수 있는 서비스이다. 현재 앱스토어와 플레이스토어에 배포되어 있으니, 언제나 다운로드해서 땅따먹기를 할 수 있다!

[iOS] : https://apps.apple.com/app/ground-flip/id6550922550

[Android] : https://play.google.com/store/apps/details?id=com.m3pro.ground_flip

[소개 사이트] https://ground-flip2.imweb.me/

출시 초반

출시 초반 부터 많은 사람들이 유입된 것은 아니었다. 그라운드 플립은 6월 말부터 약 한달 반 가량 개발해 7월 30일에 출시 되었다. 이때 당시에는 첫 출시였고 서비스의 안정성이 보장되지 않았기 때문에 광고를 통해 홍보하는 것은 위험하다고 판단했다. 물론 출시전에 많은 테스트를 해보긴 했지만 개발자들이 사용해본 테스트였고 실제 유저 들이 사용했을 때 안정적일지는 미지수였다.

그래서 초기에는 팀원들과 팀원들의 지인 위주로 사용해달라고 부탁하여 베타 테스트 느낌으로 사용자를 모았다. 그리고 우리 멘토님께서 스레드에 홍보를 주기적으로 해주셨다. 무려 5000명의 팔로워를 가진 스레드 계정으로 홍보해주셔서 너무 감사했다! aje.travel ← 궁금하면 한번 들어가보시길

스크린샷 2024-09-29 오전 2.19.57.png

그래서 차트를 보면 하루에 보통 3명 정도 가입하는 것을 볼 수 있다. 많으면 7명, 적으면 1명도 가입 하지 않는 날도 있었다. 하지만 이때 약 50명 정도의 인원이 실사용을 해주면서 서비스가 잘 동작한다는 확신을 얻을 수 있었다.

홍보

블로그

이제 안정성이 확보되었기 때문에 조금 씩 홍보를 하기로 했다. 우선은 돈이 안드는 방향으로 홍보를 해봐야겠다고 생각했다. 그래서 블로그에 홍보 하기로 했다. 그라운드 플립 관련 글을 쓸 때 마다 설치해달라는 홍보 문구를 추가했다. 이 글의 시작 부분에서 홍보 했던 것 처럼 말이다. ㅎㅎ

스크린샷 2024-09-29 오전 2.49.28.png

블로그 글이 velog 트렌딩에

서 상위권에 들면서 글을 읽어주는 사람이 많아졌다. 내 글도 트렌딩에 오르고 팀원인 우기 의 글도 트렌딩에 오르면서 홍보 문구를 보고 깔아주시는 분들이 조금 생겼다.

스크린샷 2024-09-29 오전 2.54.13.png

이렇게 약간의 홍보와 함께 유저수 100명을 달성했다!

이때 처음으로 100명을 달성해서 엄청 기분이 좋았고 팀원들과 기뻐했던 기억이 난다.

Disquiet

어느 날 지인의 소개로 Product Makers Club S24 라는 것을 알게되었다. Disquiet 이라는 플랫폼에서 진행하는 프로그램이었는데 4주동안 유저 1000명을 모으는 챌린지였다. 참가만 하면 최소 3만명에게 프로젝트 홍보를 지원 해주었다. 그리고 참가 방식도 매주 메이커 로그 작성과 프로덕트 런칭만 하면되서 우리 한테는 너무 좋은 조건이라고 생각해서 참가 했다.

그래서 매주 그라운드 플립 관련 글을 올려 홍보했다. Disquiet에 올린 글들은 링크 에서 볼 수 있다.

렛플

이렇게 열심히 홍보를 하고 다니니까 뜻밖의 감사한 메일 하나를 받게 되었다.

스크린샷 2024-09-29 오전 3.11.57.png

렛플이라는 플랫폼에서 우리 그라운드 플립을 무료로 홍보해준다고 메일을 보내주었다. 더 홍보해야하는 우리의 입장에서는 무료로 홍보 해주는 것이 너무 감사한 일이었다. 렛플에 올라간 글은 링크 에서 확인 할 수 있다.

광고

지금 까지는 돈을 안드리고 홍보한 방법들에 대해서 소개했다. 이제부터는 광고에 대해서 소개하려고한다. 아무래도 위의 플랫폼들은 개발자들이 많은 곳이다 보니 일반적인 사람들에게는 홍보가 부족하다고 생각이 되었다. 그래서 구글광고와 메타광고를 시작하였다.

Google ads

먼저 구글 쪽에 광고를 시작하였다. 광고를 시작하려면 광고 이미지가 있어야 했다. 우선은 피그마를 사용해서 자체 제작한 이미지를 사용했다.

스크린샷 2024-09-29 오전 3.30.10.png

이렇게 2 종류의 이미지를 만들어 광고를 시작했다. 광고는 iOS, 안드로이드 로 나누어서 각각의 스토어 링크로 들어갈 수 있는 광고를 만들었다. 하지만 iOS 의 경우 설치수를 측정하는게 힘들어서 광고 효율이 잘 나오지는 않았다… 그렇게 하루에 약 2만원 씩 광고를 시작했다.

스크린샷 2024-09-29 오전 3.27.25.png

결과를 보면 하루 설치 수가 광고 덕분에 확실히 늘었다. 보통 하루에 10명 정도는 설치를 해주셨다. 추석 기간에는 광고비를 2배로 올려보니 설치수도 2배가 되어 빠르게 300명 까지 모을 수 있었다.

KakaoTalk_Photo_2024-09-29-03-36-01.png

통계를 보면 설치 당 드는 비용도 꽤 잘나온 것 같다.

메타 광고

구글 광고에 비해 메타 광고는 좀 늦어졌다. 소프트웨어 마에스트로에서 프로젝트 비용을 지원 받고 있는데 메타 광고에 대한 승인이 늦어졌기 때문이다.

위에서 우리끼리 제작한 광고 이미지는 아무래도 공대생들 끼리 만든 것이다 보니 허접했다.😁😁 그래서 광고 디자인은 전문 디자이너 분께 외주를 맞겨 다시 제작했다.

스크린샷 2024-09-29 오전 3.39.44.png

이렇게 만들어진 광고 이미지중 3개를 뽑아서 광고를 시작했다. 3개의 이미지중 광고 효율이 잘 나오는 것 하나를 뽑기 위해 3가지 광고 이미지를 동시에 광고 했다.

스크린샷 2024-09-29 오전 3.41.52.png

그 결과 4번째 광고 이미지가 압도적으로 효율이 좋게 나와서 4번째 광고 이미지 하나만 유지시켰다.

메타 광고에서 앱 설치 유도를 하려면 facebook sdk 를 설치하고 복잡한 과정이 필요했다. 그래서 우리는 단순하게 랜딩 페이지를 만들어 여기로 유도 시키고 랜딩 페이지에 각각의 스토어 설치 버튼을 만들어 설치하게 만들었다.

랜딩 페이지

랜딩 페이지는 imweb 으로 빠르게 만들었다. imweb 에 좋은 템플릿 들이 많아 빠르게 만들 수 있었다. 랜딩 페이지는 링크에 확인할 수 있다.

스크린샷 2024-09-29 오전 3.48.57.png

imweb 이 좋은게 pc 버전과 모바일 버전의 화면을 반응형으로 만들 수 있어 편리했다. 메타 광고는 모바일 사용자들이 많이 볼텐데 우리에겐 너무 좋은 선택지였다. 하지만 imweb의 무료플랜을 사용해 광고에 태우니 금방 일일 한도 트래픽이 다 차서 페이지가 터졌다. 그래서 급하게 유료 버전을 결제해서 일일 한도 트래픽을 늘렸다…

결과

결과는 구글광고와 비교도 안될 정도로 폭발적으로 유저가 늘었다!

300명 달성하는데 약 한달 반이 걸렸는데 메타광고를 추가 하는 것 만으로 약 5일만에 700명이 늘었고 1000명을 달성했다!!스크린샷 2024-09-29 오전 3.55.07.png

마무리

내가 1000명 사용자를 가진 프로젝트의 개발자가 될 것이라고는 상상도 못했는데 실제로 이루어지니 기분이 너무 좋다. 이번 경험을 통해 아무런 노력없이 알아서 사용자가 들어오지 않는다는 것을 알았다. 반드시 세상에 알려야 누군가 알아보고 설치해준다는 것을 느꼈다.

1000명이 들어와 기분이 좋은 것도 있지만 트래픽이 급증해 관리할 부분이 많이 생겨 힘든 점도 있다 ㅋㅋ 이 부분은 따로 글을 작성하려고 하니 많은 관심 부탁드린다.

앞으로의 계획

이후에도 소마에서 사용가능한 프로젝트 비용이 많이 남아서 메타광고를 계속 돌려 사용자를 더 모집 할 생각이다. 지금 새로운 기능인 그룹 모드도 스토어 심사를 기다리고 있다. 심사가 끝나는 대로 출시하고 그룹 모드를 주제로 한 새로운 광고도 돌리려고 한다.

그리고 대학교들을 그룹으로 만들어 두었기 때문에 에타 같은 대학생들이 많이 모이는 플랫폼에 집중적으로 광고해서 더 많은 사용자들을 모아볼 생각이다. “연세대에서 고려대의 땅을 전부 점령했어요! 그라운드 플립으로 땅을 연세대의 땅을 빼앗으세요!” 이런식의 광고 메시지를 던지면 효과가 좋지 않을까 생각중이다. 😁😁 물론 아직 안해봐서 결과는 모르지만. ㅎㅎ

21
14
구민

구민

땅따먹기, 이제 그룹원들과 같이 해봐요!

안녕하세요! 땅따먹기 만보기 서비스인 그라운드 플립의 개발자 구민입니다. 오늘은 저희 그라운드 플립의 새로운 기능인 그룹 모드 출시에 앞서 개발과정과 배경에 대해 소개해드리려고요! 🔥🔥

그라운드 플립이란?

스크린샷 2024-09-12 오전 1.16.46.png

먼저 저희 그라운드 플립에 대해서 소개하려고 하는데요. 그라운드 플립은 단순히 걷는 것에서 끝나지 않고, 걸은 길을 점령할 수 있는 시스템을 제공합니다. 내가 걷는 경로가 내 땅이 되고, 다른 사람들이 점령한 영역도 뺏을 수 있어요. 걸으면 걸을수록 점령한 영역이 지도에 표시되고, 다른 사용자와 경쟁하는 재미를 느낄 수 있습니다. 현재 앱스토어와 플레이스토어에 배포되어 있으니, 언제나 다운로드해서 땅따먹기를 할 수 있습니다!

그룹 기능을 추가한 이유

사실 그룹 기능은 그라운드 플립을 처음 기획할 때부터 핵심 기능으로 고려했습니다. 혼자서 땅을 점령하는 것도 재미있지만, 나와 같은 그룹원들과 함께 더 많은 땅을 점령하는 경험은 더욱 재미있을 것이라고 생각했기 때문입니다. 개인전 만큼이나 그룹전에서도 큰 매력이 있을 것이라 판단했습니다. 또한, 자신이 속한 그룹의 랭킹을 올리기 위해 더 큰 소속감을 느끼고 열심히 플레이할 수 있을 것이라고 기대했습니다.

마케팅 측면에서도 그룹 기능이 강력한 무기가 될 수 있다고 생각했어요. 경쟁 관계에 있는 그룹을 대상으로 마케팅을 한다면 더 많은 유저를 유입할 수 있을 것이라 보았습니다. 예를 들어, 연세대와 고려대 학우들에게 “연세대가 고려대의 땅을 전부 점령하고 있어요! 이대로 보고만 있을 건가요?”와 같은 경쟁심을 자극하는 메시지로 홍보한다면 많은 참여를 이끌어낼 수 있을 것이라 기대했습니다.

마지막으로, 유저 피드백도 중요한 요인이었습니다. 출시 후 유저들의 의견을 들어보니, 친구들과 함께 걷고 싶은데 각자 걸은 구역이 개인 점수로만 반영되는 것이 아쉽다는 피드백이 있었습니다. 그래서 저희는 빠르게 그룹 기능을 개발하여 유저들의 불편함을 해소하려고 했습니다.

그룹 기능 기획 과정

그룹 기능을 개발하기 전에 어떤 방식으로 그룹을 나눌지 고민했습니다. 저희가 생각했던 방법은 두 가지였어요. 첫 번째는 사용자가 자유롭게 그룹을 생성하고 가입할 수 있도록 하는 것, 두 번째는 저희가 미리 관련 있는 그룹을 만들어 두고 사용자가 선택해 가입하도록 하는 것이었습니다.

결론적으로 저희는 두 번째 방법을 선택했습니다. 첫 번째 방법은 유저의 자유를 최대한 보장하지만, 무분별하게 그룹이 생성되면 서로 관련 없는 그룹끼리 경쟁하게 될 가능성이 있었습니다. 예를 들어, ‘OO 아파트 부녀회’와 ‘ㅁㅁ전자 사원 모임’이 생긴다면, 이 두 그룹 사이에 경쟁심이 생길까 하는 의문이 들었기 때문입니다. 따라서 저희가 미리 관련 있는 그룹을 생성하고 유저들이 선택하여 가입하는 방식으로 개발하기로 했습니다.

어떤 그룹을 추가할까?

다음으로 고민했던 부분은 어떤 그룹을 미리 만들어 둘지였습니다. 여러 후보 중에서 대학교와 직장이라는 두 가지로 좁혀졌어요. 이 두 집단이 사람들을 나누기에 가장 대중적이라고 판단했습니다. 처음에는 두 집단을 모두 포함하려 했지만, 개발 기간이 길지 않았기 때문에 우선 대학교 집단을 먼저 넣기로 결정했습니다. 학교는 직장인도 거쳐 간 경험이 있는 곳이고, 직장을 다니지 않는 학생들도 포함할 수 있기 때문에 초기에는 더 많은 유저가 대학교 그룹에 속할 수 있을 것이라고 생각했기 때문입니다.

스크린샷 2024-09-25 오후 3.25.03.png

또한, 학교 대항전 시스템은 기존 게임들에서도 성공적인 사례가 많았고, 이를 통해 더욱 확신을 가지고 개발에 착수할 수 있었습니다.

개발 시작

저희는 그룹 그룹의 개발기간을 2주로 잡고 3일 정도 테스트 후에 출시하는 계획을 세웠습니다. 2주동안 개발 할 내용에 대해 스프린트 계획을 짜고 개발자 3명이 골고루 task를 나누어 개발했어요.

땅따먹기 로직과 랭킹 로직은 이미 개인전을 대상으로 개발이 완료된 상태였기 때문에 이 로직을 그룹전까지 커버 할 수 있게 살짝 변경해주면 되어서 비교적 쉽게 개발 할 수 있었어요. 그룹에 추가할 학교 들의 정보를 파싱하는 것과 그룹에 가입하고 탈퇴하는 로직에 신경써서 개발을 진행하였고 계획대로 2주안에 개발을 끝낼 수 있었습니다!

그룹 기능

이렇게 열심히 개발한 그룹기능을 보여드릴게요!🔥🔥

그룹 화면

스크린샷 2024-09-25 오후 3.51.32.png

그룹 기능 전용으로 화면을 새로 디자인 하여 그룹의 정보를 쉽게 볼 수 있게 구현했어요. 사진에 보이는 것 처럼 그룹이 소유한 땅이나 멤버수, 랭킹을 쉽게 볼 수 있어요! 그룹의 대표이미지와 색상도 지정하여 지도에 땅이 표시 될때 그룹의 대표 색상으로 표시되게 만들었습니다.

그룹에 가입하지 않은 경우에는 그룹 검색을 통해 원하는 그룹을 검색하고 가입 할 수 있게 만들었어요. 최대한 대한민국의 대학교를 다 넣으려고 노력했습니다. 빠르게 출시하여 유저들의 반응을 보고 원하는 그룹이 있다면 더 추가해드리는 방향으로 진행하려고 합니다.

그룹 랭킹

스크린샷 2024-09-25 오후 3.51.10.png

이제 랭킹 창에서 그룹 들간의 순위를 확인 할 수 있어요! 어떤 그룹이 상위권이 있는지 내 그룹은 몇등 정도 하는지 쉽게 찾을 수 있게 만들었습니다.

또한 그룹 내에서 내가 어느 정도 순위인지 확인할 수 있어요. 이를 통해 누가 가장 그룹내에서 기여를 많이 하고 있는지 알 수 있습니다.

그룹전 모드

스크린샷 2024-09-25 오후 3.58.11.png

이제 지도에 그룹전으로 땅따먹기를 한 결과를 볼 수 있습니다. 위의 모드 변경 토글에서 그룹전만 클릭하면 끝이에요! 기존 개인전에서는 내 땅은 초록색, 다른 사람들의 땅은 모두 빨강색으로 표시되는 것과 달리 그룹전에서는 소유한 그룹의 대표색으로 표시됩니다. 때문에 지도에서 더 다채로운 색으로 땅이 점령되어있는 화면을 확인할 수 있어요!

마무리

지금 까지 그라운드 플립의 그룹기능을 소개해드렸습니다. 2주동안 열심히 개발해서 뿌듯한 것 같네요! 이제 출시하여 사용자들의 반응을 살필 일만 남았습니다. 그룹기능은 현재 테스트까지 끝나 이번주 안에 출시를 게획하고 있으니 많은 관심 부탁드려요!

그리고 많은 성원덕에 현재 누적 사용자수 500명에 달성했습니다! 관심 가져주시고 설치해주신 모든 분들께 감사합니다!! 😁😁

그라운드 플립은 앱스토어, 플레이 스토어에서 다운 받을 수 있습니다!

[iOS] : https://apps.apple.com/app/ground-flip/id6550922550

[Android] : https://play.google.com/store/apps/details?id=com.m3pro.ground_flip

[소개 사이트] https://ground-flip2.imweb.me/

14
3
구민

구민

그라운드 플립에서 걷기와 자동차를 타는 것을 구분하는 방법

최근 그라운드 플립이라는 땅따먹기 서비스를 개발하였다. 이 프로젝트는 사용자가 지나간 영역을 사용자의 영역으로 만들어주는 프로젝트이다.

스크린샷 2024-09-19 오후 5.54.56.png

위 사진과 같이 사용자가 지나간 영역에 해당하는 사각형 만큼 지도에 색이 칠해진다.

도입 배경

현재 서비스를 개발해 배포한 상황이다. 사용자 유입을 위해 이벤트를 열려고 하고 있다. 현재 우리 앱에는 사용자가 획득한 땅의 개수를 기반으로 하는 랭킹 시스템이 존재한다.

IMG_0664.jpg

이 랭킹 시스템을 이용해서 1등 부터 3등 까지 상품을 주는 이벤트를 기획중이다. 상품이 걸린 만큼 땅을 차지하는 로직이 누구에게나 공정해야한다고 판단했다.

우리 서비스는 땅따먹기라는 게이미피케이션 요소를 도입하여 걷기나 달리기를 장려하는 앱이다. 하지만 상품을 위해 자동차나 킥보드를 사용해서 앱을 사용하면 단 시간에 엄청많은 땅을 획득할 수 있다. 이렇게 되면 걸어서 땅을 획득하는 사용자들이 공정한 경쟁을 할 수 없기때문에 자동차나 킥보드를 타고 사용하는 행위를 막아야했다.

그래서 클라이언트 측에서 걷기나 달리기를 구분하는 로직을 개발하기로 했다!

개발 환경

개발 환경은 Flutter 를 사용한다. 위치 정보, 즉 GPS 데이터를 얻어오기 위해 Flutter 의 location 패키지를 사용했다.

이 글은 걷기나 달리기 행동을 구분하는 로직에 대한 설명글이다. 때문에 땅따먹기 로직이나 다른 로직보다는 걷는 상태와 자동차를 탄상태를 구분하는 로직에 집중하여 설명한다.

속도 기반 구현

로직

처음에 어떻게 사람이 실제 움직이는 것과 탈 것을 사용하는 행위를 구분할지 생각해보았다. 그러다가 포켓몬 고의 예시를 살펴보니 10.5km/h 이상으로 움직이면 인식을 안한다고 들어서 이 방법을 적용해보기로 했다.

Flutter 의 location 패키지는 위치 정보를 반환 할 때 속도 값을 같이 반환한다. 반환값인 LocationData 를 살펴보면

  /// In meters/second
  ///
  /// Will be null if not available.
  final double? speed;

speed 값이 있다. 이 speed 값은 m/s 로 나오기 때문에 10.5 km/h 와 비교하려면 3.6 을 speed 에 곱해야한다.(3.6 을 곱하면 km/h 로 환산 가능.) 그 결과 아래와 같이 코드를 작성했다.

void _trackUserLocation() {
  _locationService.location.onLocationChanged.listen((newLocation) async {
		if(newLocation.speed * 3.6 <= 10.5) {
			await occupyPixel();
		}
  });
}

결과

그 결과 테스트 하기 위해 버스와 지하철을 타고 앱을 실행해보았더니 적용하지 않았을 때 보다는 확실히 사람이 움직이는 행위를 구분해내었다.

한계

하지만 문제점이 꽤나 많았다. 문제점 들은 다음과 같았다.

스크린샷 2024-08-27 오후 9.45.18.png

  • 터널을 진입한 경우 땅이 차지되는 문제

  • 지하철 탑승시 GPS 가 많이 튀어 현재 위치한 곳과 멀리 떨어진 곳에 방문되는 문제

  • 자동차의 속도가 10.5km 안으로 줄어들 때 땅이 차지 되는 문제

생각보다 땅이 획득되는 구간이 많아서 제대로 부정행위를 방지 할 수 없다고 판단해서 이 문제들을 개선하기로 했다!

원인 파악

우선 왜 위와 같은 문제점들이 발생했는지 원인을 분석 해보았다.

1. 터널 진입시, 지하철 탑승시

터널 진입시와 지하철 탑승시의 속도를 확인해보았다.

-1 이 나온다?

황당했다,,,

찾아보니 GPS 를 잘 잡지 못하는 경우에는 속도를 -1로 표시하는 것을 알았다. 속도가 -1 로 측정되니 항상 기준 속도인 10.5km 보다 작아서 땅이 획득 된 것이었다. 지하철의 경우도 GPS 가 이곳 저곳으로 튀는데 속도 값은 -1로 나오니 땅이 획득 되었다.

  • 결국 속도를 location 패키지에 의존하지 않고 직접 계산 해야할 필요가 생겼다.

2. 자동차의 속도가 느려지는 경우

이 부분은 자동차의 신호 대기나 코너를 돌면서 속도가 줄어들며 발생한다. 속도가 10.5 km 아래로 줄어들면 그 순간에 땅이 점령되었다.

  • 단순히 10.5km 이하 일때 가 아니라 전체적으로 자동차가 잠시 느려지는 것을 감지할 필요가 있었다.

하나씩 해결해보자.

1. 직접 속도 계산하기

우선 GPS 가 약한 곳에서도 처리 할 수 있게 위치를 기반으로 직접 속도를 계산 해보았다.

  • 현재 위치와 가장 최근의 위치를 사용하여 속도를 구한다. 이전 위치들에 접근하기 위해 이전 위치를 저장했다.

스크린샷 2024-08-27 오후 11.51.44.png

위 그림처럼 좌표값과 좌표에 방문한 시간만 있으면 속도를 쉽게 구할 수 있다. 다만 여기서 위경도를 기준으로 거리를 구하는 것이 좀 복잡하다. 지구가 둥글기 때문에 일반 적인 평면을 기준으로 계산하면 안된다. 자세한 내용은 설명하면 너무 길어서 구글에 찾아보길 바란다.

그해서 두 좌표사이의 거리를 소요시간으로 나누면 속도를 구할 수 있다.

  calculateSpeed(LocationData previousLocation, LocationData currentLocation) {
    final timeInSeconds =
        (currentLocation.time! - previousLocation.time!) / 1000;
    final distanceInMeters = calculateDistance(
      previousLocation.latitude!,
      previousLocation.longitude!,
      currentLocation.latitude!,
      currentLocation.longitude!,
    );
    final speedInMps = distanceInMeters / timeInSeconds;
    final speedInKmH = speedInMps * 3.6;

    return speedInKmH;
  }

  double calculateDistance(
    double startLat,
    double startLng,
    double endLat,
    double endLng,
  ) {
    const double earthRadius = 6371000;

    final double dLat = degreesToRadians(endLat - startLat);
    final double dLng = degreesToRadians(endLng - startLng);

    final double a = (sin(dLat / 2) * sin(dLat / 2)) +
        (cos(degreesToRadians(startLat)) *
            cos(degreesToRadians(endLat)) *
            sin(dLng / 2) *
            sin(dLng / 2));

    final double c = 2 * atan2(sqrt(a), sqrt(1 - a));

    return earthRadius * c;
  }

  double degreesToRadians(double degrees) {
    return degrees * (3.141592653589793 / 180);
  }

위와 같은 코드로 직접 좌표간의 속도를 구했다.

2. 주행시 잠시 느려지는 구간 가려내기

우선 자동차가 느려지는 구간을 가려내기 전에 직접 자동차를 타서 속도 데이터를 수집해봤다. 약 30분 간의 주행 데이터이다. 가로 축은 시간, 새로 축은 속도(km/h) 를 의미한다.

Figure_1.png

그 결과 위와 같은 그래프가 그려진다. 위 빨간선이 10.5 km/h 에 해당하는데 이 선 밑으로 속도가 떨어지는 구간 마다 땅이 먹어진다.

이를 막기 위해 속도를 판단할 때 순간의 속도를 판단하는 것이 아니라 특정 구간의 속도를 판단해보기로 했다.

스크린샷 2024-08-28 오전 12.07.45.png

속도가 감소하는 부분을 살펴보면 보통 50초 사이에 감소되는 것을 발견했다. 이 구간을 같이 판단하면 일시적으로 속도가 줄어드는 구간을 판단할 수 있지 않을까 하는 생각이들었다.

GPS 는 1초 간격으로 수집되기 때문에 약 1초간격으로 위치와 속도가 기록된다. 그래서 내가 세운 로직은 현재 속도가 낮아도 최근 50초 사이의 속도 중에 사람이 내지 못할 속도가 기록되었다면 속도가 감소된 걸로 파악되게 로직을 생각해봤다.

사람이 내지 못할 속도는 25 키로로 정했다. 우사인 볼트 같은 사람의 순간 최고 속력은 빠르다고 40km/h 에 가깝다고 하지만 일반 사람들이나 마라톤 선수들의 평균속도가 20 키로 정도라고 하기 때문에 그것보다 살짝 높게 25키로를 기준으로 잡았다.

스크린샷 2024-08-28 오전 12.24.00.png

그 결과 위 그림처럼 속도가 기준 속도보다 낮은 경우에도 이전 50초 사이의 기록중에 25를 넘는 기록이 있기 때문에 자동차를 탄것으로 인식된다.

주의점

위 방법에서 가장 주의할 점은 얼마만큼의 구간을 같이 확인 할 것인지이다. 위에서는 50초로 예를 들었지만 구간의 길이만큼 성능이 차이날 것이라고 예상했다.

  • 만약 50초보다 더 짧으면 이전 주행 기록이 정상적으로 감지가 안될것이다.

  • 50초보다 너무 길다면 자동차를 내려서 걷는데도 이전 기록이 영향을 끼쳐 걷는 것으로 인식을 못할 것이다.

때문에 적당한 구간을 설정해주어야되는 어려움이 있었다. 결론 적으로 나는 50초를 기준으로 테스트를 해보았다.

또한 단 하나의 기준치를 넘는 기록을 가지고 판단하면 안된다. 왜냐하면 GPS가 가끔씩 튀는 구간이 있어서 걷는 중이라도 속도가 급작스럽게 높은 수치가 찍힐 수 있다. 때문에 적당한 threshold 를 잡아 적용해야한다. 나는 5개를 기준으로 잡았다.

결과는?

앞서 단순히 현재 속도를 기준으로 판단하는 로직보다 걷는 것을 잘 구분한다.

  • 터널에서는 땅이 점령이 되지 않는다.

  • 지하철에서 튀는 부분도 급작스럽게 튀면 속도가 빠르게 찍히기 때문에 점령되지 않는다.

  • 50초 안에 느려지면 자동차로 인식하고 땅이 점령되지 않는다.

하지만 여기에도 미쳐 발견하지 못한 문제가 많았다…

차가 막히면 어떻게 될까….?

실제 테스트를 위해 버스를 탑승하였는데 일반적으로는 잘 구분이 되었다. 하지만 차가 막히니 차가 지나가는 땅을 모두 점령해버렸다…

이유는 간단하다. 차가 막히면 지속적으로 기준점보다 낮은 속도를 계속 유지한다. 때문에 걷기랑 똑같은 데이터로 측정된다.

결국 속도기반으로 구분하는 것은 한계가 있다라는 결론에 도달했다. 다른 데이터를 기준으로 구분 할 필요가 있었다.

가속도 센서

어떤 데이터를 기준으로 나누어야 효과적으로 구분할 수 있을지 곰곰히 고민해봤다. 만보기가 떠올랐다. 만보기는 사람의 걸음수를 측정한다. 어떻게 측정할까? 사람이 움직일때마다 가속도 센서등을 사용하여 움직임을 측정한다. 이는 오직 사람이 걷거나 뛰면서 몸이 흔들리며 핸드폰이 흔들려야 측정된다.

“자동차에 탄 경우에는 어떨까?”

자동차에 탄사람은 걷거나 뛰는 것 만큼 흔들리지 않는다!

결론은 이 흔들림을 기준으로 구분해보기로 했다!

구현하기

Flutter 의 pedometer 패키지를 보면 PedestrianStatus 이라는 데이터를 제공한다. 이것이 걷는 중인지 정지상태인지 pedometer 에서 계산해주는 데이터이다. 이를 활용하면 쉽지만 꽤 정확하게 걷는 상태와 걷지 않는 상태를 구분해낼 수 있었다.

  void _trackUserLocation() {
    _locationService.location.onLocationChanged.listen((newLocation) async {
      _locationService.updateCurrentLocation(newLocation);

      if (walkingService.isWalking()) {
        await occupyPixel();
      }
    });
  }
class WalkingService {
  static final WalkingService _instance = WalkingService._internal();
  static const _walking = 'walking';
  static const _stopped = 'stopped';
  static const _unknown = 'unknown';
  String pedestrianStatus = _stopped;
  late Stream<PedestrianStatus> _pedestrianStatusStream;

  WalkingService._internal();

  factory WalkingService() {
    return _instance;
  }

  init() {
	  // 걷기 상태가 변경될때마다 상태를 업데이트 한다.
    _pedestrianStatusStream = Pedometer.pedestrianStatusStream;
    _pedestrianStatusStream.listen((PedestrianStatus event) {
      String status = event.status;
      pedestrianStatus = status;
    });
  }

  @override
  isWalking() {
    if (pedestrianStatus == _unknown) {
      return false;
    } else {
      return pedestrianStatus == _walking;
    }
  }
}

결과

결과는 매우 잘 작동했다!

위에서 문제가 되었던

  • 터널에서 땅 점령 문제

  • 지하철에서 점령 문제

  • 자동차에서 속도가 느려질때 점령 문제

  • 차가 막혀서 계속 속도가 느릴때 점령 문제

문제들 모두 해결되었다. pedometer 가 자동차 정도의 흔들림은 걷는 것으로 인식하지 않았다.

스크린샷 2024-09-19 오후 6.04.41.png

위 영상은 자동차를 타고 실제로 로직을 개선한 버전과 개선하지 않은 버전을 동시에 녹화하여 빨리 감기한 영상이다. 개선전 영상은 속도가 느려질때 마다 땅이 점령되는데 반해 개선 후 영상은 느려져도 점령되지 않는 것을 확인할 수 있다!

한계

완벽할 것 같은 이 방법에도 문제점이 있었다.

차 안에서 강제로 핸드폰을 흔들면 걷기로 인식되어 땅이 점령된다…

일반적으로 차안에서 강하게 핸드폰을 흔들 사람은 별로 없을 것이라고 예상되지만 완벽한 공정성을 위해서는 눈감고 넘어갈 수 없는 문제였다.

개선하기

사실 이 부분은 간단하게 해결할 수 있는 것이 위에서 속도 기반으로 구분하는 로직을 만들지 않았는가? 이 로직을 적절히 합치면 해결할 수 있다.

  • 속도 기반으로 걷는 중인지 자동차를 타고 있는 중인지 체크한다.

  • 가속도 센서 기반으로 걷는 중인지 걷지 않는 상태인지 체크한다.

위 두 방법 모두 걷기로 인식하는 경우만 걷기로 인식한다.

몇가지 예를 통해 결과를 예측해보자!

  1. 속도가 빠른 자동차안에서 핸드폰을 흔들고 있다고 가정하자. 가속도 센서 기반에서는 걷기라고 인식하지만 속도 기반에서는 자동차라고 인식하기 때문에 걷기라고 인식하지 않는다.

  2. 출근길 차가 막히는 버스를 타고 있다고 가정하자. 속도 기반에서는 속도가 느려 걷기라고 인식하지만 가속도 센서 기반에서는 움직이지 않으니까 자동차라고 인식하기 때문에 걷기라고 인식한다.

이제 걷는 상태와 자동차등을 탄 상태를 매우 잘 구분하는 로직이 완성되었다. 이를 통해 보다 공정한 경쟁 시스템을 만들 수 있다!!!

마무리

걷는 상태와 자동차를 탄 상태를 구분하는 것은 처음에는 간단해보였지만 전혀 간단하지않은 작업이었다.

무엇보다 구분하는 기준을 생각해내는 것이 쉽지 많은 않았다. 기준을 떠올리려고 자동차를 타고 시간에 따른 속도도 측정해보고, 걸으면서 걷기의 특징도 생각하는 등 여러 작업을 해보았다. 심지어 꿈에서 까지 생각했었다. ㅋㅋㅋ

테스트 하는 것도 쉽지 않았다. 실제 걷는 것과 자동차를 타는 데이터가 필요하다보니 에뮬레이터로는 테스트 해 볼 수 없었다. 때문에 실제기기를 사용해서 실제로 걷고, 뛰고, 버스를 타고, 지하철을 타보고 테스트 할 수 밖에 없어서 시간이 오래 걸렸다. 또 많이 걸어서 몸도 피곤했다…

그래도 마지막에 만족할만한 성능으로 개선해서 만족스러운 작업이었던 것 같다. 만보기 기반으로 해결 될 때 고민 했던 것에 비해 너무 쉽게 해결되어서 좀 좌절했지만 결국 고민 했던 부분들이 헛수고 아니라 같이 합쳐지게 되어 되게 뿌듯했던 것 같다.

늘 백엔드에서 서버들끼리 최적화 방법만 생각하다가 실제 사람의 행동을 구분하는 로직을 짜니 재미있고 새로웠다!

14
14
구민

구민

땅따먹기 하실래요?

안녕하세요!

저희는 걸어서 세상을 점령하는 재미를 선사하는 앱, 그라운드 플립을 개발하고 있는 팀입니다. 저희는 세 명의 개발자들이 모여 함께 만들고 있으며, 걷기를 좋아하는 사용자들이 더 재미있게 걸을 수 있는 경험을 제공하고자 이 앱을 만들게 되었습니다.

스크린샷 2024-09-12 오전 1.16.46.png

그라운드 플립은 단순히 걷는 것에서 끝나지 않고, 걸은 길을 점령할 수 있는 시스템을 제공합니다. 내가 걷는 경로가 내 땅이 되고, 다른 사람들이 점령한 영역도 뺏을 수 있어요. 걸으면 걸을수록 점령한 영역이 지도에 표시되고, 다른 사용자와 경쟁하는 재미를 느낄 수 있습니다. 현재 앱스토어와 플레이스토어에 배포되어 있으니, 언제나 다운로드해서 땅따먹기를 할 수 있습니다!

저희는 현재 그룹 기능을 개발하고 있습니다. 이 기능을 통해 혼자서 걷는 것뿐 아니라 그룹 간의 대결이 가능해져요. 예를 들어 인접한 학교 간의 대항전 같은 콘텐츠도 가능합니다. 이런 그룹 대항전은 사용자들끼리의 상호작용을 더 활성화시키고, 지역 사회 내에서도 큰 흥미를 이끌어낼 것으로 기대하고 있어요.

지금은 사용자 모집과 마케팅이 가장 큰 과제입니다. 저희는 3명 모두 개발자이다 보니 마케팅같은 부분은 어렵더라고요… 그래서 더 많은 사용자를 모집하기위해 마케팅에 대한 연구를 열심히 하고 있어요! 작은 팀이지만, 앞으로도 계속해서 앱을 개선하고 새로운 기능을 추가하며 더 많은 사용자들과 함께 성장해나가는 모습을 보여드리고 싶습니다.

많은 응원 부탁드리며, 앞으로도 다양한 피드백을 통해 저희 그라운드 플립이 더 발전할 수 있도록 노력하겠습니다!

아래는 저희 그라운드 플립의 다운로드 링크입니다. 관심있으신 분들은 사용해보시고 피드백을 남겨주신다면 저희에 큰 도움이 될 것 같습니다!

[iOS] : https://apps.apple.com/app/ground-flip/id6550922550

[Android] : https://play.google.com/store/apps/details?id=com.m3pro.ground_flip

[소개 사이트] https://ground-flip2.imweb.me/

감사합니다!

6
1