[링크] 트렐로(Trello) 쪼개기
'협업 > Trello' 카테고리의 다른 글
Trello로 효율적으로 협업하기 (0) | 2013.12.20 |
---|---|
[링크] [Trello] 팀프로젝트의 일정관리를 도와주는 무료서비스 Trello 소개 (0) | 2013.12.20 |
Trello로 효율적으로 협업하기 (0) | 2013.12.20 |
---|---|
[링크] [Trello] 팀프로젝트의 일정관리를 도와주는 무료서비스 Trello 소개 (0) | 2013.12.20 |
[펌] Borderless window in standalone player (0) | 2016.11.08 |
---|---|
[펌] Disable Screen Auto Rotation on Unity3D (0) | 2016.11.03 |
[펌] 유니티 최적화 Tips (0) | 2016.10.26 |
[펌] 유니티 SendMessage 사용의 장점 (0) | 2016.10.26 |
[Tip] Coroutine Optimization Technique (0) | 2016.10.07 |
이 프로세스 문서의 현행화는 Github에서 진행되니 추후에는 Github을 방문해 주시면 고맙겠습니다.
1. Trello Card 만들기
1.1 기본적인 Trello 흐름
1.2 Trello카드 내용은 Description란에는 이슈 링크를 걸어주거나 wiki 링크를 걸어줘, 해당 스토리의 정보를 알 수 있도록 해준다. 그리고 Spec을 참조하여 Checklist를 추가해 완료조건을 기술해 개발해가면서 하나씩 처리해 나간다.
1.3 카드 처리 및 이동시 Slack Alert를 줘 실시간으로 처리가 가능하도록 설정한다.
2. Branch 만들고 Pull Request, Merge 하기
2.1 소스 리모트와 동기화
> git checkout master && git pull origin master && git fetch -p origin
2.2 브랜치명을 만들고 브랜치로 이동.
> git checkout -b dev_standard
2.3 작업 후 커밋.
> git commit -a -m "[VOY-201] README git 사용법 추가" # 커밋 작성은 issue ID를 넣고 내용은 구체적으로 제시한다.
2.4 작업을 완료 후 master branch로 변경하여 remote에 새로운 변경 사항을 master에 반영
> git checkout master > git pull origin master && git fetch -p origin
2.5 변경사항이 있다면 dev_standard branch에서 rebase를 수행
> git checkout dev_standard > git rebase master
- rebase 중 충돌이 발생하면 아래 수행하고 아니면 넘어감.
> git add . > git rebase --continue
2.6 Pull Request 요청하기 전에 Trello 카드도 [Review] 리스트로 옮기고 Checklist 하나를 더 만들어서 Review 내용(리뷰 담당자 포함)을 기술하면 Trello 알림을 통해 담당자가 리뷰어임을 알게 된다. 아니면 Trello 카드를 만들때 Review Checklist를 미리 만들어서 리뷰 대상자를 등록한다.
2.7 Pull Request 요청
> git push origin dev_standard
- push 후 Github의 repository로 이동해서 Compare & pull request 버튼 클릭하고 코멘트[To close VOY-201(jira issue 번호), 혹은 github issue 사용하면 #1234로] 남기고 Create pull request 버튼 클릭한다.
- 이때 Pull Request 정보가 Slack을 통해 담당자에게 보내지게 되고 리뷰를 수행한다.
- 리뷰 수행 후 수정사항이 있으면 수정 후 Pull Request를 다시 보내고, 수정 사항이 없으면 Github에서 Merge pull request를 클릭하고 Confirm merge 버튼을 클릭해서 merge를 완료한다.
- Github에서 merge가 완료되면, Delete branch 버튼을 클릭하거나 아래 로컬에서 커맨드로 원격 브랜치를 삭제한다.(선택사항)
> git push origin :dev_standard
2.8 Review 후 수정사항이 있는 경우 수정한 다음 2.7을 재 수행한다.
2.9 로컬 master 동기화
> git checkout master && git pull origin master && git fetch -p origin
- 로컬 브랜치 삭제(선택사항)
> git branch -d dev_standard
3. 배포하기
- 테스트 코드를 돌리고, jenkins나 자체 배포 도구를 활용하여 운영 서버에 소스를 배포한다.
4. 배포후 확인
- 기능 테스트를 눈으로 확인하면서 화면의 깨짐, 데이터의 정확성, 브라우저 호환성 등을 점검한다.
- Selenium 도구를 통해 브라우저단에서 테스트를 할 수 있는데, 이 Selenium이 구동한 브라우저의 결과 화면을 아이컨텍해서 봄으로써 어느 정도 테스트 자동화를 할 수 있다.
5. Trello 카드 Done 리스트로 이동
- 배포후 확인에서 이상이 없다면 Trello의 카드를 [Done(Sprint1 - 날짜기간)] 리스트에 이동시키고, 이슈를 close한다.
[출처] http://www.mimul.com/pebble/default/2015/06/08/1433751662702.html
[링크] 간트차트 프로그램 추천 : 다운 없이 바로 제작, 엑셀 저장 가능! (0) | 2019.06.27 |
---|---|
[링크] 테크니컬 리더십: 시작하기 (0) | 2018.12.05 |
팀장쯤 되면 알아야 할 똑똑한 팀 운영 법 (0) | 2015.07.17 |
엑셀 간트(Gantt) 차트 만들기 (0) | 2015.01.05 |
무료 프로젝트 관리툴 3종 비교 (0) | 2015.01.05 |
[링크] Firebase Crashlytics를 Slack과 연동해서 알림 받기 (0) | 2020.03.12 |
---|---|
[링크] [Trello - Slack] 완벽 연동 방법 (0) | 2016.11.01 |
[펌] [SNS] 여유로운 업무 환경을 위해, '슬랙(slack)' (0) | 2016.11.01 |
[링크] Firebase Crashlytics를 Slack과 연동해서 알림 받기 (0) | 2020.03.12 |
---|---|
[링크] [Github - Slack] 완벽하게 연동하기 (0) | 2016.11.01 |
[펌] [SNS] 여유로운 업무 환경을 위해, '슬랙(slack)' (0) | 2016.11.01 |
안녕하세요. 오늘도 신선한 '기업 커뮤니케이션' 관련 소식을 전해드리러 온 정은킴입니다 :D
여러분들은 업무를 볼 때 팀원들과 의견을 나누고, 파일을 공유하기 위해 어떤 '메신저' 를 사용하시
나요? 이번 주, 혹은 다음 주에 해야 할 업무와 계획 등을 효과적으로 관리해주는 'To do list' 로는
어떤 것을 사용하고 계신가요? 우리는 이렇게 우리의 업무를 보다 빠르게, 성공적으로 마치기 위해
다양한 '비즈니스 커뮤니케이션 툴'을 사용하고 있습니다.
'비즈니스 커뮤니케이션 툴' 시장은 최근 몇 년 사이 비약적으로 성장해 좀 더 특별한 강점을 내세운 다양한 도구들이 출시되고 있습니다. 특히 업무를 볼 때, 내가 '해야 할 일'을 효과적으로 관리해주는 GTD(Getting Things Done) 기반의 '할 일' 관리 툴은 요즘 같이 각자의 업무가 많아지고, 복잡한
업무 상황 속에서 모든 직장인들에게 꼭 필요한 툴이라고 볼 수 있습니다. 이미 해외 시장을 비롯,
국내에서도 다양한 '업무 관리 툴'들이 등장하고 있는데, 그래서 저는 오늘부터 매주 화요일마다
'비즈니스 커뮤니케이션 툴'에 대해 하나씩 살펴보는 특집 기사를 포스팅 하려고 합니다.
지난 8월, 사진 공유 사이트로 유명한 '플리커(flikr)'의 공동 창업자인 스튜어트 버터필드가 업무용
커뮤니케이션 툴인 '슬랙(slack)'을 공개했습니다. 슬랙은 '느슨한, 늘어진'이라는 의미로, 과중한
업무를 한 시라도 빨리 처리하려는 현대인들에게 슬랙을 사용함으로써 '느슨한' 여유를 가질 수 있게
하자는 뜻을 내포하고 있습니다. 사용자들은 웹을 포함해 모바일에서도 슬랙을 사용할 수 있는데, 웹에서든, 모바일에서든, 동일한 환경으로 쉽게 슬랙을 사용할 수 있어 언제, 어디서든 사용자의 업무
반경을 넓혀줍니다. 그럼 이제, 슬랙만이 가지고 있는 색깔을 확인해볼까요?
《 '느슨한' 여유를 가지다 》
[Good Point] 저는 이번에 슬랙을 체험하면서 슬랙이 가지고 있는 많은 기능들 중, 특히 자주 사용
했던 두 가지 기능이 있습니다. 그 첫 번째 기능은 바로 '파일 전송' 기능입니다. 슬랙은 웹에서든
모바일에서든 자유롭게 대화를 나눌 수 있는 메신저 기반의 '비즈니스 커뮤니케이션 툴'인데요, 이
성격에 맞춘 슬랙의 파일 전송 기능은 사용자들이 쉽고 빠르게 다양한 업무용 파일을 공유할 수
있게 해줍니다. 웹에서 슬랙을 실행했을 때, 웹 브라우저 창의 왼쪽 영역에서는 팀원들과 대화를
나누는 동시에, 오른쪽 영역에서는 내가 보냈거나, 찾고자 하는 파일을 바로 찾을 수 있습니다.
또한, 파일의 제목과 확장자명 등으로도 쉽게 파일 검색이 가능하고, 이미지나 PDF 등이 파일 속성 별로도 내가 찾고자 하는 파일을 바로 찾을 수 있습니다. 아이디어 회의 같은 간단한 회의를 슬랙에서 진행했을 때, 팀원들과 대화를 나누며 다양한 이미지나 업무와 관련된 기사를 공유할 수 있어 편리합니다. 슬랙의 '파일 전송' 기능은 모바일에서도 동일한 구성으로 이용할 수 있어서 사용자들이
웹과 모바일 등의 디바이스에 상관 없이 쉽게 사용하기 좋습니다. 내가 찾고자 하는 파일의 속성과 제목 등을 검색할 수 있는 세부 검색 아이콘도 상단바에 달려 있어 사용자들의 눈에 익숙합니다.
슬랙은 '비즈니스 커뮤니케이션 툴'답게 업무의 흔적을 남길 수 있는 기능이 존재합니다. 제가 두 번째로 많이 사용했던 '별표 대화(Starred Items)' 기능인데요, 상대방의 아이디 옆에 있는 별 모양
을 누르면, 해당 대화가 별표 처리되어 웹 브라우저의 오른쪽 영역에서 별표 친 대화만 골라서 볼 수 있습니다. 다른 팀과의 협조가 필요한 업무를 진행하거나, 상사의 중요 공지 사항을 한 데 묶어서 볼 수 있어서 편리합니다. 이 기능은 내가 어떤 대화창에서 업무와 관련해 어떻게 말했는지 확인할 수 있기 때문에 향후 업무 상 커뮤니케이션에 문제가 생겨 '나'와 상대방이 어떻게 대화를 나누고, 어떤 방식으로 업무를 처리하기로 했는지 확인할 수 있습니다. 이는 곧 서로간의 업무 기록이 되어 보다 책임감있게 업무를 처리할 수 있는 작은 도움이 되기도 합니다.
[Bad Point] 슬랙은 '웹 메신저'의 성격을 띄는 업무 관리 도구인만큼, 왠만한 기능 사용에 있어서
모든 사용자가 동일하게 쓸 수 있습니다. 하지만, 대화방 생성을 아무나 할 수 있고, 각 대화방의
주제를 설정하는 것도 권한에 상관 없이 바꿀 수 있는 점은 보안에 민감한 회사들이 사용하기에 적당
한 것 같지 않습니다. 또, 대화방 및 파일함 내에 너무 많은 아이콘과 텍스트(첨부 파일 설명 문구,
댓글 문구)들이 있어 화면이 정돈되어있지 않다는 느낌이 드는 것도 슬랙이 가진 단점이라고 할 수 있겠습니다.
《 '친절함'을 입히다 》
[Good Point] 슬랙은 타 업무 관리 도구와는 다르게, 세세한 기능에도 신경을 많이 써 사용자들이
최대한 많은 기능들을 많이 써볼 수 있도록 했습니다. 그래서 사용자들이 많이 클릭하는 메뉴 세 개의 하위 메뉴에 'Help&Feedback'이라는 도움말 기능을 넣어 사용자들이 느낀 불편함을 곧바로 찾을 수 있도록 배려했습니다.
사실 슬랙과 비슷한 업무 관리 도구들을 보면, 도움말 기능이 환경설정 메뉴에만 있거나 그 제품의
해당 홈페이지로 이동해야 도움말을 볼 수 있는데, 슬랙은 세 곳에 있는 주 메뉴에 도움말 기능을
동일하게 둠으로써 어떤 기능을 사용하더라도 사용자가 도움말을 접할 수 있는 빠른 환경을 제공합니다.
여러분, 여러분들께서는 현재 사용하고 있는 웹메신저를 처음 사용했을 때를 기억하시나요? 상대방과 대화를 나누려면 어떤 아이콘을 눌러야 하고, 어떤 버튼을 눌러야 파일이 전송되는지 조금은 헤매셨을 것입니다. 하지만, 슬랙에서는 사용자가 처음 슬랙을 실행했을 때부터 헤매지 않게 도와주는 '친절한' 기능이 있습니다. 이 기능은 슬랙의 주요 메뉴 세 곳(대화방 개설, 사용자 정보, 대화 전송)에서 '살아 움직이는' 버튼으로 사용자들의 시선을 끕니다. '살아 움직이는' 동그라미 모양의 이
버튼은 사용자가 해당 메뉴를 누를 때까지 계속 움직입니다. 사용자들은 무심코 이 버튼을 눌렀다가
해당 메뉴를 어떻게 사용해야 하는지 학습하게 되는데, 해당 메뉴를 설명해주는 도움말을 읽고 난 후
'Done(마침)'이라는 버튼을 클릭하지 않으면 계속 움직이는 버튼이 사용자의 주의를 끕니다.
이 버튼은 사용자들에게 슬랙의 다양한 메뉴를 어떻게 사용하는지 익혀두고, 이를 업무 관리에 곧바로 도입할 수 있도록 했습니다.
슬랙은 웹메신저를 기반으로 하는 '업무 관리 도구'로서 특별한 기능이 하나 있습니다. 그것은 바로 '대화 내용 수정' 기능입니다. 이 기능에서는 상대방과 대화를 나눈 후, 내가 했던 대화 내용을 수정할 수 있는데, 타 웹메신저에서는 찾아볼 수 없는 특이한 기능입니다. 저는 처음에 이 기능을 써보
고 의문이 들었습니다. 왜냐하면, 나중에 내 마음대로 대화 내용을 수정할 수 있기 때문입니다.
사용자들은 수정하고 싶은 자신의 대화의 '설정' 아이콘을 누른 뒤, 'edit' 메뉴로 들어가 곧바로
해당 대화 내용을 수정할 수 있습니다. 이렇게 대화 내용 수정이 끝나면 해당 대화 옆에 'edited'라는 문구가 뜨면서 언제 대화 내용을 수정했는지 날짜와 시간까지 구체적으로 확인할 수 있습니다.
제가 슬랙에서 발견한 또 다른 '친절함'은 사용자의 프로필을 설정해주는 '슬랙봇'에서 찾을 수 있었습니다. 슬랙봇은 사용자의 대화자 리스트 내, 첫 번째로 위치하고 있는데 처음 슬랙을 쓰는 사용자
들과 1:1로 대화를 하는 형식으로 사용자의 프로필을 설정할 수 있도록 도와줍니다. 이름을 비롯, 부서명, 프로필 사진 등을 슬랙봇과 대화하면서 입력할 수 있어 재미있게 프로필 설정을 할 수 있습니다. 웹 브라우저의 오른쪽 영역에서도 친절한 슬랙봇을 만날 수 있습니다.
[Bad Point] 제가 이번에 슬랙을 체험하면서 가장 아쉬웠던 점은 한국어 지원이 안 된다는 것이었습니다. 사용자 이름 및 닉네임, 대화방 이름까지 영어로만 설정이 가능해 조금 불편합니다. 물론 우리나라에 정식 출시되거나, 한국어 버전이 나온다는 말은 없지만, 우리나라의 '업무 관리 툴' 시장도
더욱 넓어지고 있는 만큼 더 많은 사람들이 슬랙을 많이 사용해봄으로써 우리나라의 색깔에 맞는
'업무 관리 툴'이 출시되었으면 좋겠습니다.
또 다른 슬랙의 단점으로는 IE(Internet Explorer)에서는 슬랙을 사용할 수 없다는 것입니다. 이 점은
슬랙이 가진 최대의 단점이라고 볼 수 있는데, 특히 우리나라에서는 IE를 기본 웹브라우저를 설정해
인터넷을 사용하는 사람들이 77%에 달하기때문입니다. (자료 출처: StatCounter, 10월 기준)
IE에서 슬랙을 실행해서 메시지를 입력하고, 엔터를 누르는 순간 연결이 되지 않았다는 메시지가
뜹니다. 사용자는 분명히 슬랙에 로그인되어있는데도, 슬랙은 오프라인 상태로 인식합니다. 크롬
이나 파이어폭스 등의 다른 웹브라우저들을 사용하지 않는 사람들에게는 큰 불편함을 초래할 것 같네요.
여러분, 슬랙을 자신의 회사에 도입한 고객들은 3일 만에 이메일 수신량이 75%나 감소했다는 놀라운 결과를 얻었다고 합니다. 그만큼 시간이 오래 걸리고 불필요한 이메일 업무를 깔끔하게 정리해
준 '착한' 도구가 되었다는 뜻이겠죠? 과연 슬랙은 점점 더 치열해지고 있는 '비즈니스 커뮤니케이션 툴' 시장에서 선두 자리를 차지할 수 있을까요? 마냥 '착한' 도구로만 있기에는 '비즈니스 커뮤니케이션 툴' 시장은 너무 냉정합니다.
[링크] Firebase Crashlytics를 Slack과 연동해서 알림 받기 (0) | 2020.03.12 |
---|---|
[링크] [Github - Slack] 완벽하게 연동하기 (0) | 2016.11.01 |
[링크] [Trello - Slack] 완벽 연동 방법 (0) | 2016.11.01 |
[Link] xlCompare as Excel Diff Tool! (0) | 2020.07.02 |
---|---|
[링크] 엑셀 강좌 사이트 (0) | 2018.10.30 |
[링크] 입력할 데이터를 미리 정하기 - 유효성 검사 (0) | 2014.06.14 |
엑셀 틀고정, 첫행고정, 첫열고정 사용하기 (0) | 2014.03.14 |
[링크] https://github.com/pumperer/InfiniteList_NGUI
A component that runs on top of NGUI's UIScrollView & UITable classes for Unity3D (i.e. It requires NGUI & Unity3D) can be used with dynamic data.
Instead of instantiating a Prefab for each row in the list we are instantiating a fixed pool of objects that will be reused according to the scroll direction.
Best suited for Mobile (tested on both iOS & Android).
This demo package requires both Unity3D http://unity3d.com and NGUI http://www.tasharen.com/?page_id=140 to be installed. video: https://www.youtube.com/watch?v=5xFVJqzp0kY
To run the demo:
The demo package is released under the MIT License: http://opensource.org/licenses/MIT
Example of app using this component is Avatar Messenger for Android (Contacts list view) which is a free app on Google Play: https://play.google.com/store/apps/details?id=com.orange.labs.avachat
The main controller script that can be attached to a gameobject (e.g. the panel)
Some of the main methods included:
Initializes the list (also can be called to refresh the list with new data)
public void InitTableView(ArrayList inDataList, List<int> inSectionsIndices, int inStartIndex)
Parameters:
Refresh the list without changing the data (list start at startIndex value)
public void RefreshTableView()
Individual methods for changing the parameters if needed
public void SetStartIndex(int inStartIndex)
public void SetOriginalData(ArrayList inDataList)
public void SetSectionIndices(List<int> inSectionsIndices)
You can include section titles values.. or if you have more detailed sections seperators you can change the implementation of PopulateListSectionWithIndex
string GetTitleForSection(int i)
void PopulateListSectionWithIndex(Transform item, int index)
You can do your implementation of what to populate your row item with (in the demo we simply set a label to string value from our datalist array). Simply change InfiniteItemBehaviour (mentioned later below) to include more items as you want.
void PopulateListItemWithIndex(Transform item, int dataIndex)
Events that can be listened to.
public event InfiniteItemIsPressed InfiniteItemIsPressedEvent;
public event InfiniteItemIsClicked InfiniteItemIsClickedEvent;
Scripts attached to the row item prefab & section prefab (Note: the item prefab need to be tagged as "listItem" and the section prefab as "listSection")
Both checks for the visiblity of the item when the list start scrolling and notifiy the InfiniteListPopulator when the items becomes invisible. you can change use them as a template and include more labels, sprites or textures.
[펌] Blur filter for UITexture in NGUI (0) | 2017.02.09 |
---|---|
[펌] NGUI 쉽게 말풍선 만들기 (0) | 2017.02.03 |
NGUI CoverFlow(with Reflection Shader) (0) | 2016.10.11 |
[Link] Unity-NGUIExtension (0) | 2016.10.10 |
[펌] Smart Localization with NGUI (0) | 2016.09.26 |
For the moment, we have created a static scene with a player and some enemies. It’s a bit boring. Time to enhance our background and scene.
An effect that you find in every single 2D game for 15 years is “parallax scrolling”.
To make it short, the idea is to move the background layers at different speeds (i.e., the farther the layer is, the slower it moves). If done correctly, this gives an illusion of depth. It’s a cool, nice and easy-to-do effect.
Moreover, many shmups use a scrolling in one — or more — axis (except the original one, Space Invaders).
Let’s implement that in Unity.
Adding a scrolling axis need a bit of thinking on how we will make the game with this new aspect.
It’s good to think before coding. :)
We have a decision to take here :
The first choice is a no-brainer if you have a Perspective
camera. The parallax is obvious: background elements have a higher depth. Thus, they are behind and seems to move slower.
But in a standard 2D game in Unity, we use an Orthographic
camera. We don’t have depth at render.
About the camera: remember the “Projection” property of your camera game object. It’s set to Orthographic
in our game.
Perspective
means that the camera is a classic 3D camera, with depth management. Orthographic
is a camera that renders everything at the same depth. It’s particularly useful for a GUI or a 2D game.
In order to add the parallax scrolling effect to our game, the solution is to mix both choices. We will have two scrollings:
Note: you may ask: “Why don’t we just set the camera as a child of the player object?”. Indeed, in Unity, if you set an object (camera or not) as a sub-child of a game object, this object will maintain its relative position to its parent. So if the camera is a child of the player and is centered on him, it will stay that way and will follow him exactly. It could be a solution, but this would not fit with our gameplay.
In a shmup, the camera restricts the player movement. If the camera moves along with the player for both horizontal and vertical axis, then the player is free to go where he wants. We DO want to keep the player inside a restricted area.
We would also recommend to always keep the camera independent in a 2D game. Even in a platformer, the camera isn’t strictly linked to the player: it follows him under some restrictions. Super Mario World has probably one the best camera possible for a platformer. You may have a look at how it is done.
Adding a scrolling to our game has consequences, especially concerning enemies. Currently, they are just moving and shooting as soon as the game starts. However, we want them to wait and be invincible until they spawn.
How do we spawn enemies? It depends on the game, definitely. You could define events that spawn enemies when they are triggered, spawn points, pre-determined positions, etc.
Here is what we will do: We position the Poulpies on the scene directly (by dragging the Prefab
onto the scene). By default, they are static and invincibles until the camera reaches and activates them.
The nice idea here is that you can use the Unity editor to set the enemies. You read right: without doing anything, you already have a level editor.
Once again, it’s a choice, not science. ;)
Note: on a bigger project, you may need a dedicated level editor such as “Tiled” or a custom one you made. Your levels can be text files (plain text, XML, JSON, etc.) that you read in Unity for example.
First, we must define what our planes are and for each, if it’s a loop or not. A looping background will repeat over and over again during the level execution. E.g., it’s particularly useful for things like the sky.
Add a new layer to the scene for the background elements.
We are going to have:
Layer | Loop |
---|---|
Background with the sky | Yes |
Background (1st row of flying platforms) | No |
Middleground (2nd row of flying platforms) | No |
Foreground with players and enemies | No |
We could add as many layers of background objects as we want.
Careful with that axe, Eugene: if you add layers ahead of the foreground layer, be careful with the visibility. Many games do not use this technique because it reduces the clearness of the game, especially in a shmup where the gameplay elements need to be clearly visible.
Okay, we saw how implementing a parallax scrolling affects our game.
Did you know? “Scrolling shooters” is another name used for the shmups.
But enough thoughts, time to practice!
Unity has some parallax scrolling scripts in its standard packages (take a look at the 2D platformer demo on the Asset Store). You can of course use them, but we found it would be interesting to build one from scratch the first time.
Standard packages: these are practicals, but be careful to not abuse of them. Using standard packages can block your thoughts and will not make your game stand out of the crowd. They give a Unity feel to your gameplay.
Remember all the flash game clones?
We will start with the easy part: scrolling backgrounds without looping.
Remember the “MoveScript” we used before? The basis is the same: a speed and a direction applied over time.
Create a new “ScrollingScript” script:
using UnityEngine;
/// <summary>
/// Parallax scrolling script that should be assigned to a layer
/// </summary>
public class ScrollingScript : MonoBehaviour
{
/// <summary>
/// Scrolling speed
/// </summary>
public Vector2 speed = new Vector2(2, 2);
/// <summary>
/// Moving direction
/// </summary>
public Vector2 direction = new Vector2(-1, 0);
/// <summary>
/// Movement should be applied to camera
/// </summary>
public bool isLinkedToCamera = false;
void Update()
{
// Movement
Vector3 movement = new Vector3(
speed.x * direction.x,
speed.y * direction.y,
0);
movement *= Time.deltaTime;
transform.Translate(movement);
// Move the camera
if (isLinkedToCamera)
{
Camera.main.transform.Translate(movement);
}
}
}
Attach the script to these game objects with these values:
Layer | Speed | Direction | Linked to Camera |
---|---|---|---|
Background | (1, 1) | (-1, 0, 0) | No |
Background elements | (1.5, 1.5) | (-1, 0, 0) | No |
Middleground | (2.5, 2.5) | (-1, 0, 0) | No |
Foreground | (1, 1) | (1, 0, 0) | Yes |
For a convincing result, add elements to the scene:
Middleground
.Foreground
, far from the camera.The result:
Not bad! But we can see that enemies move and shoot when they are out of the camera, even before they spawn!
Moreover, they are never recycled when they pass the player (zoom out in the “Scene” view, and look at the left of the scene: the Poulpies are still moving).
Note: experiment with the values. :)
We’ll fix these problems later. First, we need to manage the infinite background (the sky).
In order to get an infinite background, we only need to watch the child which is at the left of the infinite layer.
When this object goes beyond the camera left edge, we move it to the right of the layer. Indefinitely.
For a layer filled with images, notice that you need a minimum size to cover the camera field, so we never see what’s behind. Here it’s 3 parts for the sky, but it’s completely arbitrary.
Find the correct balance between resource consumption and flexibility for your game.
In our case, the idea is that we will get all the children on the layer and check their renderer.
A note about using the renderer component: This method won’t work with invisible objects (e.g., the ones handling scripts). However, a use case when you need to do this on invisible objects is unlikely.
We will use an handy method to check whether an object’s renderer is visible by the camera. We’ve found it on the community wiki. It’s neither a class nor a script, but a C# class extension.
Extension: the C# language allows you to extend a class with extensions, without needing the base source code of the class.
Create a static method starting with a first parameter which looks like this: this Type currentInstance
. The Type
class will now have a new method available everywhere your own class is available.
Inside the extension method, you can refer to the current instance calling the method by using the currentInstance
parameter instead of this
.
Create a new C# file named “RendererExtensions.cs” and fill it with:
using UnityEngine;
public static class RendererExtensions
{
public static bool IsVisibleFrom(this Renderer renderer, Camera camera)
{
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}
}
Simple, isn’t it?
Namespaces: you might have already noted that Unity doesn’t add a namespace around a MonoBehaviour
script when you create it from the “Project” view. And yet Unity does handle namespaces…
In this tutorial, we are not using namespaces at all. However, in your real project, you might consider to use them. If not, prefix your classes and behaviors to avoid a collision with a third-party library (like NGUI).
The real reason behind not using namespaces was that during the Unity 4 days (this tutorial was originally written for Unity 4.3), a namespace would prevent the use of default parameters. It’s not a problem anymore, so: use namespace!
We will call this method on the leftmost object of the infinite layer.
Observe the full “ScrollingScript” (explanations below):
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// Parallax scrolling script that should be assigned to a layer
/// </summary>
public class ScrollingScript : MonoBehaviour
{
/// <summary>
/// Scrolling speed
/// </summary>
public Vector2 speed = new Vector2(10, 10);
/// <summary>
/// Moving direction
/// </summary>
public Vector2 direction = new Vector2(-1, 0);
/// <summary>
/// Movement should be applied to camera
/// </summary>
public bool isLinkedToCamera = false;
/// <summary>
/// 1 - Background is infinite
/// </summary>
public bool isLooping = false;
/// <summary>
/// 2 - List of children with a renderer.
/// </summary>
private List<SpriteRenderer> backgroundPart;
// 3 - Get all the children
void Start()
{
// For infinite background only
if (isLooping)
{
// Get all the children of the layer with a renderer
backgroundPart = new List<SpriteRenderer>();
for (int i = 0; i < transform.childCount; i++)
{
Transform child = transform.GetChild(i);
SpriteRenderer r = child.GetComponent<SpriteRenderer>();
// Add only the visible children
if (r != null)
{
backgroundPart.Add(r);
}
}
// Sort by position.
// Note: Get the children from left to right.
// We would need to add a few conditions to handle
// all the possible scrolling directions.
backgroundPart = backgroundPart.OrderBy(
t => t.transform.position.x
).ToList();
}
}
void Update()
{
// Movement
Vector3 movement = new Vector3(
speed.x * direction.x,
speed.y * direction.y,
0);
movement *= Time.deltaTime;
transform.Translate(movement);
// Move the camera
if (isLinkedToCamera)
{
Camera.main.transform.Translate(movement);
}
// 4 - Loop
if (isLooping)
{
// Get the first object.
// The list is ordered from left (x position) to right.
SpriteRenderer firstChild = backgroundPart.FirstOrDefault();
if (firstChild != null)
{
// Check if the child is already (partly) before the camera.
// We test the position first because the IsVisibleFrom
// method is a bit heavier to execute.
if (firstChild.transform.position.x < Camera.main.transform.position.x)
{
// If the child is already on the left of the camera,
// we test if it's completely outside and needs to be
// recycled.
if (firstChild.IsVisibleFrom(Camera.main) == false)
{
// Get the last child position.
SpriteRenderer lastChild = backgroundPart.LastOrDefault();
Vector3 lastPosition = lastChild.transform.position;
Vector3 lastSize = (lastChild.bounds.max - lastChild.bounds.min);
// Set the position of the recyled one to be AFTER
// the last child.
// Note: Only work for horizontal scrolling currently.
firstChild.transform.position = new Vector3(lastPosition.x + lastSize.x, firstChild.transform.position.y, firstChild.transform.position.z);
// Set the recycled child to the last position
// of the backgroundPart list.
backgroundPart.Remove(firstChild);
backgroundPart.Add(firstChild);
}
}
}
}
}
}
(The numbers in the comments refer to the explanations below)
Start()
method, we set the backgroundPart
list with the children that have a renderer. Thanks to a bit of LINQ, we order them by their X
position and put the leftmost at the first position of the array.Update()
method, if the isLooping
flag is set to true
, we retrieve the first child stored in the backgroundPart
list. We test if it’s completely outside the camera field. When it’s the case, we change its position to be after the last (rightmost) child. Finally, we put it at the last position of backgroundPart
list.Indeed, the backgroundPart
is the exact representation of what is happening in the scene.
Remember to enable the “Is Looping” property of the “ScrollingScript” for the 0 - Background
in the “Inspector” pane. Otherwise, it will (predictably enough) not work.
(Click on the image to see the animation)
Yes! We finally have a functional “parallax scrolling” implementation.
Note: why don’t we use the OnBecameVisible()
and OnBecameInvisible()
methods? Because they are broken.
The basic idea of these methods is to execute a fragment of code when the object is rendered (or vice-versa). They work like the Start()
or Stop()
methods (if you need one, simply add the method in the MonoBehaviour
and Unity will use it).
The problem is that these methods are also called when rendered by the “Scene” view of the Unity editor. This means that we will not get the same behavior in the Unity editor and in a build (whatever the platform is). This is dangerous and absurd. We highly recommend to avoid these methods.
Let’s update our previous scripts.
We said earlier that enemies should be disabled until they are visible by the camera.
They should also be removed once they are completely off the screen.
We need to update “EnemyScript”, so it will:
(The numbers refer to the comments in the code)
using UnityEngine;
/// <summary>
/// Enemy generic behavior
/// </summary>
public class EnemyScript : MonoBehaviour
{
private bool hasSpawn;
private MoveScript moveScript;
private WeaponScript[] weapons;
private Collider2D coliderComponent;
private SpriteRenderer rendererComponent;
void Awake()
{
// Retrieve the weapon only once
weapons = GetComponentsInChildren<WeaponScript>();
// Retrieve scripts to disable when not spawn
moveScript = GetComponent<MoveScript>();
coliderComponent = GetComponent<Collider2D>();
rendererComponent = GetComponent<SpriteRenderer>();
}
// 1 - Disable everything
void Start()
{
hasSpawn = false;
// Disable everything
// -- collider
coliderComponent.enabled = false;
// -- Moving
moveScript.enabled = false;
// -- Shooting
foreach (WeaponScript weapon in weapons)
{
weapon.enabled = false;
}
}
void Update()
{
// 2 - Check if the enemy has spawned.
if (hasSpawn == false)
{
if (rendererComponent.IsVisibleFrom(Camera.main))
{
Spawn();
}
}
else
{
// Auto-fire
foreach (WeaponScript weapon in weapons)
{
if (weapon != null && weapon.enabled && weapon.CanAttack)
{
weapon.Attack(true);
}
}
// 4 - Out of the camera ? Destroy the game object.
if (rendererComponent.IsVisibleFrom(Camera.main) == false)
{
Destroy(gameObject);
}
}
}
// 3 - Activate itself.
private void Spawn()
{
hasSpawn = true;
// Enable everything
// -- Collider
coliderComponent.enabled = true;
// -- Moving
moveScript.enabled = true;
// -- Shooting
foreach (WeaponScript weapon in weapons)
{
weapon.enabled = true;
}
}
}
Start the game. Yes, there’s a bug.
Disabling the “MoveScript” as a negative effect: The player never reaches the enemies as they’re all moving with the Foreground
layer scrolling:
Remember: we’ve added a “ScrollingScript” to this layer in order to move the camera along with the player.
But there is a simple solution: move the “ScrollingScript” from the Foreground
layer to the player!
Why not after all? The only thing that is moving in this layer is him, and the script is not specific to a kind of object.
Push the “Play” button and observe: It works.
(Click on the image to see what happens)
You might have noticed that the player is not (yet) restricted to the camera area. “Play” the game, push the “Left Arrow” and watch him leaves the camera.
We have to fix that.
Open the “PlayerScript”, and add this at the end of the “Update()” method:
void Update()
{
// ...
// 6 - Make sure we are not outside the camera bounds
var dist = (transform.position - Camera.main.transform.position).z;
var leftBorder = Camera.main.ViewportToWorldPoint(
new Vector3(0, 0, dist)
).x;
var rightBorder = Camera.main.ViewportToWorldPoint(
new Vector3(1, 0, dist)
).x;
var topBorder = Camera.main.ViewportToWorldPoint(
new Vector3(0, 0, dist)
).y;
var bottomBorder = Camera.main.ViewportToWorldPoint(
new Vector3(0, 1, dist)
).y;
transform.position = new Vector3(
Mathf.Clamp(transform.position.x, leftBorder, rightBorder),
Mathf.Clamp(transform.position.y, topBorder, bottomBorder),
transform.position.z
);
// End of the update method
}
Nothing complicated, just verbose.
We get the camera edges and we make sure the player position (the center of the sprite) is inside the area borders.
Tweak the code to better understand what is happening.
We have a scrolling shooter!
We have just learned how to add a scrolling mechanism to our game, as well as a parallax effect for the background layers. However, the current code only works for right to left scrolling. But with your new knowledge, you should be able to enhance it and make it work for all scrolling directions (bonus: We did it as someone was stuck on the subject, click to see the code and an animation).
Still, the game really needs some tweaks to be playable. For example:
We will address these points in our upcoming chapter about gameplay tweaking (not released yet, unfortunately). For the moment, you can experiment. ;)
In the next chapter, we will focus our attention on how to make the game a bit more… flashy. With particles!
[출처] http://pixelnest.io/tutorials/2d-game-unity/parallax-scrolling/
[펌] StreamingAssets 폴더 지정하기 (0) | 2016.11.10 |
---|---|
Invert ParticleEffect Velocity (0) | 2016.11.09 |
[펌] Music player - (load sound files at runtime from directory, and play them) (1) | 2016.09.27 |
[펌] OnApplicationFocus 와 OnApplicationPause 차이 (0) | 2016.09.22 |
[펌] CUSTOM COROUTINES(Unity 5.3) (0) | 2016.07.21 |
필요한 경우가 아니면 GameObject를 비활성화 해라. 개체수를 감소시켜라.
필요한 경우가 아니면 Scripts를 비활성화 해라.
Find, FindByTag, GetComponent류의 사용을 자제해야 한다. 특히 Update, FixedUpdate같은 곳에서 지속적으로 사용하는 것은 퍼포먼스에 악영향이 있다. Awake, OnEnable에서 미리 찾아서 가지고 있는 것이 좋다.
Transform.position, gameObject.transform, gameObject.camera 등 유니티 엔진에서 C# 프로퍼티로 랩핑하여 제공하는 변수 타입에 접근시에 부하와 임시 객체가 생성된다. 캐싱하여 사용하는 것이 좋다.
태그 비교시에 if ( go.tag == “myBot” ) 구문 대신에 go.compareTag(“myBot”)을 사용하는 것이 임시 객체 생성을 회피하는 방법이다.
LINQ 명령어를 사용하는 경우 중간 버퍼가 할당된다. 이는 가비지로 남게 된다.
SendMessage류의 사용을 자제해야 한다. 직접 함수를 호출하는 경우보다 SendMessage류를 사용하는 경우 100배 느리다. 그리고 호출시에 함수 이름을 넣게 되는데 코드 난독화가 필요한 경우 장애요소가 된다.
foreach()를 사용할 경우 enumerator를 생성하기 위해서 힙 메모리를 할당한다. for(;;)문을 활용하는 것이 좋다. 한번 돌 때마다 24bit의 가비지를 남긴다.
[출처] http://www.antegg.com/wiki/doku.php?id=note:unity_3d:%EC%B5%9C%EC%A0%81%ED%99%94_tips
[펌] Disable Screen Auto Rotation on Unity3D (0) | 2016.11.03 |
---|---|
[링크] Unity Technologies (0) | 2016.11.01 |
[펌] 유니티 SendMessage 사용의 장점 (0) | 2016.10.26 |
[Tip] Coroutine Optimization Technique (0) | 2016.10.07 |
[펌] 에디터에서 게임 플레이를 할 때 저장되지 않은 Assets 저장하기 (0) | 2016.09.30 |