반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
어제까지 잘 실행해 보셨나요?

저의 경우엔 textfield 하고 textarea 표시할 때 label (Title, Narrative) 가 안나오더라구요.
그리고 상단 툴바에 home 버튼만 나오고 save 버튼은 안나오구요.
그리고 하단 버튼에 trash 버튼도 안 나오고......


원래는 이렇게 나와야 되는데 아래처럼 나오네요.


저 왼쪽 스크롤을 내리면은 아래 툴바가 나오긴 하는데 trash 버튼은 안 나옵니다.

브라우저 버전일까 싶어서 크롬 최신버전으로 깔아도 똑 같은 문제네요.
이 소스가 원래 Sencha Touch 1.1.1 버전을 기반으로 한 거라서 따로 인터넷 검색해서 1.1.1 버전의 css 하고 js 파일을 다운 받아 썼는데... 그 파일 버전이 잘못 된건지......

여러분은 어떻게 나오시나요?

일단 오늘 Sencha Touch 의 Notes Application 마지막 부분을 정리하겠습니다.
잘 안되는 부분은 다시 해결해 봐야겠습니다.
(맨 아래 최종버전 압축파일 올리겠습니다.)
혹시 원래 설계대로 잘 되시는 분 있으면 연락 주세요.

===== o ===== o ===== o ===== o ===== o =====

이번 강좌가 Sencha Touch 로 첫번째 앱 만들기 마지막 시간입니다.
지난 시간에는 Note Editor 와 새로운 Notes를 생성하는 기능을 구현해 봤습니다.
이제 수정하고 delete하는 기능을 살펴 보겠습니다.

***** Disclosure events in a Sencha Touch List

유저가 이 앱을 사용하면서 disclosure 버튼(화살표 버튼)을 누르게 되면 해당 Note의 제목과 내용이 보여지게 됩니다.



우리는 이 기능을 notes list의 onItemDisclosure 핸들러를 통해 구현할 수 있습니다.

NotesApp.views.notesList = new Ext.List({
    id: 'notesList',
    store: 'NotesStore',
    onItemDisclosure: function (record) {
        var selectedNote = record;
        NotesApp.views.noteEditor.load(selectedNote);
        NotesApp.views.viewport.setActiveItem('noteEditor', { type: 'slide', direction: 'left' });
    },
    itemTpl: '
<div class="list-item-title">{title}</div>' +
        '<div class="list-item-narrative">{narrative}</div>',
    listeners: {
        'render': function (thisComponent) {
            thisComponent.getStore().load();
        }
    }
});

이 핸들러 함수는 파라미터로서 선택된 note를 받습니다. 이 핸들러에서 우리가 구현해야 할 것은 에디터의 load()메소드를 사용해서 note를 load 하는 겁니다.
그리고 나서 viewport의 setActiveItem()을 호출해서 Note Editor의 view를 active 시킵니다.

***** Removing records from a data store

notes를 지우는 기능도 아주 간단히 구현할 수 있습니다.
화면 아래 툴바에 있는 휴지통 버튼이 이 기능을 실행하도록 할 겁니다.
아래처럼 이 버튼 핸들러를 수정합니다.

NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
    dock: 'bottom',
    items: [
        { xtype: 'spacer' },
        {
            iconCls: 'trash',
            iconMask: true,
            handler: function () {

                var currentNote = NotesApp.views.noteEditor.getRecord();
                var notesList = NotesApp.views.notesList;
                var notesStore = notesList.getStore();

                if (notesStore.findRecord('id', currentNote.data.id)) {
                    notesStore.remove(currentNote);
                }

                notesStore.sync();

                notesList.refresh();
                NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction:

'right' });
            }
        }
    ]
});

현재의 note에 대한 reference 정보들을 확보한 다음에 우리는 store의 findRecord() 함수를 사용해 에디터에 로드된 note를 찾아서 지울겁니다.
그리고 나서 sync()를 호출해서 이 삭제작업에 대해 commit 합니다. 그리고 다시 리스트를 render 해서 새로운 Notes List view를 보여줍니다.

이 기능은 Save Note 부분에서 처리됐던 과정이랑 비슷합니다. 단지 saving 이 아니라 deleteing 만 달르 뿐입니다.

***** Grouping items in a Sencha Touch List

이제 마지막으로 남은것은 Notes List view 에서 날짜별로 그루핑 하는 겁니다. 유저가 note들을 날짜별로 구분해서 보면 훨씬 더 보기 좋을테니까요.

첫번째로 Ext.List에게 아이템들이 group화 되어야 한다고 알려줘야 합니다. 이것은 grouped config 옵션을 사용해서 구현할 수 있습니다.

NotesApp.views.notesList = new Ext.List({
    id: 'notesList',
    store: 'NotesStore',
    grouped: true,
    emptyText: '<div style="margin: 5px;">No notes cached.</div>',
    onItemDisclosure: function (record) {
        var selectedNote = record;
        NotesApp.views.noteEditor.load(selectedNote);
        NotesApp.views.viewport.setActiveItem('noteEditor', { type: 'slide', direction: 'left' });
    },
    itemTpl: '<div class="list-item-title">{title}</div>' +
        '<div class="list-item-narrative">{narrative}</div>',
    listeners: {
        'render': function (thisComponent) {
            thisComponent.getStore().load();
        }
    }
});

그 다음엔 NotesStore의 getGroupStrint() 함수를 오버라이드 해야 합니다.

Ext.regStore('NotesStore', {
    model: 'Note',
    sorters: [{
        property: 'date',
        direction: 'DESC'
    }],
    proxy: {
        type: 'localstorage',
        id: 'notes-app-store'
    },
    getGroupString: function (record) {
        if (record && record.data.date) {
            return record.get('date').toDateString();
        } else {
            return '';
        }
    }
});

이제 groupField 프로퍼티와 getGroupString() 함수를 이용해서 구체적인 사항들을 정의하실 수 있습니다.

getGroupString() 함수는 store의 data model 프로퍼티에 근거한 string을 리턴합니다.
이 앱의 경우는 그룹의 헤더로 note의 date 값을 사용할 겁니다.
에뮬레이터로 보면 아래와 같이 나올 겁니다.



***** We made it!


이제 완성했습니다. 아주 간단한 Sencha Touch 애플리케이션이죠? 그래서 Sencha Touch 프레임워크에 대해 쉽게 이해할 수 있을 것 같습니다.
이제 첫번째 앱을 만들면서 감을 잡았으니 Sencha Touch로 된 좀 더 복잡한 애플리케이션을 만들 수 있을 겁니다.

아래 지금까지 진행한 소스가 있습니다.
다운받아서 실행해 보세요.


이걸 실행해보면 처음에 얘기했던대로 제 브라우저에서는 label 도 안나오고 save 버튼하고 trash 버튼 모두 안나오네요.

여러분은 제대로 나오시는지 궁금하네요.
sencha-touch.css 하고 sencha-touch-debug.js 도 다른 버전으로 바꿔보고 브라우저도 여러군데서 실험해 봐야겠습니다.

성공하신분 댓글로 정보 부탁드립니다.

다음엔 Sencha Touch 최신버전 (2.0) 에 맞는 예제소스로 공부해 볼 생각입니다.

추천추천 부탁드려요..~~~~~~~~~~~
반응형


반응형
지난 시간에는 New 버튼을 달고 더미 데이터를 넣어서 List 를 출력해 봤습니다.
잘 되셨나요?

지난주까지 진행한 소스코드 아래에 있습니다.
필요하신 분은 받아서 보세요.


오늘은 Note Editor 부분을 하겠습니다.
Notes List 에서 Note Editor 화면으로 전환하고 새 데이터를 넣고 저장하고 이것을 List 로 새로 출력하는 기능을 할 겁니다.
이 과정에서 validation도 체크하는 기능도 다룰거구요.

아래 오늘의 내용을 보시죠.

Writing a Sencha Touch Application, Part 3

Part 1,2 에서는 Notes 앱 중에 Notes List view 부분을 다뤘습니다. 오늘은 Note Editor view를 다루겠습니다.
타이틀은 Edit Note 가 될 텐데요. Note의 생성, update, 삭제 기능이 있을 겁니다.
아래 Mock up 이미지와 완성 화면이 있습니다.








