자바스크립트 코드를 작성하다 보면 객체 내에서 일부 데이터만 필요하고

나머지 데이터는 필요없는 상황이 많다.

이때 간단하게 오브젝트 내에서 필요한 데이터만 추출해 보자.


1. 배열 (Array)


let data = ["crong", "honux", "jk", "jinny"];
let [jisu,,jung] = data;
console.log(jisu, jung);

data의 배열 내에 4개의 이름이 들어가 있다.

jisu는 data의 0번째, jung은 data의 2번째 값을 받고있다.

1번째 값은 ,,으로 건너 뛰었다.

로그를 출력하면 crong, jk가 출력되는것을 확인할 수 있다.


2. 오브젝트 (Object)


let obj = {
name : "crong",
address : "Korea",
age : 10
};

오브젝트 내에서 원하는 데이터를 뽑고싶다면

let {name, age} = obj;

이렇게 추출하면 된다.

name은 crong

age는 10이 들어있다.


만약 변수의 이름을 다르게 하고 싶다면

let {name:myName, age:myAge } = obj;

myName에 name의 값이 들어가게 되고

myAge에 age의 값이 들어가게 된다.


myName, myAge 변수를 사용하면 된다.


3. JSON 파싱


let news = [
{
"title" : "sbs",
"imgurl" : "http://static.naver.net/1",
"newslist" : [
"[가보니] 가상 경주도 즐기고, 내 손으로 자동차도 만들고",
"'갤럭시S8' 출시? '갤노트7' 처리 계획부터 밝혀야"
]
},
{
"title" : "mbc",
"imgurl" : "http://static.naver.net/2",
"newslist" : [
"Lerem ipsum dolor sit amet",
"ipsum dolor sit amet"
]
}
];

JSON 내의 데이터중 필요한 데이터만 추출해보자.


let [,mbc] = news;

JSON 배열 내의 데이터중 1번째 데이터를 mbc에 할당한다.

let {title, imgurl} = mbc;

title에 mbc의 title값이 담기고 imgurl에 mbc의 imgurl값이 담긴다.

console.log(title, imgurl);

출력하면 mbc와 url주소가 출력된다.


Destructuring을 이용해서

let [, {title, imgurl} ] = news;

바로 뽑아낼 수도 있다.


4. Event 객체 파싱


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<ul>
<div> "Lerem ipsum dolor sit amet",
"ipsum dolor sit amet"</div>
</ul>
</body>
</html>

HTML에 div 속성으로 다음과 같은 데이터를 삽입한다.


document.querySelector("div").addEventListener("click", function({type,target}){
console.log(type, target.tagName);
});

argument로 객체 전체가 넘어오게 되는데

상당수가 필요없는 데이터 일때가 많다.

type과 target의 데이터만 필요할 경우 function의 파라미터에 { type, target }을 이용해서 해당 데이터만 추출한다.

console.log 를 통해 확인하면 해당 데이터만 전달 받는것을 확인할 수 있다.

배열 안의 모든 값을 확인할때

제일 기본적인 방법은


let data = [1, 2, 3 ];
for(let i = 0; i < data.length; i++){
console.log(i);
}

이렇게 순회할 수 있지만 다음과 같이 forEach에 callback을 이용해서도 가능하다.


let data = [1, 2, 3 ];
data.forEach( function(value){
console.log("valueis", value);
});

상황에 맞춰 편하게 쓰면 될것같다.


let data = [1, 2, 3 ];
for( let value of data ){
console.log( value);
}

for of를 써도 가능


let data = [1, 2, 3 ];
for( let idx in data ){
console.log( data[idx]);
}

for in 같은 경우 상위 객체의 함수가 출력될수 있기 때문에 for i in 은 조심해서 사용하도록 한다.

기존에 ECMA6기반으로 코드를 작성, 프로젝트를 압축 (concat) 하고 난독화 (uglify) 등을 진행할때 gulp를 사용했었습니다.

클래스의 확장, 라이브러리간 의존성이 생겨 task를 나누어서 관리했었는데

다른 클래스를 참조할때 전역객체를 통해 클래스를 참조하다 보니 window.console에 노출되는등 좋지 않은점이 많이 발견되었습니다.

프로젝트가 커질수록 이렇게 관리하는건 시간이 오래 걸린다 판단되어 Webpack으로 전환했습니다.


하지만 인터넷등을 보니 WebPack 개념 자체에 대해서는 설명이 잘 되어있지만

import.. export를 실질적으로 어떻게 하는지 보여주는 부분은 없어서 난감했었는데 해당 부분에 대해 정리해 놨습니다.


webpack의 개념과 모듈, import, export에 관한 개념은 다른 글에 많이 나와있기 때문에

