Skip to content
isdnetworks
Go back

누르는 자리가 너무 작았다

게임 버튼이 잘 안 눌린다는 얘기를 들었다. 내가 해 보니 눌리기는 해서 뭐가 문제인지 바로 안 보였다.

Table of contents

Open Table of contents

가장자리가 안 눌렸다

같은 버튼을 여러 번 눌러 보니 가운데는 잘 눌리고 가장자리는 안 눌렸다. 코드를 열어 보니 boundingBox() 가 준 CCRect 를 그대로 누르는 영역으로 쓰고 있었다.

CCRect r = button->boundingBox();
if (r.containsPoint(touch)) { ... }

이미지를 열어 봤더니 가장자리에 투명한 여백이 있었다. 전체가 60픽셀인데 실제 그림은 40픽셀이고 나머지는 비어 있다. 그러면 보이는 것보다 영역이 오히려 크니까 더 잘 눌려야 하는데 반대였다.

손가락 쪽을 생각해 보니 이유가 짐작됐다. 화면은 접촉을 CCTouch 한 점으로 주는데 실제 손가락 끝은 넓은 면적으로 닿는다. 그래서 인식되는 점이 내가 누르려던 자리와 조금 어긋난다. 작은 기기에서 특히 심했다. 화면 크기에 맞춰 비율로 줄이고 있어서 작은 화면에서는 버튼도 같이 작아졌기 때문이다.

보이는 크기와 누르는 크기를 나눴다

CCMenuCCMenuItem 을 안 쓰고 직접 만든 버튼이라 containsPoint() 판정도 우리 코드에 있었다. 먼저 최소 크기를 정했다. 화면이 아무리 작아도 그 이하로는 안 줄인다.

float size = max(baseSize * scale, MIN_TOUCH_SIZE);

값은 손가락 끝 크기를 기준으로 잡고 여러 사람이 눌러 보게 하면서 조정했다.

그다음 보이는 크기와 누르는 크기를 아예 나눴다. CCRectMake 로 여유를 더해 누르는 자리를 조금 더 크게 잡았다.

CCRect touchArea = CCRectMake(
    r.origin.x - PADDING, r.origin.y - PADDING,
    r.size.width + PADDING*2, r.size.height + PADDING*2);

영역이 겹쳤다

영역을 키우니 버튼이 붙어 있는 자리에서 두 영역이 겹쳤다. 겹치면 둘 다 반응하거나 엉뚱한 쪽이 눌린다.

버튼 사이에 간격을 두어 대부분을 해결했는데 그래도 겹치는 데가 남았다. 그건 위에 있는 것이 먼저 받게 했다. 자식 목록을 뒤에서부터 보면 나중에 그린 것이 먼저 걸린다. 나중에 CCMenu 쪽을 열어 보니 itemForTouch 는 반대로 앞에서부터 훑어 첫 매치를 쓴다. 겹치면 목록 앞쪽이 이기는 것이라 우리와 판단이 달랐다.

for (int i = children.size() - 1; i >= 0; i--) {
    if (children[i]->hit(touch)) { return children[i]; }
}

그리고 하나가 받으면 거기서 멈추게 했다. 전부 확인하면 겹친 영역에서 여러 개가 반응한다.

누를 때가 아니라 뗄 때

또 하나 걸린 것이 있었다. 누르는 순간에 바로 동작하게 돼 있어서 잘못 눌렀을 때 취소할 방법이 없다.

뗄 때 실행하도록 바꿨다. 이것도 CCMenu 쪽을 열어 보니 거기는 처음부터 그렇게 돼 있다. ccTouchEnded 에서 unselected() 를 부르고 그다음에 activate() 를 부른다. 누르면 눌린 모양으로 바뀌고, 손가락을 밖으로 빼면 원래대로 돌아가고, 안에서 떼야 실행된다. 이러면 잘못 눌러도 밖으로 빼서 취소할 수 있다.

대신 눌렸다는 표시가 필요해졌다. 바로 실행할 때는 결과가 곧장 보여서 눌린 것을 아는데, 뗄 때 실행하면 누르고 있는 동안 아무 일도 안 일어나서 눌린 것이 맞나 싶어진다. 눌리는 동안 모양이 살짝 작아지거나 어두워지게 했고 짧은 소리도 넣었다. 소리가 있으면 화면을 안 봐도 눌린 것을 안다.

정리


Share this post on:

Previous Post
색 넷을 가르는 기준
Next Post
환경마다 설정이 달랐다