***** Creating a Sencha Touch Form Panel

Note Editor mockup을 보면 우리는 툴바와 필드들을 만들어야 합니다.
우선 form field들 부터 만들겠습니다.

NotesApp.views.noteEditor = new Ext.form.FormPanel({
    id: 'noteEditor',
    items: [
        {
            xtype: 'textfield',
            name: 'title',
            label: 'Title',
            required: true
        },
        {
            xtype: 'textareafield',
            name: 'narrative',
            label: 'Narrative'
        }
    ]
});


이 필드들을 만들기 위해 Ext.form.FormPanel 클래스를 사용했습니다. 센차터치에서 form 필드들을 만들 때 가장 손쉽게 만들 수 있는 방법입니다.
제목은 textfield를 사용하고 내용을 넣는 공간은 Text field를 사용합니다.
title 부분에 required 를 true로 했습니다. 반드시 이곳에 값을 넣어야 한다는 겁니다. 디비의 not null 이죠. 나중에 save 하는 단계에서 이곳에 값을 넣지 않으면 어떻게 되는지 보실 수 있습니다.

툴바를 넣기 전에 이 form들의 모습이 어떤지 미리 보면 좋겠죠? viewport 부분을 약간 수정해서 이 form이 보이도록 해 보죠.
viewport의 items 부분을 수정해 아래처럼 수정해 보세요. 그러면 지난번에 만들었던 list가 아니라 edit form이 나올겁니다.

NotesApp.views.viewport = new Ext.Panel({
    fullscreen: true,
    layout: 'card',
    cardAnimation: 'slide',
    items: [NotesApp.views.noteEditor] // TODO: revert to [NotesApp.views.notesListContainer]
});

제대로 됐다면 아래처럼 보일겁니다.




***** Adding top and bottom toolbars to a Sencha Touch Panel

이제 툴바를 만들 차례입니다.
첫번째 툴바는 Home 과 Save 버튼이 있는 위쪽 툴바입니다.

NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
    title: 'Edit Note',
    items: [
        {
            text: 'Home',
            ui: 'back',
            handler: function () {
                // TODO: Transition to the notes list view.
            }
        },
        { xtype: 'spacer' },
        {
            text: 'Save',
            ui: 'action',
            handler: function () {
                // TODO: Save current note.
            }
        }
    ]
});

위 소스 콛를 보시면 툴바를 만들면서 ui config 옵션을 사용하신 걸 보실 수 있을 겁니다. (back, action 으로 정의했죠?) home 버튼에는 back 이라고 정의했습니다. 왜냐하면 이 버튼을 누르면 back 해서 main view 로 갈 것이기 때문입니다. 그리고 save 버튼에는 action이라고 정의했는데요. 이것은 유저가  이 버튼을 누르면 note를 save 할 거라는 겁니다. 이 기능이 가장 중요한 기능 중 하나죠?



화면 아래에 있는 툴바에는 휴지통 버튼이 들어갈 겁니다. 이 버튼을 누르면 해당 note 가 delete 되겠죠?
NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
    dock: 'bottom',
    items: [
        { xtype: 'spacer' },
        {
            iconCls: 'trash',
            iconMask: true,
            handler: function () {
                // TODO: Delete current note.
            }
        }
    ]
});

여기에 몇가지 주의하실 부분이 있습니다. 첫번째로 dock config를 어떻게 사용했는지 보세요. 화면 아래에 배치하기 위해 bottom을 사용했습니다. 그리고 iconCls와 iconMask config 옵션을 보세요. 이 기능들은 버튼 안에 trash icon을 render 하기 위한 옵션들입니다.



이제 툴바를 add 하실 수 있습니다.

NotesApp.views.noteEditor = new Ext.form.FormPanel({
    id: 'noteEditor',
    items: [
        {
            xtype: 'textfield',
            name: 'title',
            label: 'Title',
            required: true
        },
        {
            xtype: 'textareafield',
            name: 'narrative',
            label: 'Narrative'
        }
    ],
    dockedItems: [
            NotesApp.views.noteEditorTopToolbar,
            NotesApp.views.noteEditorBottomToolbar
        ]
});

약간 코드를 수정해서 지금까지 한 작업을 화면으로 볼 수 있도록 해 보죠.

NotesApp.views.viewport = new Ext.Panel({
    fullscreen: true,
    layout: 'card',
    cardAnimation: 'slide',
    items: [NotesApp.views.noteEditor] // TODO: revert to [NotesApp.views.notesListContainer]
});

성공했으면 아래와 같은 화면을 보실 수 있을 겁니다.




아주 훌륭하죠?

지금까지 우리는 Notes List와 Note Editor 뷰를 만들었습니다. 이제 필요한 것은 이 앱의 workflow 입니다. 뷰 이외에 다른 비지니스 로직을 어떻게 구현하느냐를 말하는 것이죠. 우선 첫번째 기억할 비지니스 로직(Navigate screen) 은 Notes List 에서 New 버튼을 누르면 Notes Edit View 로 간다는 겁니다.



****** How to change views in a Sencha Touch application

이제 Notes List view 로 가 볼까요? 이제 New 버튼의 handler 부분을 다룰 차례입니다. 이 버튼이 눌려지면 새로운 note를 만들 수 있어야 합니다. 그러니까 이 버튼을 누르면 Note Editor를 화면에 보이도록 하면 되곘죠.

NotesApp.views.notesListToolbar = new Ext.Toolbar({
    id: 'notesListToolbar',
    title: 'My Notes',
    layout: 'hbox',
    items: [
        { xtype: 'spacer' },
        {
            id: 'newNoteButton',
            text: 'New',
            ui: 'action',
            handler: function () {

                var now = new Date();
                var noteId = now.getTime();
                var note = Ext.ModelMgr.create(
                    { id: noteId, date: now, title: '', narrative: '' },
                    'Note'
                );

                NotesApp.views.noteEditor.load(note);
                NotesApp.views.viewport.setActiveItem('noteEditor', {type: 'slide', direction: 'left'});
            }
        }
    ]
});

순서대로 한번 볼까요?
첫번째로 ModelMgr 클래스의 create()메소드를 사용해서 새로운 note를 생성합니다.

var now = new Date();
var noteId = now.getTime();
var note = Ext.ModelMgr.create(
    { id: noteId, date: now, title: '', narrative: '' },
    'Note'
);

그리고 나서 이 새 note를 Note Editor에 전해줍니다. FormPanel에서 이 부분이 보이도록 하기 위해 load 메소드를 사용했습니다. 이 load 메소드는 필드들을 보여줄겁니다. 이때 value 값들이 있으면 그 value 값들도 보여 줄 거구요.

NotesApp.views.noteEditor.load(note);

다음으로는 우리가 viewport에서 card layout을 사용했듯이 viewport이 setActiveItem()메소드를 사용해서 Note Editor를 보이도록 할 겁니다.
이 setActiveItem()을 call 하면 우리는 우리가 active 시키려고 하는 card의 id를 전달해 주고 그 객체가 transition 하는 animation 기능을 사용할 수 있습니다.

NotesApp.views.viewport.setActiveItem('noteEditor', {type: 'slide', direction: 'left'});

이 New 버튼이 어떻게 작동하는지 확인하기 전에 viewport의 items array를 약간 수정해야 합니다.

NotesApp.views.viewport = new Ext.Panel({
    fullscreen: true,
    layout: 'card',
    cardAnimation: 'slide',
    items: [
        NotesApp.views.notesListContainer,
        NotesApp.views.noteEditor
    ]
});



여기까지 완성 됐나요? 그러면 이제 user가 작성한 note를 save 할 수 있도록 하시면 됩니다.
이 기능은 당연히 Note Editor의 Save 버튼에 달아야 겠죠.

***** Validating a data model in Sencha Touch

save 버튼을 누르게 되면 우선 체크해야 할 것들이 몇가지 있습니다.