여기서는 실질적인 구성, 실행을 하는것이 목적입니다.


- 목표 - 

1. main 진입점에서 다른 js파일을 import한뒤 import한 클래스의 함수를 이용해서 로그를 찍어보자. 

2. js파일을 한개로 압축한뒤 minify 시킨다.


현재 사용하는 개발도구는 IntelliJ 입니다. Webstorm은 같은 Jetbrain에서 만든 도구라 크게 다른점은 없을거라 판단되며

기타 도구들도 Node.js 와 npm이 있다면 충분히 가능할것으로 판단됩니다.


[1] terminal 에서 webpack을 global로 설치한다.


정상적으로 설치가 완료되면 위 화면과 같이 나옵니다. (현재 사진은 재설치한 상태)

설치가 되지 않는다면 Node.js설치가 제대로 되었는지 확인해 본다.


[2] terminal 에서 webpack-cli를 global로 설치한다.


의존성과 관련된 문제는 스스로 설치해서 해결해야 된다고 나와있지만

현재 프로젝트 자체가 깨끗하게 비어있기 때문에 문제되는 부분은 없습니다.


[3]webpack.config.js 파일을 생성



-> webpack을 통해 빌드할때 환경설정을 하는 스크립트라고 생각하면 된다.


module.exports = {

mode: 'development',

context: __dirname + '/app', // 모듈 파일 폴더
entry: { // 엔트리 파일 목록
app: './main.js'
},
output: {
path: __dirname + '/dist', // 번들 파일 폴더
filename: '[name].bundle.js' // 번들 파일 이름 규칙
}
}

환경설정과 관련되서 현재 프로젝트의 디렉토리에 관한 설명



현재 프로젝트는 app폴더, dist폴더로 나뉘어져 있다.


app폴더는 기존처럼 우리가 작성한 스크립트들이 들어있는 폴더이고

dist폴더는 webpack을 통해서 하나로 합쳐진 파일이 저장되는 폴더이다.


스크립트를 저장하는 폴더명 (모듈 파일 폴더 이름)을 바꾸고 싶다면 webpack.config.js에서

'/app' 부분을 변경하면 된다 (작성한 코드를 저장하는 폴더)


하나로 합쳐져서 나오는 폴더명 (번들 파일 폴더 이름)을 바꾸고 싶다면

'/dist' 부분을 변경하면 된다 (합쳐진 코드를 저장하는 폴더)



app 폴더 안에 진입점이 될 main.js 와 모듈이 될 Utils.js를 생성합니다.


main.js

"use strict";

import Utils from './Utils'
Utils.log(' Hello Webpack ');

console.log(" Yes !");

Utils.js

"use strict";

export default class Utils{
static log(msg){ console.log('[LOG]' + msg ); }
}


진입점 에서는 Utils 클래스의 static함수를 이용해서 로그를 찍을 예정입니다.

이제 터미널에 webpack 커맨드를 사용해서 빌드합니다.



빌드가 정상적으로 완료되면 이렇게 뜹니다.

dist폴더에 빌드된 파일 (app.bundle.js) 을 확인해보면


/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./main.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./Utils.js":
/*!******************!*\
!*** ./Utils.js ***!
\******************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return Utils; });\n\r\n\r\nclass Utils{\r\n static log(msg){ console.log('[LOG]' + msg ); }\r\n}\n\n//# sourceURL=webpack:///./Utils.js?");

/***/ }),

/***/ "./main.js":
/*!*****************!*\
!*** ./main.js ***!
\*****************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Utils */ \"./Utils.js\");\n\r\n\r\n\r\n_Utils__WEBPACK_IMPORTED_MODULE_0__[\"default\"].log(' Hello Webpack ');\r\n\r\nconsole.log(\" Yes !\");\n\n//# sourceURL=webpack:///./main.js?");

/***/ })

/******/ });

다음과 같이 합쳐진 코드를 확인할 수 있습니다.

추후에 config에서 development 로 되어있는 옵션을 Production 으로 변경한뒤

concat, babel, minify 옵션을 적용하면 코드를 한줄로 압축, 난독화해서 처리할 수 있습니다.


이제 index.html 파일을 다음과 같이 수정합니다.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="dist/app.bundle.js"></script>
</body>
</html>

빌드된 파일 1개만 로드하게 하면 됩니다.

그후 index.html 파일을 우클릭 한뒤 Run, 또는 Debug로 실행하면


다음과 같이 Utils.js의 함수를 이용해서 정상적으로 Log가 생성되는걸 확인할 수 있습니다.


1. webpack설정에서 진입점만 정의한뒤

2. 다른 파일에 있는 클래스를 호출할때는 import를 통해서 호출하면

