관리 메뉴

도드넷

JAVASCRIPT#77 - 탑다운 1부 본문

창고/JS KING 포니 [중단]

JAVASCRIPT#77 - 탑다운 1부

도드! 2016. 8. 2. 10:24
반응형



Big things have small beginnings...


JAVASCRIPT#77 - 탑다운 1부


1. 게임의 시작


$("#startButton").click(function() {
        gf.startGame(initialize);
    });


스타트 버튼이라는 요소를 클릭하면 gf.startGame 함수가 initialize라는 파라미터와 함께 시작된다.



2. gf.startGame 과 initialize 함수


gf.startGame = function(endCallback, progressCallback) {
    // 1. 이미지 배열과 프리로드
    var images = [];
    var total = gf.imagesToPreload.length;
    for (var i = 0; i < total; i++) {
        var image = new Image();
        images.push(image);
        image.src = gf.imagesToPreload[i];
    }
    var preloadingPoller = setInterval(function() {
        var counter = 0;
        var total = gf.imagesToPreload.length;
        for (var i = 0; i < total; i++) {
            if (images[i].complete) {
                counter++;
            }
        }
        if (counter == total) {
            // 2. 프리로드가 완료됬을시, 콜백(initialize)과 주 반복문(refreshGame) 실행 시작.
            clearInterval(preloadingPoller);
            endCallback();
            setInterval(gf.refreshGame, gf.baseRate);
            gf.time = (new Date()).getTime();
        } else {
            if (progressCallback) {
                count++;
                progressCallback((count / total) * 100);
            }
        }
    }, 100);
};



var initialize = function()
    {

        // 1. 컨테이너 만들기
        $("#mygame").append("<div id='container' style='display: none; width: 800px; height: 600px;'>");
        container       = $("#container");
        
        // 2. 컨테이너에 콘솔 추가
        container.append("<div id='console' style='font-family: \"Press Start 2P\", cursive; color: #fff; width: 770px; height: 20px; padding: 15px; position: absolute; bottom: 0; background: rgba(0,0,0,0.5); z-index: 3000'>");
        console = $("#console");
        
        // 3. "world"(group) 그룹 객체 정의
        world           = gf.addGroup(container,"group",{
                            x: -(510-192)/2,
                            y: -(360-192)/2
                        });
        
        // 4. "tiles"(tiles) 그룹 만들기
        tiles           = gf.addGroup(world,"tiles");
            
        // 5. json 기반 타일 불러오기
        gf.importTiled("level.json",tiles, "tiles");


        // 6. 제 3 타일 z 좌표 설정 (맨위에서 플레이어를 덮는 타일이 됨)
             $("#tiles3").css("z-index", "2989");
        
        // 7. "npcsGroup"(npcs) 그룹 만들기
        npcsGroup       = gf.addGroup(world,"npcs");

        // 8. npcs배열에 NPC1 DOM 객체 div와 NPC함수에 의해 생성된 object 값 전달
        npcs.push({
            div: gf.addSprite(npcsGroup,"NPC1", {
                x:      800,
                y:      800,
                width:  96,
                height: 96
            }),
            object: new NPC("Dr. Where", ["안녕","I hope you will enjoy it.","You should head east from here...","there's someone you may want to meet."], console)
        });

        // 9. object의 div값을 생성하면서 지정함.
        npcs[npcs.length-1].object.div = npcs[npcs.length-1].div;

        // 10. 해당 npc의 애니메이션 설정
        gf.setAnimation(npcs[npcs.length-1].div, new gf.animation({
            url: "npc/scientist.png"
        }));

        // 11. 해당 npc DOM의 z 좌표 설정
        $("#NPC1").css("z-index", 800 + 96);

        // 12. npcs배열에 NPC2 DOM 객체 div와 NPC 함수에 의해 생성된 object 값 전달
        npcs.push({
            div: gf.addSprite(npcsGroup,"NPC2", {
                x:      1800,
                y:      600,
                width:  96,
                height: 96
            }),
            object: new NPC("Junior",["Howdy lad! If you explore this country"," be carefull! There are monsters", "roaming around!"], console)
        });

        // 13. 해당 npcs의 오브젝트.div 설정
        npcs[npcs.length-1].object.div = npcs[npcs.length-1].div;


        // 14. 해당 npc의 애니메이션 설정
        gf.setAnimation(npcs[npcs.length-1].div, new gf.animation({
            url: "npc/desertnpc.png"
        }));

        // 15. 해당 npc DOM의 z 좌표 설정
        $("#NPC2").css("z-index",600 + 96);
        
        // 16. "enemiesGroup"(enemies) 그룹 정의
        enemiesGroup    = gf.addGroup(world,"enemies");

        // 17. enemies 배열에 enemy1 DOM 객체 div와 Enemy 함수에 의해 생성된 object 값 전달
        enemies.push({
            div: gf.addSprite(\
              enemiesGroup,"enemy1", {
                    x:      100,
                    y:      1300,
                    width:  192,
                    height: 192
                }),
            object: new Enemy(10,15)
        });

        // 18. 해당 enemy의 애니메이션 설정
        gf.setAnimation(enemies[enemies.length-1].div, skeletonAnim.stand.down, true);

        // 19. 해당 enemy의 z 좌표 설정
        $("#enemy1").css("z-index",1300 + 192-16);
        
        // 20. enemies 배열에 enemy2 DOM 객체 div와 Enemy 함수에 의해 생성된 object 값 전달
        enemies.push({
            div: gf.addSprite(enemiesGroup,"enemy2", {
                    x:      1800,
                    y:      1200,
                    width:  192,
                    height: 192
                }),
           object: new Enemy(2,50)
        });

        // 21. 해당 enemy의 애니메이션 설정
        gf.setAnimation(enemies[enemies.length-1].div, ogreAnim.stand.down, true);

        // 22. 해당 enemy의 z 좌표 설정
        $("#enemy2").css("z-index",1200 + 192 - 16);
        
        // 23. player.div(player) 그룹 객체 생성
        player.div      = gf.addGroup(world,"player", {
                            x: 510,
                            y: 360
                        });

        // 24. 플레이어 아바타 생성
        player.avatar   = gf.addSprite(player.div, "avatar", {
                            x:      (192-128)/2,
                            y:      (192-128)/2,
                            width:  128,
                            height: 128
                        });

        // 25. 플레이어 웨폰 생성
        player.weapon   = gf.addSprite(player.div, "weapon", {
                            width:  192,
                            height: 192
                        });

        // 26. 플레이어 히트존 생성
        player.hitzone  = gf.addSprite(player.div, "hitzone", {
                            x:      16,
                            y:      192-80,
                            width:  128 + 32,
                            height: 64
                        });

        // 27. 플레이어 콜존(히트존2) 생성
        player.colzone  = gf.addSprite(player.div, "hitzone", {
                            x:      72,
                            y:      76,
                            width:  48,
                            height: 64
                        });
        
        // 28. 플레이어 아이들 함수 실행
        player.idle();
       
        // 29. 플레이어 상태 walk로 설정
        gameState = "walk";
        
        // 30. 플레이어 버튼 요소 삭제
        $("#startButton").remove();

        // 31. 콘테이너 디스플레이 설정
        container.css("display", "block");
    }