1. form field의 title과 narrative  정보는 Note Model 인스턴스에서 capture 됩니다.
2. note의 title의 value 가 없으면 유저에게 alert 화면을 띄울 겁니다.
3. note 가 new일 경우 이 note를 cache에 add 할 겁니다. 이 note 가 이전에 저장 됐던 것이면 cache에 있는 해당 note를 update 할 겁니다.
4. 그리고 나서 Notes List 를 refresh 해서 보여줄 겁니다.

자 이 기능들을 구현해 볼까요?
save 버튼의 tap 핸들러를 구현하기 전에 Note data model을 수정해서 validation 부분을 구현하는데 좀 더 편하도록 해 봅시다. 우리가 할 것은 model의 title 필드의 validation 함수를 사용해서 message 프로퍼티를 override 할 겁니다. 이 기능은 이 필드가 invalid 할 경우 메세지를 띄우는 기능입니다.

Ext.regModel('Note', {
    idProperty: 'id',
    fields: [
        { name: 'id', type: 'int' },
        { name: 'date', type: 'date', dateFormat: 'c' },
        { name: 'title', type: 'string' },
        { name: 'narrative', type: 'string' }
    ],
    validations: [
        { type: 'presence', field: 'id' },
        { type: 'presence', field: 'title', message: 'Please enter a title for this note.' }
    ]
});

이 메세지는 우리가 Note Editor view 에서 note의 validation을 할 때 사용할 겁니다.
이제 save 버튼의 tap 핸들러를 구현해서 이 validation 이 어떻게 이뤄지는지 확인해 보겠습니다.

NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
    title: 'Edit Note',
    items: [
        {
            text: 'Home',
            ui: 'back',
            handler: function () {
                NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
            }
        },
        { xtype: 'spacer' },
        {
            text: 'Save',
            ui: 'action',
            handler: function () {

                var noteEditor = NotesApp.views.noteEditor;

                var currentNote = noteEditor.getRecord();
                // Update the note with the values in the form fields.
                noteEditor.updateRecord(currentNote);

                var errors = currentNote.validate();
                if (!errors.isValid()) {
                    currentNote.reject();
                    Ext.Msg.alert('Wait!', errors.getByField('title')[0].message, Ext.emptyFn);
                    return;
                }

                var notesList = NotesApp.views.notesList;
                var notesStore = notesList.getStore();

                if (notesStore.findRecord('id', currentNote.data.id) === null) {
                    notesStore.add(currentNote);
                } else {
                    currentNote.setDirty();
                }

                notesStore.sync();
  notesStore.sort([{ property: 'date', direction: 'DESC'}]);

                notesList.refresh();

                NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });

            }
        }
    ]
});

이 handler 함수에서 첫번째로 form panel의 getRecord() 메소드를 사용했습니다. 이 메소드는 form에 Note model이 로드되는 reference를 가질 수 있도록 해 줍니다. 그 다음에는 updateRecord() 메소드를 사용합니다. 이 메소드는 이 model reference로 폼 필드로부터 value들을 가져와서 전달해 줍니다.
validation dms Note data model에서 validate()를 call 함으로서 Errors 객체를 return 하도록 합니다. isValid()는 이 과정에서 에러가 있는지 없는지 알 수 있게 해 줍니다. 지난 시간에 했듯이 Note Editor 에서는 title 만이 not null입니다. 그래서 이 앱에서는 그 부분만 체크할 겁니다. 에러를 확인하기 위해서는 model의 validations config 옵션에서 정의했듯이 errors.getByField('title')[0] 메세지를 통해서 확인할 수 있습니다.

이 validation을 통화 하면 이 note를 cache에 add 해야 합니다. 대신 이 데이터가 이전에 있는지 확인하는 기능이 있어야 합니다.
아래 findRecord()메소드를 통해서 이 작업을 간단하게 해 주시구요.

var notesStore = notesList.getStore();
if (notesStore.findRecord('id', currentNote.data.id) === null) {
    notesStore.add(currentNote);
}


update 시키신 후에는 sync() 메소드를 이용해서 완전히 이 데이터를 저장하시면 됩니다. 오라클에서 commit; 기능하고 비슷합니다.
그 다음에 sort() 메소드를 사용해서 note를 날짜 순서로 정렬합니다. 그러면 notes list에 render 할 준비가 끝나는 겁니다.


notesList.refresh();

NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });

type을 보시면 slide와 right가 있을 겁니다. 이것은 화면 전환 할 때 된쪽에서 오른쪽으로 slide하게 화면이 바뀌도록 합니다.

이제 남은 것은 Home button에 handler를 구현하는 겁니다.
이 홈 버튼을 누르면 단순히 Notes List로 돌아가기만 하면 됩니다.

{
    text: 'Home',
    ui: 'back',
    handler: function () {
        NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });'s next
    }
}

한번 화면으로 테스트 해 보고 싶으신가요? 이제 실행 해 보시면 save하고 새 note를 create하는 것들이 다 가능할 겁니다.

***** What’s next
다음에 우리가 구현 할 것은 기존에 존재하는 notes를 수정하고 지우는 기능입니다.
이 기능은 다음 시간에 구현해 보겠습니다.

오늘까지 한 js 소스는 아래와 같습니다.

var App = new Ext.Application({
    name: 'NotesApp',
    useLoadMask: true,
    launch: function () {

        Ext.regModel('Note', {
            idProperty: 'id',
            fields: [
                { name: 'id', type: 'int' },
                { name: 'date', type: 'date', dateFormat: 'c' },
                { name: 'title', type: 'string' },
                { name: 'narrative', type: 'string' }
            ],
            validations: [
                { type: 'presence', field: 'id' },
                { type: 'presence', field: 'title', message: 'Please enter a title for this note.' }
            ]
        });

        Ext.regStore('NotesStore', {
            model: 'Note',
            sorters: [{
                property: 'date',
                direction: 'DESC'
            }],
            proxy: {
                type: 'localstorage',
                id: 'notes-app-store'
            }
        });

        NotesApp.views.noteEditorTopToolbar = new Ext.Toolbar({
            title: 'Edit Note',
            items: [
                {
                    text: 'Home',
                    ui: 'back',
                    handler: function () {
                        NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });
                    }
                },
                { xtype: 'spacer' },
                {
                    text: 'Save',
                    ui: 'action',
                    handler: function () {

                        var noteEditor = NotesApp.views.noteEditor;

                        var currentNote = noteEditor.getRecord();
                        // Update the note with the values in the form fields.
                        noteEditor.updateRecord(currentNote);

                        var errors = currentNote.validate();
                        if (!errors.isValid()) {
                            currentNote.reject();
                            Ext.Msg.alert('Wait!', errors.getByField('title')[0].message, Ext.emptyFn);
                            return;
                        }

                        var notesList = NotesApp.views.notesList;
                        var notesStore = notesList.getStore();

                        if (notesStore.findRecord('id', currentNote.data.id) === null) {
                            notesStore.add(currentNote);
                        } else {
                           currentNote.setDirty();
                        }

                        notesStore.sync();
                        notesStore.sort([{ property: 'date', direction: 'DESC'}]);

                        notesList.refresh();

                        NotesApp.views.viewport.setActiveItem('notesListContainer', { type: 'slide', direction: 'right' });

                    }
                }
            ]
        });

        NotesApp.views.noteEditorBottomToolbar = new Ext.Toolbar({
            dock: 'bottom',
            items: [
                { xtype: 'spacer' },
                {
                    iconCls: 'trash',
                    iconMask: true,
                    handler: function () {
                        // TODO: Delete current note.
                    }
                }
            ]
        });

        NotesApp.views.noteEditor = new Ext.form.FormPanel({
            id: 'noteEditor',
            items: [
                {
                    xtype: 'textfield',
                    name: 'title',
                    label: 'Title',
                    required: true
                },
                {
                    xtype: 'textareafield',
                    name: 'narrative',
                    label: 'Narrative'
                }
            ],
            dockedItems: [
                    NotesApp.views.noteEditorTopToolbar,
                    NotesApp.views.noteEditorBottomToolbar
                ]
        });

        NotesApp.views.notesList = new Ext.List({
            id: 'notesList',
            store: 'NotesStore',
            itemTpl: '
<div class="list-item-title">{title}</div>
' +
                '
<div class="list-item-narrative">{narrative}</div>
',
            onItemDisclosure: function (record) {
                // TODO: Render the selected note in the note editor.
            },
            listeners: {
                'render': function (thisComponent) {
                    thisComponent.getStore().load();
                }
            }
        });

        NotesApp.views.notesListToolbar = new Ext.Toolbar({
            id: 'notesListToolbar',
            title: 'My Notes',
            layout: 'hbox',
            items: [
                { xtype: 'spacer' },
                {
                    id: 'newNoteButton',
                    text: 'New',
                    ui: 'action',
                    handler: function () {

                        var now = new Date();
                        var noteId = now.getTime();
                        var note = Ext.ModelMgr.create(
                            { id: noteId, date: now, title: '', narrative: '' },
                            'Note'
                        );

                        NotesApp.views.noteEditor.load(note);
                        NotesApp.views.viewport.setActiveItem('noteEditor', { type: 'slide', direction: 'left' });
                    }
                }
            ]
        });

        NotesApp.views.notesListContainer = new Ext.Panel({
            id: 'notesListContainer',
            layout: 'fit',
            html: 'This is the notes list container',
            dockedItems: [NotesApp.views.notesListToolbar],
            items: [NotesApp.views.notesList]
        });

        NotesApp.views.viewport = new Ext.Panel({
            fullscreen: true,
            layout: 'card',
            cardAnimation: 'slide',
            items: [
                NotesApp.views.notesListContainer,
                NotesApp.views.noteEditor
            ]
        });
    }
});