3. Webpack이 빌드할때 의존성 관련된 부분을 알아서 처리한뒤

4. 한개의 파일로 합쳐준다.

5. index.html 에서는 합쳐준 파일 1개만 로드하면 된다.


이렇게 요약할수 있습니다.

Three js 에서 애니메이션 재생시 애니메이션 한개마다 FBX 파일을 로드, 처리하는건 불필요하다고 판단되어


3D Max에서 JD 파일로 모델을 애니메이션 정보와 함께 출력했다.


JD 파일을 이용해서 씬에 출력 및 애니메이션을 재생해보자.


JDLoader.min.js


JDLoader 파일을 먼저 index에 추가, 로드 시킨다. (검색해도 찾을수 있음)


jd파일을 json로드한뒤 parse 하면 다양한 정보들이 담겨서 나오는데 해당 데이터를 담아보자.



static jdModel( data )
{
let meshes = [];
let mixers = [];
let actions = [];

for( let i = 0; i < data.objects.length; ++i )
{
if( data.objects[i].type == "Mesh" || data.objects[i].type == "SkinnedMesh" )
{
let mesh = null;
let matArray = this.createMaterials( data );
if ( data.objects[i].type == "SkinnedMesh")
{
mesh = new THREE.SkinnedMesh( data.objects[i].geometry, matArray );
}
else
{
mesh = new THREE.Mesh( data.objects[i].geometry, matArray );
}
meshes.push( mesh );

if( mesh && mesh.geometry.animations )
{
for(let j = 0, length = mesh.geometry.animations.length; j < length; j++)
{
let mixer = new THREE.AnimationMixer( mesh );
mixers.push( mixer );
let action = mixer.clipAction( mesh.geometry.animations[j] );
action.play();
actions.push( action );
}
}
}
else if ( data.objects[i].type == "Line" )
{
let jd_color = data.objects[i].jd_object.color;
let color1 = new THREE.Color( jd_color[0] / 255, jd_color[1] / 255, jd_color[2] / 255 );
let material = new THREE.LineBasicMaterial({ color: color1 }); //{ color: new THREE.Color( 0xff0000 ) }
let line = new THREE.Line( data.objects[i].geometry, material );
// scene.add( line );

if( line.geometry.animations )
{
for( let j = 0, length = mesh.geometry.animations.length; j < length; j++ )
{
let mixer = new THREE.AnimationMixer( line );
mixers.push( mixer );
let action = mixer.clipAction( line.geometry.animations[j] );
action.play();
actions.push( actions );
}
}
}
}

let object = {};
object.meshes = meshes;
object.mixers = mixers;
object.actions = actions;
return object;
}

static createMaterials( data )
{
let matArray = [];
for( let i = 0; i < data.materials.length; ++i )
{
let mat = new THREE.MeshPhongMaterial({});
mat.copy( data.materials[i] );
matArray.push( mat );
}

return matArray;
}

Static 함수로 처리했다.


기존의 JDModel 로드 방법에 일부 스크립트가 추가되었는데

반환되는 object내부에

meshes , mixers, actions가 담겨서 나오게 된다.


이 함수를 통해 오브젝트를 받은뒤

meshes에 들어있는 모든 오브젝트를 Scene에 등록해준다.


this.object = new THREE.Group();

let model = StaticMethodCall.jdModel( data );

for(let i = 0, length = model.meshes.length; i < length; i++)
this.object.add( model.meshes[i] );

Group을 하나 만든뒤 씬에 등록하고 그 자식으로 넣어주는 방법이 편하다.


mixer는 애니메이션을 담당하므로 update함수에서 지속적으로 호출한다.

this.mixers[0].update( delta );

애니메이션을 재생, 정지 하고 싶을때는 Actions를 이용한다.

this.actions[1].stop();
this.actions[0].play();


Javascript 에서 모바일 브라우저인지 감지하는 코드


static isMobile(){
// if we want a more complete list use this: http://detectmobilebrowsers.com/
// str.test() is more efficent than str.match()
// remember str.test is case sensitive
let isMobile = (/iphone|ipod|android|ie|blackberry|fennec/).test
(navigator.userAgent.toLowerCase());
return isMobile;
}


'프로그래밍 > JavaScript' 카테고리의 다른 글

WebPack 빌드 및 사용하기  (2) 2018.08.21
Three.js 에서 jd 모델 사용하기.  (0) 2018.08.08
스파인 애니메이션 재생 문제 (Spine Animation)  (0) 2018.07.13
Threejs repeat  (0) 2018.07.04
Spine Attachment Off  (0) 2018.06.20

Spine으로 특정시점에 애니메이션을 재생시키거나 AddAnimation으로 애니메이션을 이어서 재생할때

