Phaser 4 Pseudo 3D 레이싱 게임 - 헤드라이트를 사다리꼴 하나에서 두 개의 광원으로 바꾸기
Apex Seoul의 야간 헤드라이트가 조향과 고저차에서 어색해진 이유를 좌표계·차량 sprite 방향·빛 합성으로 나눠 추적했습니다. camera 기준 cone, 단일 회전 사다리꼴, 과도한 중심 수렴, 잘못된 lift를 버리고 실제 램프 위치에서 시작하는 두 광원 구조와 terrain별 위치 검증으로 정리한 기록입니다.
상태 관리란 무엇일까요? 위키 설명을 따르자면 텍스트 필드 같은 여러개의 UI 컨트롤의 상태를 관리하는 것을 의미합니다.
예를 들자면, 회원 가입창에 이메일이 유효하면 전송 버튼이 활성화되고 유효하지 않으면 단추가 비활성화되는것 같은 상황은 상태에 따른 UI 컨트롤이 관리되는 경우입니다.
사실 이래선 기존이랑 뭐가 다른지 알 수가 없습니다. 여기서는 flutter 를 예를 들어보도록 하겠습니다. flutter의 구성은 widget 들의 조합입니다. 최상위 root widget 에서 하위 widget 을 포함하는 전형적인 tree 구조를 가집니다.
어디선가 비슷하죠?
react 나 vue.js 같은 frontend framework 가 연상됩니다.
각 ui widget 들은 다른 widget 들간의 연결은 느슨하게 유지됩니다.
데이터는 bloc 패턴과 같은 stream 에 대한 event 로 리스닝 받고 있고요.
(자세한 내용은 bloc pattern 이나 reactive programming 개념은 검색 해보세요!)

버스 타요~
mobx 는 react 계열의 인기있는 상태 관리 라이브러리입니다.
개인적으로 mobx 를 좋아하기 때문에 flutter 에 mobx 라이브러리 나와서 한번 다루어 보도록 하겠습니다.
자세한 내용은 React에서 Mobx 경험기 (Redux와 비교기) 를 참조하세요.
여기에서는 mobx.pub 문서를 참조하였습니다.
pubspec.yaml 파일에 참조 라이브러리를 설치합니다.
여기서는 버전 정보를 일부러 건너 뛰었습니다. pub.dev 에서 최신 버전을 참조해서 가져오세요.
dependencies:
mobx: ^0.3.7
flutter_mobx: ^0.3.2
다음에는 dev_dependencies 를 추가합니다.
dependencies:
build_runner: ^1.6.7
mobx_codegen: 0.3.7
아래 명령어로 패키지를 설치합니다.
flutter packages get
여기서는 간단한 counter 샘프을 만들어 보도록 하겠습니다.
store 를 추가하기 위해 counter.dart 파일을 만들어 보겠습니다.
import 'package:mobx/mobx.dart';
// Include generated file
part 'counter.g.dart';
// This is the class used by rest of your codebase
class Counter = _Counter with _$Counter;
// The store-class
abstract class _Counter with Store {
@observable
int value = 0;
@action
void increment() {
value++;
}
}
추상 클래스 _Counter 는 store 를 포함하고 있으며,
store 관련 코드는 모두 여기 클래스에 담게 됩니다.
데이터는 observable annotation 으로 작성하며
데이터를 조작하는 코드는 action annotation 으로 작성합니다.
(더 많은 예제는 mobx 공식 문서를 참조하세요.)
기존 js 에서와 달리 build_runner 로 통해 코드를 생성되게 됩니다. (webpack 인가봐요) part 지시자를 통해서 추상 클래스가 변활될 파일들을 지정하게 됩니다.
아래 명령어를 통해 counter.g.dart 파일을 생성합니다.
flutter packages pub run build_runner build
import 'counter.dart'; // Import the Counter
final counter = Counter(); // Instantiate the store
생성된 카운터 클래스를 가져오고 선언합니다.
class MyHomePage extends StatelessWidget {
const MyHomePage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MobX Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
// Wrapping in the Observer will automatically re-render on changes to counter.value
Observer(
builder: (_) => Text(
'${counter.value}',
style: Theme.of(context).textTheme.display1,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: counter.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
참조하시면 StatefuleWidget 을 더이상 사용하지 않는 것을 볼 수 있습니다. state 는 Counter store 에 보관되며, Observer Widget 를 통해 값을 렌더링하는 것이죠.
FloatingActionButton widget 클릭시 counter.increment action 을 호출하게 됩니다.
와 간단하게 counter 앱이 만들어졌어요!

이번 내용은 뭔가 깊이가 없어서 아쉽습니다. 다음번에는 좀 더 쉽게 더 재미있게 풀어서 연재해보도록 하겠습니다.
감사합니다.
Apex Seoul의 야간 헤드라이트가 조향과 고저차에서 어색해진 이유를 좌표계·차량 sprite 방향·빛 합성으로 나눠 추적했습니다. camera 기준 cone, 단일 회전 사다리꼴, 과도한 중심 수렴, 잘못된 lift를 버리고 실제 램프 위치에서 시작하는 두 광원 구조와 terrain별 위치 검증으로 정리한 기록입니다.
Apex Seoul의 밤 다운힐을 실제 주행 기준으로 다시 보며, 수평선에 잘리던 숲을 SVG 군집으로 교체하고, road와 roadside를 같은 어둠으로 수렴시키고, 차량 전방의 두 타원 헤드라이트와 FT86형 파워밴드를 시행착오 끝에 정리한 기록입니다.
Apex Seoul의 밤 다운힐 비주얼을 왼쪽 절벽·가드레일, 오른쪽 옹벽·수목 구조로 재정리하고, 가드레일 충돌, 저속 조향 pose, standing start 파워밴드까지 주행 로그와 자동 QA로 다시 맞췄습니다.
Apex Seoul에서 200km/h grip 주행이 너무 쉽게 느껴진 이유를 주행 로그로 분해하고, 코스 곡률을 바꾸지 않은 채 하향 코너 속도 예산·understeer·안전 여유 비용·자동 검증으로 다운힐의 선택을 만들었습니다.
Apex Seoul에 스페이스 브레이크 기반 드리프트와 카운터 스티어를 넣고, 입력을 놓았을 때의 복귀·전환을 별도 상태로 분리했습니다. 주행 로그와 자동 시나리오로 감각을 수치화하며, 스핀은 아직 구현하지 않기로 한 이유도 정리합니다.
Apex Seoul을 한 번 내려오는 다운힐 런으로 정리하고, 고속 조향과 코너 감속을 실제 주행 로그로 다시 튜닝한 뒤, FT86 기반 Raven Coupe에 NA 고회전 RPM, 기어, 토크 곡선, fuel cut 상태를 붙였습니다.