이제 저도 Sencha Touch 에 대해 대충 감이 잡히네요.
다음시간에 첫번째 센차터치 앱 Notes 를 완료하겠습니다.
그리고 계속 하이브리드 모바일 앱을 위해 Corona SDK, HTML5, Sencha Touch, Phone Gap 등 관련 기술을 익히고 싶네요.

꾹~~ 꾹~~ 응원 부탁드려요... ~~~~~~~
반응형


반응형

Writing a Sencha Touch Application, Part 2

지난 시간에는 Sencha로 만드는 첫번째 앱인 My Notes 앱을 배웠습니다.
Notes List view를 말들고 있었습니다.
지난시간에 아래 화면까지 작업했습니다.



여기에 아래 mock-up 이미지처럼 툴바에 버튼을 달고 유저가 생성한 Notes들을 랜더링해서 보여주는 기능을 Ext.list를 이용해서 구현할 겁니다.



***** Creating a Data Model in Sencha Touch

우선 데이타 모델을 만들겠습니다. DB를 이용한다면 필드들을 만드는 겁니다.
리스트에 표시할 내용들에 대한 데이터 모델인데요 id,date,title,narrative 등이 있어야 합니다.
이 데이터 모델은 Ext.regModel() 메소드를 이용해서 만들겁니다.

Ext.regModel('Note', {
    idProperty: 'id',
    fields: [
        { name: 'id', type: 'int' },
        { name: 'date', type: 'date', dateFormat: 'c' },
        { name: 'title', type: 'string' },
        { name: 'narrative', type: 'string' }
    ],
    validations: [
        { type: 'presence', field: 'id' },
        { type: 'presence', field: 'title' }
    ]
});

데이타 모델과 관련한 API는 여기를 클릭해서 보시면 도움이 될 겁니다.
Sencha Touch의 이 데이터 모델관련 메소드에서는 내부적으로 validation을 지원합니다.
위에는 id와 title에 validations를 주었습니다. 데이터가 꼭 있어야 된다는 내용입니다. sql로 치면 not null 입니다.
이 validation이 어떻게 동작하는지에 대해서는 나중에 살펴보도록 하죠.
또한 associations 기능도 지원을 하는데요 우리가 만드는 앱에서는 사용하지는 않습니다.
아주 유용한 기능이니까 API를 꼭 참조하세요.

***** Configuring a Sencha Touch Data Store to use HTML5 local storage

이제 데이터를 Cacheg하는 기능이 필요합니다. Ext.regstore() 함수가 데이터 store를 생성하도록 할 겁니다.
아래 소스코드를 참조하세요.

Ext.regStore('NotesStore', {
    model: 'Note',
    sorters: [{
        property: 'date',
        direction: 'DESC'
    }],
    proxy: {
        type: 'localstorage',
        id: 'notes-app-localstore'
    }
});

Ext.regStore() 는 프레임 워크의 Store Manager 와 같이 store를 생성하고 register 합니다. 프레임워크의 다른 클래스들 처럼 여러분은 앱의 데이터 store를 lookup 하고 modify 하는데 이 Store Manager를 사용할 수 있습니다.
우리의 NotesStore의 모델 config 옵션은 Note model 입니다. 우리는 또한 sorters 옵션도 사용해서 날짜 역순으로 표시할 겁니다.
우리의 앱은 브라우저 세션을 이용해서 notes를 저장할 수 있어야 합니다. 그러기 위해서는 store의 proxy로 모델데이터를 로드하고 저장하는 일을 해야 합니다. 그래서 proxy config 옵션을 사용합니다. 이 옵션을 사용함으로서 proxy 는 Ext.data.LocalStorageProxy 클래스의 인스턴스가 됩니다. 이 클래스는 HTML5의 LocalStorage API를 사용해 사용자 브라우저에 모델 데이터를 저장하게 됩니다.

***** Creating a Sencha Touch list

데이터 모델과 store 가 준비 됐으면 이제 notes list 를 생성할 수 있습니다.

NotesApp.views.notesList = new Ext.List({
    id: 'notesList',
    store: 'NotesStore',
    itemTpl: '
<div class="list-item-title">{title}</div>
' +
        '
<div class="list-item-narrative">{narrative}</div>
'
});

복잡한 거는 없습니다. store config 옵션에 이름을 넣습니다. render 하기 위해 itemTpi config 옵션을 사용합니다. 그 안에 있는 태그(markup)은 list-item-title과 list-item-narrative 클래스가 정의 돼 있습니다. 이 클래스는 app.css 파일에서 사용할 겁니다.