ㄴinitialize 에서 사용된 함수들


1. gf.addGroup


// 1. 그룹 프래그맨트 정의
gf.groupFragment = $("<div class='gf_group' style='position: absolute; overflow: visible;'></div>");

// 2. 그룹 생성 함수 
gf.addGroup = function(parent, divId, options)
{
    // 2-1. 옵션 합치기
    var options = $.extend({
        x: 0,
        y: 0,
        flipH: false,
        flipV: false,
        rotate: 0,
        scale: 1
    }, options);

    // 2-2. 그룹 DOM 객체 생성.
    var group = gf.groupFragment.clone().css({
            left:   options.x,
            top:    options.y}).attr("id",divId).data("gf",options);

    // 2-3. 해당 그룹 DOM 화면에 더하기
    parent.append(group);

    return group;
}


2. gf.ImportTiled


PASS.. 2부에서 다뤄봄!


gf.importTiled = function(url, parent, divIdPrefix){
    var animations = [];
    var tilemaps = [];
   
    $.ajax({
        url: url,
        async: false,
        dataType: 'json',
        success: function(json){
            var height = json.height;
            var width  = json.width;
            var tileHeight = json.tileheight;
            var tileWidth  = json.tilewidth;
           
            var layers = json.layers;
            var usedTiles = [];
            var animationCounter = 0;
            var tilemapArrays = [];
           
            // detection which animations we need to generate
            // and converting the tiles array indexes to the new ones
            for (var i=0; i < layers.length; i++){
                if(layers[i].type === "tilelayer"){
                    var tilemapArray = new Array(height);
                    for (var j=0; j<height; j++){
                        tilemapArray[j] = new Array(width);
                    }
                    for (var j=0; j < layers[i].data.length; j++){
                        var tile = layers[i].data[j];
                        if(tile === 0){
                            tilemapArray[Math.floor(j / width)][j % width] = 0;
                        } else {
                            if(!usedTiles[tile]){
                                animationCounter++;
                                usedTiles[tile] = animationCounter;
                                animations.push(new gf.animation({
                                    url: json.tilesets[0].image,
                                    offsetx: ((tile-1) % Math.floor(json.tilesets[0].imagewidth / tileWidth)) * tileWidth,
                                    offsety: Math.floor((tile-1) / Math.floor(json.tilesets[0].imagewidth / tileWidth)) * tileHeight
                                }));
                            }
                            tilemapArray[Math.floor(j / width)][j % width] = usedTiles[tile];
                        }
                    }
                    tilemapArrays.push(tilemapArray);
                }
            }
            // adding the tilemaps
            for (var i=0; i<tilemapArrays.length; i++){
                tilemaps.push(gf.addTilemap(parent, divIdPrefix+i, {
                    x:          0,
                    y:          0,
                    tileWidth:  tileWidth,
                    tileHeight: tileHeight,
                    width:      width,
                    height:     height,
                    map:        tilemapArrays[i],
                    animations: animations
                }));
            }
        }
    });
   
    return {
        animations: animations,
        tilemaps: tilemaps
    }
}


