일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Document Class
- MMOKit
- scaleform
- 수학정석
- flash
- 집합의 연산
- flash cs3
- 클릭
- watch
- 플래시
- scaleform3
- as3
- Chart
- as2
- 강좌
- CLIK
- 형변환
- 스케일폼
- as3.0
- scaleform4
- 애드온
- DataBinding
- autodesk
- flash player 10
- ApplicationDomain
- KGC 2013
- GDC
- addChild
- 태그클라우드
- 샌프란시스코
- Today
- Total
scaleform.minarto.com
UI에서의 시간 갱신 본문
UI를 만들다 보면 시간과 관련된 개발을 할 때가 꽤 많습니다.
단순히 시계 표시도 있고, 카운터도 많죠... 시간에 관한 프로그레스 바도 있고 암튼 게임 장르를 가리지 않고 굉장히 많습니다.
간단하게는 enterframe 로 만들겠지만 이 방식도 문제가 있습니다. 시스템이 버벅거리면 오차가 발생하기 때문입니다
저같은 경우는 다음과 같은 라이브러리를 만들어서 사용합니다
https://github.com/minarto/scaleform-as2-libraries/blob/master/src/com/minarto/data/DBind.as
예를 든건 as2버전이지만, as3 버전도 이론적으로 똑같습니다. (라이브러리에 올라가있는 as3 버전은 옛날 코드이니 문제가 발생할 수 있습니다)
스케일폼에서는 시간을 어쨌든 클라이언트(서버)로 부터 받아야 합니다. 로컬의 시간은 유저가 언제든지 변경 가능하기 때문입니다.
그렇다고 해서 서버로부터 매초... 아니 매 밀리초마다 시간을 갱신할 수도 없습니다. 그러기에는 서버부하, 대역폭, 인보크 타임 증가 등 너무 많은 손실이 생깁니다.
저 코드는 클라이언트가(정확히는 스케일폼이) 동작해서 경과된 시간을 기반으로 합니다. 그래서 서버 시간과의 오차를 가지고선 계속 가감을 해주는 방식입니다.
서버에서 자주 최신 시간(?)을 받아주면 오차는 더 줄겠지만, 뭐 어쨌든 그건 클라이언트나 서버가 하기 나름입니다.
코드 일부만 잠시 살펴보겠습니다.
import com.minarto.data.*; class com.minarto.data.DBind extends Bind { static private function getOffsetTime():Number { var bind:Bind = BindDic.get("main"), offsetTime:Number, date:Date; var onTime = function($year:Number, $month:Number, $date:Number, $hour:Number, $min:Number, $sec:Number, $millisec:Number) { var date:Date = new Date($year, $month, $date, $hour, $min, $sec || 0, $millisec || 0); offsetTime = date.getTime() - getTimer(); } bind.add("serverDate", null, onTime); date = new Date; bind.evt("serverDate", date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()); getOffsetTime = function() { return offsetTime; } return getOffsetTime(); } /** * get current date * @return */ static public function getDate():Date { return new Date(getOffsetTime() + getTimer()); } public function toString():String { return "[com.minarto.data.DBind interval:" + getInterval() + "sec]" } private var interval:Number = 100, intervalID:Number; /** * set interval * @param $interval */ public function init($interval:Number):Void { interval = ($interval || 0.1) * 1000; if(intervalID) { this.play(); } } private function intervalFunc():Void { var key:String, date:Date = getDate(); for (key in handlerDic) { evt(key, date); } } /** * play */ public function play():Void { clearInterval(intervalID); intervalID = setInterval(this, "intervalFunc", interval); } /** * stop */ public function stop():Void { clearInterval(intervalID); intervalID = NaN; } /** * is playing */ public function getIsPlaying():Boolean { return Boolean(intervalID); } /** * get interval */ public function getInterval():Number { return interval * 0.001; } }
이 코드를 이해하시려면 Bind 코드도 알아두시는게 좋지만, 그렇지 않아도 흐름은 보실 수 있을 겁니다
클라(서버)로 부터 현재 시간을 받죠. "serverDate" 라는 값으로 받아서 현재까지의 경과시간과의 오차를 구합니다. 그게 바로 offsetTime 입니다.
그걸 구했다면 이 클래스에 설정된 시간(interval값)마다 갱신하면서 그 오차값을 더해서 현재의 시간을 구해주는 코드입니다.
클라는 서버시간 갱신을 1분에 한번씩 해도 될 것이고, 1시간에 한번씩 해도 되겠죠... 마지막 오차값을 사용해서 시간을 구할 뿐입니다.
이 방식을 사용하면 1ms 마다 갱신해야할 UI 요소가 있다고 하더라도 클라나 서버와의 시간 갱신은 필요가 없습니다.
(물론 오차가 두렵다면 서버시간 갱신을 자주 해주면 되는 겁니다)