.list-item-title
{
    float:left;
    width:100%;
    font-size:90%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.list-item-narrative
{
    float:left;
    width:100%;
    color:#666666;
    font-size:80%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.x-item-selected .list-item-title
{
    color:#ffffff;
}
.x-item-selected .list-item-narrative
{
    color:#ffffff;
}

이제 panel의 items config 옵션을 사용해서 container panel에 list를 추가해 보겠습니다.

NotesApp.views.notesListContainer = new Ext.Panel({
    id: 'notesListContainer',
    layout: 'fit',
    html: 'This is the notes list container',
    dockedItems: [NotesApp.views.notesListToolbar],
    items: [NotesApp.views.notesList]
});

시뮬레이터에서 확인하기 전에 dummy note를 집어 넣겠습니다. 그래야 브라우저나 디바이스로 테스트하면 이 dummy 내용이 나올 테니까요. 아래와 같이 data config 옵션을 넣어 보세요.

Ext.regStore('NotesStore', {
    model: 'Note',
    sorters: [{
        property: 'date',
        direction: 'DESC'
    }],
    proxy: {
        type: 'localstorage',
        id: 'notes-app-store'
    },
    // TODO: remove this data after testing.
    data: [
        { id: 1, date: new Date(), title: 'Test Note', narrative: 'This is simply a test note' }
    ]
});

에뮬레이터에서 Notes List 는 아래와 같이 보일 겁니다.



이제 우리의 Notes List view는 거의 완성 됐습니다. 툴바를 만들었고 Note List도 만들었습니다. 그리고 data model,store도 구현했구요 이러한 것들은 이 notes를 cache 하게 될 겁니다. 아직 안된게 두개가 있습니다. 다른 페이지로 넘어가도록 하는 버튼들인데요. 툴바에 있는 New 버튼하고 각각의 List item에 있는 disclosure 버튼입니다.



***** Adding buttons to a Sencha Touch toolbar

아래 소스코드는 New 버튼을 툴바에 add 하는 방법을 보여줍니다.
NotesApp.views.notesListToolbar = new Ext.Toolbar({
    id: 'notesListToolbar',
    title: 'My Notes',
    layout: 'hbox',
    items: [
        { xtype: 'spacer' },
        {
            id: 'newNoteButton',
            text: 'New',
            ui: 'action',
            handler: function () {
                // TODO: Create a blank note and make the note editor visible.
            }
        }
    ]
});

보시면 툴바에 New button을 달 수 있도록 hbox 레이아웃과 spacer를 넣었습니다. 그리고 handler function 도 넣었습니다. 여기에는 나중에 Note Editor view 와 관련한 기능이 추가 될 겁니다.

***** Implementing disclosure buttons in a Sencha Touch list

각 리스트에 달릴 disclosure 버튼을 다는것도 쉽습니다. 아래 코드에서 보듯이 onItemDisclosure function을 사용하시면 됩니다.

NotesApp.views.notesList = new Ext.List({
    id: 'notesList',
    store: 'NotesStore',
    itemTpl: '
<div class="list-item-title">{title}</div>
' +
        '
<div class="list-item-narrative">{narrative}</div>
',
    onItemDisclosure: function (record) {
        // TODO: Render the selected note in the note editor.
    }
});

리스트 아이템에 tap event에 대한 listener를 달기 위해 onItemDisclsure를 override 하고 있습니다. 이 리스너가 하는 일은 유저가 리스트를 탭하면 이를 감지해서 Note Editor view에 알려주는 역할을 하게 될 겁니다.
이 기능은 Note Editor를 만들고 나서 나중에 구현하겠습니다.

***** Where are we?

여기까지 무사히 마쳤다면 아래와 같은 화면을 부실 수 있을 겁니다.



이제 어플리케이션의 main view를 완성했습니다. 두개의 이벤트 핸들러를 구현하는 부분은 남았지만 비쥬얼한 부분은 다 완성됐습니다.

이제 다음시간에는 Note Editor를 만들어 보겠습니다.



아래는 지금까지 한 소스 입니다.

var App = new Ext.Application({
    name: 'NotesApp',
    useLoadMask: true,
    launch: function () {

        Ext.regModel('Note', {
            idProperty: 'id',
            fields: [
                { name: 'id', type: 'int' },
                { name: 'date', type: 'date', dateFormat: 'c' },
                { name: 'title', type: 'string' },
                { name: 'narrative', type: 'string' }
            ],
            validations: [
                { type: 'presence', field: 'id' },
                { type: 'presence', field: 'title' }
            ]
        });

        Ext.regStore('NotesStore', {
            model: 'Note',
            sorters: [{
                property: 'date',
                direction: 'DESC'
            }],
            proxy: {
                type: 'localstorage',
                id: 'notes-app-localstore'
            },
            // TODO: remove this data after testing.
            data: [
                { id: 1, date: new Date(), title: 'Test Note', narrative: 'This is simply a test note' }
            ]
        });

        NotesApp.views.notesList = new Ext.List({
            id: 'notesList',
            store: 'NotesStore',
            itemTpl: '
<div class="list-item-title">{title}</div>
' +
                '
<div class="list-item-narrative">{narrative}</div>
',
            onItemDisclosure: function (record) {
                // TODO: Render the selected note in the note editor.
            }
        });

        NotesApp.views.notesListToolbar = new Ext.Toolbar({
            id: 'notesListToolbar',
            title: 'My Notes',
            layout: 'hbox',
            items: [
                { xtype: 'spacer' },
                {
                    id: 'newNoteButton',
                    text: 'New',
                    ui: 'action',
                    handler: function () {
                        // TODO: Create a blank note and make the note editor visible.
                    }
                }
            ]
        });

        NotesApp.views.notesListContainer = new Ext.Panel({
            id: 'notesListContainer',
            layout: 'fit',
            html: 'This is the notes list container',
            dockedItems: [NotesApp.views.notesListToolbar],
            items: [NotesApp.views.notesList]
        });

        NotesApp.views.viewport = new Ext.Panel({
            fullscreen: true,
            layout: 'card',
            cardAnimation: 'slide',
            items: [NotesApp.views.notesListContainer]
        });
    }
});

앞으로 두 번만 더 다루면 센차터치로 만드는 첫 번째 앱이 완성됩니다.
정말 기대가 되는데요.
다음 시간에 또 뵙구요... 꾹 꾹 추천 한방 눌러 주세요.... ~~~~
반응형


반응형
안녕하세요.
드디어 Sencha Touch로 앱을 만들기로 했습니다.
이번주 들어서 갑자기 HTML5로 게임 만들기하고 Sencha Touch 앱하고 본격적으로 공부하고 싶어지더라구요.

오늘은 첫번째 모바일 웹으로 간단한 Note 기능을 만들겠습니다.

이 앱의 기능은 유저가 Notes를 받아서 이것을 디바이스에 저장하고 앱을 시작하면 그 Notes들을 볼 수 있도록 하겠습니다.

이 앱을 만들기 위해서는 아래 작업들을 해야 합니다.
- Scencha Touch Application의 block들을 만든다.
- 리스트 뷰를 이용해 정보를 렌더링 한다.
- form elements들을 이용해서 정보를 editing 한다.
- 브라우저 세션을 이용해 클라이언트 사이드 data persistence를 구현한다.
- multi-view 어플리케이션으로 여러 화면을 navigation할 수 있도록 한다.


완성된 화면인데요.
New를 누르면 간단한 Note를 할 수 있는 화면이 나오고 위 화면은 앱을 켰을 때 그 Note들이 출력되도록 하는 List 화면입니다.

***** 어플리케이션 개요
- note를 생성할 수 도록 한다.
- 현재의 note를 수정할 수 있도록 한다.
- note를 delete 할 수 있도록 한다.
- 브라우저 세션을 이용해 어플리케이션이 동작하면서 device에 note를 저장할 수 있도록 한다.

이러한 기능들을 염두에 두고 비쥬얼한 디자인을 한번 보겠습니다.

***** 메인 뷰 디자인하기

우리가 첫번째로 만들어야 할 부분은 note를 수정할 수 있는 화면입니다.
이 화면은 form 을 이용해 만들겁니다. 앞으로 이 화면은 Note Editor라고 부르도록 하겠습니다.
대략 아래와 같이 될 겁니다.


이 Note Editor를 Sencha Touch components를 이용해서 어떻게 구현할까요?
아래 그림을 보세요.



또한 우리는 기존에 있던 note들을 리스트로 랜더링해서 보여주는 화면이 필요합니다.
이 화면이 아마 이 애플리케이션의 메인 화면이 될 겁니다.
또한 이 화면은 Note Editor와 연결 돼 있어야 합니다. 아래 대략적인 그림이 있습니다.



그리고 아래는 우리가 사용할 Sencha Touch components들 입니다.



이 두 화면 이외에 보이지는 않지만 이 앱에 꼭 필요한 component가 더 있습니다.
이 컴포넌트는 이 앱의 viewport와 같은 기능을 할거고 랜더링이나 Notes List와 Note Editor를 전환하는 부분을 담당하게 될 겁니다.
이 기능을 구현하기 위해 Notes List와 Note Editor가 layout's cards가 되는 Panel을 구성할 겁니다.



***** Sencha Touch application 의 block들 만들기

우리는 index.html, app.css, app.js 이렇게 세개의 파일을 만들겁니다.
index.html은 앱을 launch 하기 위한 파일입니다. 이 파일에는 기본 Sencha Touch framework와 우리가 사용할 app.js, app.js 파일들에 대한 정보가 들어 있습니다.

<!DOCTYPE html>
<html>
<head>
    <title>Getting Started</title>

<script src="sencha-touch-debug.js" type="text/javascript"></script>
<link href="sencha-touch.css" rel="stylesheet" type="text/css" />
<link href="app.css" rel="stylesheet" type="text/css" />
<script src="app.js" type="text/javascript"></script>
</head>
<body></body>
</html>



app.js와 app.css는 이 앱에서 사용할 자바스크립트와 css 파일입니다.

app.js에서 우리가 할 최초의 작업은 어플리케이션을 instantiate 하는 작업입니다.
var App = new Ext.Application({
    name : 'NotesApp',
    useLoadMask : true,
    launch : function () {
    }
})


Ext.Application 클래스는 Sencha Touch application 임을 말합니다.
자세한 사항은 http://docs.sencha.com/touch/1-1/#!/api/Ext.Application 에 있습니다.
새 application을 instantiate 하게 되면 자동적으로 전역번수 NotesApp이 생성되고 아래의 namespaces들이 만들어 집니다.
- NotesApp
- NotesApp.views
- NotesApp.models
- NotesApp.controllers
- NotesApp.stores

그리고 launch() 함수는 오직 한번만 실행됩니다. 여기에는 우리가 생성할 application의 view가 들어가게 됩니다.
launch: function () {

    NotesApp.views.viewport = new Ext.Panel({
        fullscreen: true,
        html:'This is the viewport'
    });
}


우리 앱의 viewport는 Ext.Panel 입니다. 이 panel에는 Notes List와 Note Editor가 그려지게 될 겁니다.
여기서 fullscreen config 옵션을 true로 하게 되면 이 panel이 브라우저의 모든 공간을 활용하게 됩니다.
여기에는 monitorOrientation config도 true로 할 수 있습니다. 이렇게 되면 모바일의 경우 orientation이 바뀌게 되면 화면도 바뀌게 됩니다.

여기까지 작업한 내용을 device나 simulator에서 돌리시면 아래와 같은 화면을 보실 수 있을겁니다.



***** Creating the Notes List container
Notes List는 앱이 실행될 때 유저에게 보여질 화면입니다. 아래 그림에서 보듯이 여기에는 툴바와 리스트가 있게 될 겁니다.
한번 구현해 보겠습니다.

첫번째로 우리는 툴바와 리스트를 display 하게 될 panel을 만들어야 합니다.



우리는 이 panel을 notesListContainer라고 부르겠습니다.
NotesApp.views.notesListContainer = new Ext.Panel({
    id : 'notesListContainer',
    layout : 'fit',
    html: 'This is the notes list container'
});


여기에 툴바와 리스트를 추가하기 전에 이 viewport안에서 rendering 작업을 해야 합니다.
var App = new Ext.Application({
    name: 'NotesApp',
    useLoadMask: true,
    launch: function () {

        NotesApp.views.notesListContainer = new Ext.Panel({
            id : 'notesListContainer',
            layout : 'fit',
            html: 'This is the notes list container'
        });

        NotesApp.views.viewport = new Ext.Panel({
            fullscreen : true,
            layout : 'card',
            cardAnimation : 'slide',
            items: [NotesApp.views.notesListContainer]
        });
    }
})


여기에 왜 card 레이아웃을 사용했을 까요? 왜냐하면 Notes List container와 Note Editor 들은 cards 들이기 때문입니다.
대부분의 모바일 앱이 그렇듯이 이 cards 들은 slide 애니메이션을 사용해서 display 될 겁니다.

이 소스를 device나 simulator에서 체크해 보시면 아래와 같은 화면을 보실 수 있을 겁니다.



뭐가 잘 못 된 걸까요? 툴바와 notes list가 안 보이네요. 이것들은 아래에서 마저 작업 하겠습니다.

***** Adding a Sencha Touch toolbar to a panel

아래와 같이 툴바를 정의할 수 있습니다. 여기에 버튼이 들어가야 되는데요 이건 나중에 작업하겠습니다.
NotesApp.views.notesListToolbar = new Ext.Toolbar({
    id: 'notesListToolbar',
    title: 'My Notes'
});


디바이스나 시뮬레이터로 아래처럼 화면이 출력되는지 확인해 보세요.



***** 다음 작업
오늘은 여기서 마치도록 하고요 다음 글에서는 방금 만든 notes list를 view에 추가하겠습니다. 그리고 note를 만들고 수정하는 기능들도 작업하겠습니다.

지금까지의 소스는 아래와 같습니다.

var App = new Ext.Application({
    name: 'NotesApp',
    useLoadMask: true,
    launch: function () {

        NotesApp.views.notesListToolbar = new Ext.Toolbar({
            id: 'notesListToolbar',
            title: 'My Notes'
        });

        NotesApp.views.notesListContainer = new Ext.Panel({
            id: 'notesListContainer',
            layout: 'fit',
            html: 'This is the notes list container',
            dockedItems: [NotesApp.views.notesListToolbar]
        });

        NotesApp.views.viewport = new Ext.Panel({
            fullscreen: true,
            layout: 'card',
            cardAnimation: 'slide',
            items: [NotesApp.views.notesListContainer]
        });
    }
})

지금까지의 소스는 아래 파일을 다운받아서 보시면 됩니다.



추천 추천 부탁드려요. ~~~~~~~ ~~~~~~~
반응형


반응형
어제 SGF(Simple Game Framework)를 이용해서 HTML5 로 PingPong Game 을 만들기 시작했습니다.

index.html 과 styles.css 파일을 만들고 js폴더 밑에 SGF 를 넣었습니다.

index.html 에서는 data-screen="screen", data-game="Pong" 이 두가지 태그를 유심히 보실 필요가 있습니다.
data-screen 으로는 div id 가 screen인 것을 사용한다는 의미입니다.
이 부분이 없으면 해당 html 의 body 부분을 screen으로 사용할 겁니다.
그리고 data-game 을 Pong으로 한 것은 Pong이라는 폴더 밑에 있는 game관련 소스를 참고할 것이라는 의미입니다.
앞으로 만들 PingPong 게임의 objects 와 behavior 관련 소스코드들은 바로 이 폴더 밑에 위치할 겁니다.

일단 SGF로 게임을 만드려면 main.js 를 만들어야 합니다.
아래 코드를 Pong 폴더 안에 main.js 파일로 저장해 주세요.

// Import required classes
var Game = SGF.require("Game");
var Input = SGF.require("Input");
var Rectangle = SGF.require("Rectangle");
var Label = SGF.require("Label");
// Get a reference to our Game instance
var myGame = Game.getInstance();
// Get a reference to our game's Input instance
var myInput = myGame.input;
var game_height = 400;
var game_width = 400;
myGame.getScript("Paddle.js", function(){
// left paddle
myGame.leftPaddle = new Paddle();
myGame.leftPaddle.setPosition(0, 150);
myGame.addComponent(myGame.leftPaddle);
});

main.js에서는 처음에 Game 을 require 합니다.
그리고 Input,Rectangle,Lable 변수에 SGF의 해당 메소드들을 대입했습니다.
다음 myGame 변수에는 Game의 getInstance() 메소드를 대입했습니다.


SGF의 API를 보면 위와 같이 getInstance 에 대한 설명을 보실 수 있습니다.
항상 main.js의 첫번째 파트에 이 getInstance메소드가 오게 된다고 나와 있네요.

그리고 이 인스턴스에 input을 사용하기 위해 myInput 이라는 변수에 담습니다.
다음줄엔 game_height와 game_width 변수에 400을 대입합니다.

그리고 myGame 인스턴스에 getScript 메소드를 이용해서 Paddle.js를 사용해서 Paddle을 화면에 그려 넣습니다.
여기선 일단 leftPaddle 을 만들고 그 위치를 정하고 컴포넌트에 add를 했습니다.

아직 Paddle.js를 만들지는 않았습니다. main.js 까지 완성하면 아래 화면을 보실 수 있습니다.

어제 만들었던 하얀 바탕이 까맣게 변했죠?
Paddle을 만들었지만 아직 Paddle.js를 완성하지 않았기 때문에 화면에는 나타나지 않습니다.

아래 소스는 paddle.js 입니다.
// Paddle.js
var Paddle = Class.create(Rectangle, {
initialize: function($super){
$super();
this.height = 100;
this.width = 20;
this.color = "0011FF";
this.isPlayerOne = true;
},
setPosition: function(x, y){
this.x = x;
this.y = y;
},
getPosition: function(){
return {
'x': this.x,
'y': this.y
}
},
setIsPlayerOne: function(bool){
this.isPlayerOne = bool;
},
checkInput: function(){
if (this.isPlayerOne == false) {
if (myInput.isKeyDown(Input.KEY_UP)) {
if (this.y > 0) {
this.y = this.y - 10;
}
}
else
if (myInput.isKeyDown(Input.KEY_DOWN)) {
// x,y are taken from the left corner
if (this.y < game_height - this.height)
this.y = this.y + 10;
}
}
else {
if (myInput.isKeyDown(65)) { // 'A'
if (this.y > 0) {
this.y = this.y - 10;
}
}
else
if (myInput.isKeyDown(90)) { // 'Z'
// x,y are taken from the left corner
if (this.y < game_height - this.height)
this.y = this.y + 10;
}
}
},
update: function(){
this.checkInput();
}
});

처음 Paddle을 생성합니다. Rectangle 을 이용해서 생성했는데요. height는 100 width 는 20이고 color 는 0011FF 로 파란색 입ㅂ니다.
그리고 이 Paddle의 isPlayerOne 은 true 입니다.

setPosition,getPosition,setIsPlayerOne  함수들은 나중에 보겠습니다.

우선 checkInput 함수를 보겠습니다.

맨 처음 isPlayerOne을 체크합니다. 이 탁구게임은 2인용이기 때문에 왼쪽 Player 인지 오른쪽 Player 인지를 알아야 합니다.
우선 leftPaddle 에 inPlayerOne 을 true로 했다는 것을 기억하세요.

맨 처음 if 문은 isPlayerOne 이 false 인 경우에 실행하는 것이니까 오른쪽 paddle에 해당 되는 겁니다. 아직 이 오른쪽 패들은 만들지 않았으니까요 저 아래 else를 보겠습니다.
else 부분 (왼쪽 paddle)에서는 key 번호 65번이 눌려졌는지를 체크합니다.
이 65번은 키보드의 A 버튼을 말합니다.
이 키가 눌려졌으면 y 좌표가 10씩 줄어듭니다.
그리고 90(Z) 가 눌려졌으면 y 좌표가 10씩 늘어납니다.

이제 index.html을 refresh 하시면 위와 같은 화면을 보실 수 있습니다.
a,z 키를 눌러 보세요. 이 패들이 아래 위로 움직일 겁니다.

그럼 이제 right paddle 도 넣어 볼까요?

아래 코드를 left paddle 아래에 추가하세요.
 myGame.rightPaddle = new Paddle();
  myGame.rightPaddle.setPosition(game_width - myGame.rightPaddle.width, 150);
  myGame.rightPaddle.setIsPlayerOne(false);
  myGame.addComponent(myGame.rightPaddle);

leftPaddle이랑 다른 부분은 setIsPlayerOne을 false로 한 것입니다.
left가 아니라 right란 것을 알리기 위해서죠.


오른쪽 paddle은 키보드의 위 아래 화살표를 누르면 위 아래로 움직이게 됩니다.
이 내용은 Paddle.js 에서 보셨죠?

이제 두개의 패들을 다 만들었고 유저가 이 객체들을 움직일 수 있도록 했습니다.

지금까지 한 소스는 아래 압축파일에 있습니다.


다음시간에는 이어서 공을 만들고 Score를 만들어 보겠습니다.

꾹~~~ 추천 추천 부탁 드려요 ~~~~~ ~~~~~~~~
반응형


반응형
드디어 HTML5로 게임 만들기를 시작하려고 합니다.
그동안 사전 정지작업의 일환으로 HTML5,CSS3,Javascript 와 관련해서 살펴봤습니다.
HTML5로 게임만들기를 거쳐서 HTML5 모바일 게임을 만드는게 제 개인적인 목표입니다.

개인적으로 2년여 전 부터 모바일 앱 프로그래밍을 시작했고 작년 중순부터 Corona SDK로 크로스 플랫폼 모바일 애플리케이션을 개발하고 있습니다.

Corona SDK 이외에 HTML5 를 통한 앱 개발도 장차 크로스플랫폼 모바일 프로그래밍으로 아주 전망이 있을 것 같아 이 공부를 시작했습니다.

HTML5로 게임만들기 이외에 센차 터치나 phone Gap (폰갭)을 통한 웹 앱 개발도 제 주요 관심 분야 중 하나 입니다.
조만간 이 공부도 본격적으로 하게 되면 posting 하도록 하겠습니다.

이제 HTML5로 게임만들기를 시작해 보죠.

처음 시작할 게임은 탁구(Ping Pong)게임 입니다.

완성된 화면은 아래와 같을겁니다.


사각형 게임 화면에 빨간 정사각형(공) 이 있고 두개의 파란 Paddle 이 있습니다.
그리고 상단에는 게임 제목과 점수가 표시 됩니다.
공은 벽에 튀면서 움직이고 이 두개의 paddle로 공을 막아내는 게임입니다.

이 게임은 프레임워크로 SGF(Simple Game Framework)를 사용할 겁니다.
이 프레임워크에 대한 설명은 http://sgfjs.org/ 에 가시면 보실 수 있습니다.

이 프레임워크의 소스와 API 는 https://github.com/TooTallNate/Simple-Game-Framework 에 가시면 다운 받으실 수 있습니다.
다운받으신 후 압축을 푸시고 doc폴더의 index.html 을 실행하시면 아래와 같은 API화면을 보실 수 있습니다.


이 SGF 에 대해서는 따로 다루지는 않겠습니다. 탁구게임을 진행하면서 그때그때 필요함 부분을 설명하겠습니다.
궁금하신분은 이 API를 참조하세요.

우선 오늘은 html 파일과 css 파일을 만들어 보겠습니다.

아래와 같이 index.html을 만들어 보세요.
<!DOCTYPE HTML>
<html>
    <head>
        <title>Pong</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <!-- For IE. Force the browser to the most current rendering mode. -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge" >

        <!-- A few basic styles. These are NOT mandatory for SGF... -->
        <link href="styles.css" type="text/css" rel="stylesheet" />
       
        <script type="text/javascript" src="js/SGF.js"
            data-debug="true"
            data-prototype="lib/prototype.js"
            data-swfobject="lib/swfobject.js"
            data-screen="screen"
            data-game="Pong"></script>
    </head>
    <body>
      <div id="screen"></div>
    </body>
</html>

위 소스를 보시면 처음 <!DOCTYPE HTML> 는 HTML5를 사용하겠다는 의미입니다.
브라우저에게 HTML5를 사용하겠다고 알려주는 것이죠.
그리고 밑으로 내려와서 <link href 태그는 외부 css를 사용하겠다는 겁니다.
그리고 script 태그를 보면 js/SGF.js 를 불러왔습니다.

이 JavaScript는 SGF 프레임워크를 사용할 수 있도록 서비스를 제공해 줍니다.
이 게임에서 사용될 SGF 소스(js 폴더 밑에 있는 있어야 함)는 아래 파일을 다운 받으세요.


이 압축파일을 index.html이 있는 폴더에 압축을 푸시면 됩니다.

이제 css 파일을 만들어 보겠습니다.
이 css 파일 이름은 styles.css가 되야 하겠죠? index.html 에서 그 파일에 링크를 걸었으니까요.

body {
    margin:0 0 0 0;
    width:100%;
    height:100%;
    text-align:center;
}

#screen {
    width:400px;
    height:400px;
    border:Solid 1px #000000;
    margin:0 auto;
}

내용은 별다른게 없습니다. screen 크기가 400X400 픽셀 크기로 지정한게 답니다.

이 index.html 을 브라우저에서 실행하면 아래와 같은 화면을 보실 수 있습니다.

그냥 검은 테두리가 있는 흰 바탕화면 뿐입니다.
저 검은 테두리는 css에서 border:Solid 1px #000000; 를 선언했기 때문에 나타난 겁니다.

자 오늘은 여기까지 하구요.

내일부터 여기에 paddle, ball, score 같은 objects 들을 배치하고 이 objects 들을 control 해 보겠습니다.

추천 추천... 꾹 ~~ 눌러 주세요. ~~~~~
반응형

HTML5 CSS Text wrapping (Google)

2012. 2. 4. 22:06 | Posted by 솔웅


반응형
오늘은 Text Wrapping 에 대해 살펴 보겠습니다.
이 기능은 Internet Explore 를 제외한 모든 브라우저에서 작동 합니다.

단 아래 슬라이드 바는 Firefox에서는 숫자를 넣는 Textbox로 나옵니다.
슬라이드 바 기능을 Firefox에서 지원을 안하나 봅니다.

You can ellipse below texts with control slide bar.
If you have Firefox browser text box will be displayed instead of the slide bar then just input any number between 1~100 then enter to ellipse those texts.
This function is working on all browsers except Internet Explore.


CSS

Text wrapping

div {
  text-overflow: ellipsis;
}
A long cold winter delayed the blossoming of the millions of cherry, apricot, peach, and prune plum trees covering hundreds of square miles of the Valley floor. Then, unlike many years, the rains that followed were light and too early to knock the blossoms from their branches.
A long cold winter delayed the blossoming of the millions of cherry, apricot, peach, and prune plum trees covering hundreds of square miles of the Valley floor. Then, unlike many years, the rains that followed were light and too early to knock the blossoms from their branches.
A long cold winter delayed the blossoming of the millions of cherry, apricot, peach, and prune plum trees covering hundreds of square miles of the Valley floor. Then, unlike many years, the rains that followed were light and too early to knock the blossoms from their branches.

Play with the slider on this pages!


Google Chrome 16.0.912.75 m  - Working well (O)
Internet Explorer 9.0.8.112        - Not working (X)
Opera 11.60                            - Working well (O)
Safari 5.1.2                             - Working well (O)
FireFox 9.0.1                          - Working well (O) -not slide bar-

You can download source code file below.
아래 원본 파일을 다운 받아서 실행해 보세요.


반응형

HTML5 CSS3 Flexible Box Model

2012. 2. 2. 21:08 | Posted by 솔웅


반응형
Let's study for webkit-box of CSS3.
You can change orientation of boxes below. just select 'horizontal' or 'vertical'  of webkit-box-orient in select menu . And you can change align of the boxes also.

오늘은 CSS3의 Flexible Box 와 관련해서 알아보겠습니다.
여기를 클릭하시면 이전에 정리해 뒀던 글도 보실 수있습니다.

** display:-webkit-inline-box;    // block가 아닌 inline box

** -webkit-box-orient : 정렬 ( box ) , 기본은 horizontal
block-axis Elements are oriented along the box's axis.
horizontal Elements are oriented horizontally.
inline-axis Elements are oriented along the inline axis.
vertical Elements are oriented vertically.

** -webkit-box-flex사용
  display:-webkit-box가 적용된 하위 노드들에
  box-flex를 이용해서 크기 설정가능. ( 비율 )

** -webkit-box-pack 사용  : 가로 정렬 처리.
  start|end|center|justify; 

** -webkit-box-align 사용  : 세로 정렬 처리.
  start|end|center|justify; 


CSS

Flexible Box Model

.box {
  display: -webkit-box;
  -webkit-box-orient: ;
}
.box .one, .box .two {
  -webkit-box-flex: 1;
}
.box .three {
  -webkit-box-flex: 3;
}
Box one
Box two
Box three
CSS

Flexible Box Model

.box {
    display: -webkit-box;
    -webkit-box-pack: ;
    -webkit-box-align: ;
  }

Google Chrome 16.0.912.75 m  - Working well (O)
Internet Explorer 9.0.8.112        - Not working (X)
Opera 11.60                            - Not working (X)
Safari 5.1.2                             - Working well (O)
FireFox 9.0.1                          - Working well (O) except -webkit-box-pack

이 기능은 익스플로어랑 오페라에서는 안 되네요.
그리고 fireFox에서는 webkit-box-pack 기능이 안 되구요.

You can download source code file below.



반응형

3D 관련 툴 블랜더(blender)

2012. 2. 1. 22:05 | Posted by 솔웅


반응형
HTML5로 게임만들기 공부하다 보니까 여러 툴을 먼저 접하게 되네요.

3D관련 무료 툴로 블랜더(blender)를 알게 됐습니다.
사실 이거 공부할 시간까지는 없는데...
너무 공부하고 싶기도 하고....

요즘 모바일 앱 게임 중 3D게임을 아주 재밌게 하고 있거든요.

앞으로 이런 멋있는 3D 게임을 만드는 날도 오겠죠?
이렇게 막연히 바랬던 일들을 계속 간직하고 있으면 결국엔 이뤄지더라구요. :)