애니메이션이 출력이 안되거나 재생 시점이 각기 다른 현상이 있었다.


Spine의 Visible을 False로 처리했을때 이러한 현상이 발생했었다.


처음에는 visible을 true로 놔둔 상태에서 스크린 밖의 좌표에 이동시켰으나


Render함수의 부하가 관찰됨.


this.sprite.autoUpdate = false;

먼저 spine의 autoUpdate를 false로 설정한다.


this.sprite.update( delta );


이후 Delta값을 이용해서 업데이트 한다. (Delta는 프레임간 시간을 넣어주면 됨 [dt], 일반적인 상황에서는 1 / 60 )


관찰시 visible을 false 상태에서 true로 전환되도 정상적으로 애니메이션이 재생되는걸 확인할 수 있음

'프로그래밍 > JavaScript' 카테고리의 다른 글

Three.js 에서 jd 모델 사용하기.  (0) 2018.08.08
자바스크립트 모바일 브라우저 감지하기  (0) 2018.07.17
Threejs repeat  (0) 2018.07.04
Spine Attachment Off  (0) 2018.06.20
p2 reflection angle (반사각) 설정  (0) 2018.04.13

Three js 에서 repeat는 텍스처 출력 크기를 의미


ex)  repeat.x 가 0.5일 경우 offset.x 의 위치부터 repeat.x의 크기만큼 텍스처를 자른다.

repeat.y 가 0.5일 경우 offset.y 의 위치부터 repeat.y의 크기만큼 텍스처를 자른다.


그다음 모델에 적용시킨다.


주의할점은 모든 모델들이 하나의 텍스처를 공유하기 때문에

texture의 uv를 변경하면 같은 texture를 사용하는 모든 object들의 uv가 변경된다.


Spine Attachment Off 하는법 (어태치먼트 비활성화)


목적 : 스파인 내부의 일부 장비를 비활성화, 다양항 장비를 교체하는 효과를 낼 수 있다.



this.sprite.skeleton.findSlot('helmet0').setAttachment( null );

이런 방식으로 슬롯을 찾은뒤 어태치먼트를 null 로 설정한다.


setSkinByName을 사용하면 attachment가 다시 설정된다.

벽돌깨기 게임을 만드는 도중 공이 벽에 부딪혔을때 입사각, 반사각이 의도한대로 나오지 않는 현상이 있었다.


friction, restitution수치로 인한 현상이었는데


friction을 0, restitution을 1로 설정하면 의도한 수치대로 나왔다.


Material을 만든다음 각각 Object마다 다른 수치로 적용할수 있지만 이번에는 World의 DefaultMaterial을 수정해서 처리했다.


this.world.defaultContactMaterial.friction = 0;
this.world.defaultContactMaterial.restitution = 1;

이미 만든 world의 수치를 위와같이 변경하면 된다.

'프로그래밍 > JavaScript' 카테고리의 다른 글

Threejs repeat  (0) 2018.07.04
Spine Attachment Off  (0) 2018.06.20
HTML5 휴대폰 터치 처리  (0) 2018.04.12
HTML5 PixiJS, P2 물리엔진 적용 및 충돌 콜백 (collision callback)  (0) 2018.04.11
PIXI.js, box2d 적용  (0) 2018.04.03

Keyword : HTML touch event, input


마우스 클릭, 이동 기준으로 게임 생성후 모바일에서 게임 실행히 마우스 이벤트가 동작하지 않았다.

터치 이벤트로 따로 연결시켜줘야 했었다.

ECMA6 클래스 기준


window.addEventListener("touchstart", this.touchDown.bind(this), false);
window.addEventListener("touchend", this.touchUp.bind(this), false);
window.addEventListener("touchmove", this.touchMove.bind(this), false);

window에서 터치와 관련됨 이벤트는 touchstart, touchend, touchmove가 있다. mousedown, mouseup, mousemove와 같은 개념

바인딩된 함수는 touchDown만 살펴보면

touchDown(event){
this.touches = event.changedTouches;

this.touches[0].pageX, this.touches[0].pageY;
}

event의 changedTouches를 받은뒤

index마다 pageX, pageY를 확인하면 된다. (0번은 맨첫번째 터치, 터치를 여러 손가락으로 동시에 할경우 배열에 더 많이 담긴다.)

'프로그래밍 > JavaScript' 카테고리의 다른 글

Threejs repeat  (0) 2018.07.04
Spine Attachment Off  (0) 2018.06.20
p2 reflection angle (반사각) 설정  (0) 2018.04.13
HTML5 PixiJS, P2 물리엔진 적용 및 충돌 콜백 (collision callback)  (0) 2018.04.11
PIXI.js, box2d 적용  (0) 2018.04.03

+ Recent posts