3. gf.addSprite


// 1. 스프라이트 프래그맨트 정의.
gf.spriteFragment = $("<div class='gf_sprite' style='position: absolute; overflow: hidden;'></div>");

// 2. 스프라이트 생성 함수.
gf.addSprite = function(parent, divId, options)
{
    // 2-1. 옵션 합치기.
    var options = $.extend({
        x: 0,
        y: 0,
        width: 64,
        height: 64,
        flipH: false,
        flipV: false,
        rotate: 0,
        scale: 1
    }, options);

    // 2-2. 스프라이트 DOM 객체 생성.
    var sprite = gf.spriteFragment.clone().css({
            left:   options.x,
            top:    options.y,
            width:  options.width,
            height: options.height}).attr("id",divId).data("gf",options);

    // 2-3. 해당 스프라이트 화면에 더하기.
    parent.append(sprite);

    // 2-4. 해당 스프라이트 반환.
    return sprite;
}


4. gf.setAnimation


// 0. div 프레임 설정 함수
gf.setFrame = function(div, animation) {
    div.css("backgroundPosition", "" + (-animation.currentFrame * animation.width - animation.offsetx) + "px "+(-animation.offsety)+"px");
}

// 1. 애니메이션 배열 선언
gf.animations = [];

// 2. 애니메이션 설정 함수
gf.setAnimation = function(div, animation, loop, callback){
   
    // 2-1. 입력받은 파라미터 바탕으로 animate 객체 생성.
    var animate = {
        animation: $.extend({}, animation),
        div: div,
        loop: loop,
        callback: callback,
        counter: 0
    }
   
    // 2-2 . 해당 div url 프로퍼티 설정. 
    if(animation.url){
        div.css("backgroundImage","url('"+animation.url+"')");
    }
   
    // 2-3. 해당div의 존재여부 기본값으로 거짓 설정
    var divFound = false;
   
    // 2-4. 애니메이션 배열 검사해서 해당 div가 존재하는지 검사
    for (var i = 0; i < gf.animations.length; i++) {
       
        // 2-4-1. 만약 존재할경우 애니메이션 변경
        if(gf.animations[i].div.is(div)){
            divFound = true;
            gf.animations[i] = animate;
        }
    }
   
    // 2-5. 존재하지 않을경우 애니메이션 추가
    if(!divFound) {
        gf.animations.push(animate);
    }

    // 2-6. 해당 div프레임을 애니메이션으로 설정
    gf.setFrame(div, animation);
}


5. NPC 생성 함수


    // 1. NPC 생성함수 [파라미터 : 이름 텍스트 콘솔]
    var NPC = function(name, text, console)
    {
        // 1-1. 현재 텍스트의 인덱스를 정의 하는변수 current 설정.      
        var current = 0;
        
        // 1-2. getText 함수 정의
        this.getText = function()
        {
            // 1-2-1. text 배열의 길이가 카운터와 같을경우 끝냄
            if(current === text.length){
                current = 0;
                return "[end]";
            }

            // 1-2-2. 이름과 현재 텍스트 반환, current 값 증가
            return name + ": " + text[current++];
        };
        
        // 1-3.dialog 함수 정의
        this.dialog = function(){
            // 1-3-1. console 이라는 DOM객체의 내용을 getText로 가져온 내용으로 설정.
            console.html(this.getText());
        }
    }


6. Enemy 생성 함수


    // 1. Enemy 생성함수 [파라미터 : 디펜드 모디파이어, 라이프]
    var Enemy = function(defendModifier, life) {
               
        // 1-1. defend 함수 정의        
        this.defend = function(){

            // 1-1-1. 랜덤 소수를 반환해서 6을 곱한뒤 반올림한뒤 디펜드 모디파이어와 더해서 반환 
            return Math.round(Math.random() * 6) + defendModifier;
        }
       
        // 1-2. kill 함수 정의
        this.kill = function(value){

            //1-2-1. 라이프에서 밸류값을 뺌 (데미지를 입힘)
            life -= value;

            //1-2-2. 만약 라이프값이 0이랑 같거나 낮아질경우 상태를 dead로 만들고 참을 반환
            if (life <= 0){
                state = "dead";
                return true;
            }

            // 평소에는 거짓을 반환
            return false;
        }
    }


미스테리1.

npcs[npcs.length-1].object.div = npcs[npcs.length-1].div;


var A_GROUP = [];
var WTF = function()
{
  console.log("nigga whaaaat?");
}

A_GROUP.push({A: $("#mygame"), B: new WTF});

A_GROUP[A_GROUP.length - 1].B.nigggggaaaaa = 23;

console.log(A_GROUP[0].B.nigggggaaaaa);


결과::

결론::

1) push 할때 불러도 함수 호출이 발생하는 구나.

2) push된 객체의 B값에 저장된 WTF 객체에 사실 niggggggggga 라는 변수가 없으나 위와같이 지정할경우

자동으로 생성되면서 값할당까지 함.







반응형
Comments