블렌더 공식 홈페이지는 아래 링크를 따라 가면 됩니다.
http://www.blender.org/


Download 메뉴로 들어가면 보실 수 있습니다.
두가지 종류가 있는데요. 하나는 인스톨 버전이고 나머지 하나는 이클립스 처럼 패키지 버전입니다 (그냥 압축 풀어서 사용하면 됩니다.).

아래 링크로 가시면 한국어로 된 Tutorial 을 보실 수 있습니다.
http://wiki.blender.org/index.php/KO/Main_Page

사용자들이 자발적으로 번역하고 작성하는 위키피디아 백과사전처럼 운영되는것 같습니다.
여러분들이 한국어 튜토리얼을 열심히 번역해 주고 계신것 같습니다.


블랜더를 실행한 화면입니다.

사용법은 님이 유튜브에 동영상강좌를 올려주셔서 아주 쉽게 배울수 있습니다. (한국어예요).
http://www.youtube.com/watch?v=TEkmwrfCEzA&feature=related

아래 블렌더로 만든 3D 영화예요.
얼마전에 글 올린 불가리아의 두 친구들이 보면 아주 좋아하지 않을까 싶네요.




이 영화를 보니까 저도 3D 영화, 3D 게임을 모바일 앱으로 만들고 싶어집니다.

반응형

HTML5, JavaScript 관련 툴들 소개

2012. 1. 31. 08:36 | Posted by 솔웅


반응형
오늘 자바스크립트 관련 몇개 소개할 께요.

1. Trial Tool (JavaScript Test Tool)

써핑하다가 우연히 찾은건데요.

Tutorial 동영상을 보니까 완전 인도발음 영어를 사용하더라구요.
Parashuram Narasimhan 이라는 친구인데요.

블로그에 가 봤더니 이 Trial tool 말고도 어렵게 개발한 여러 툴들을 공유하고 있습니다.

온라인상으로는 아래 링크를 따라가 보시면 테스트 할 수 있습니다.

nparashuram.com/trialtool/index.html



왼쪽에 샘플을 하나 클릭하면 오른쪽에 JavaScript 소스가 뜹니다.
그리고 오른쪽 위의 Run을 누르면 그 결과값이 아래에 뜹니다. 에러가 있으면 에러 메세지가 뜨구요.

전체 소스 파일은 여기에서 받으실 수 있습니다.

유튜브에 있는 소개 동영상을 좀 볼까요?




이 친구의 홈페이지에 가시면 이 것 외에 여러 다른 툴들도 보실 수 있습니다.
http://nparashuram.com

2. svg-edit

이 툴은 HTML5의 도형 그리는 코드를 손쉽게 만들 수 있도록 도와주는 툴입니다.


이렇게 자기가 그리고 싶은 도형을 그린 다음에 왼쪽 위에 있는 <SVG> 버튼을 클릭합니다.



그러면 이렇게 HTML5 코드로 변환해 줍니다.
아래 주소로 가시면 직접 해 볼 수 있습니다.
http://svg-edit.googlecode.com/svn/branches/2.5.1/editor/svg-editor.html

아래 주소로 가시면 직접 다운 받아서 사용할 수도 있습니다.
http://code.google.com/p/svg-edit/downloads/list

구글에서 서비스하는 것 같은데 제 경우엔 구글 크롬에서는 잘 실행이 안되고 화이어폭스에서 잘 실행이 되더라구요.

3.  Raphaël—JavaScript Library

이 건 자바스크립트 라이브러리인데요. 아래와 같이 간단하게 API를 익혀서 화려한 이미지나 도형을 구현할 수 있도록 도와주는 라이브러리 입니다.


아래 링크로 가시면 라이브러리도 다운 받으실 수 있구요. 사용법도 배우실 수 있습니다.
http://raphaeljs.com/

반응형